Last active
March 8, 2021 06:23
-
-
Save deian/6ce46eb8c3e079034d8698cf3ca99a51 to your computer and use it in GitHub Desktop.
Retrofit libtiff use in pdfium to use RLBox
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 223d7f640173062ac0b11beb85f7edf11ed5873a Mon Sep 17 00:00:00 2001 | |
From: RLBox Team <[email protected]> | |
Date: Fri, 5 Mar 2021 00:37:26 -0800 | |
Subject: [PATCH] Retrofit libtiff to use RLBox | |
This is not a complete port, but is most of the way there. We still need | |
to: | |
- Implement a few more verifiers. | |
- Move small bits of code into the sandbox. | |
- Avoid copying twice in some places. | |
- Tests; the pdfium unit tests don't seem to exercise this code. | |
--- | |
BUILD.gn | 3 +- | |
core/fxcodec/tiff/rlbox_tiff_types.h | 22 ++ | |
core/fxcodec/tiff/tiff_decoder.cpp | 411 ++++++++++++++++++++------- | |
3 files changed, 327 insertions(+), 109 deletions(-) | |
create mode 100644 core/fxcodec/tiff/rlbox_tiff_types.h | |
diff --git a/BUILD.gn b/BUILD.gn | |
index b69dda68d..2b882b8e8 100644 | |
--- a/BUILD.gn | |
+++ b/BUILD.gn | |
@@ -46,7 +46,8 @@ config("pdfium_common_config") { | |
if (is_clang) { | |
# Override -Wno-c++11-narrowing. | |
- cflags += [ "-Wc++11-narrowing" ] | |
+ cflags += [ "-Wc++11-narrowing", "-Wc++17-extensions", "-Wno-error"] | |
+ cflags_cc = [ "-std=c++17", "-Wextra-semi", "-Wshadow"] | |
} | |
if (!is_win && !is_clang) { | |
diff --git a/core/fxcodec/tiff/rlbox_tiff_types.h b/core/fxcodec/tiff/rlbox_tiff_types.h | |
new file mode 100644 | |
index 000000000..432ec3747 | |
--- /dev/null | |
+++ b/core/fxcodec/tiff/rlbox_tiff_types.h | |
@@ -0,0 +1,22 @@ | |
+#ifndef RLBOX_TIFF_TYPES_H_ | |
+#define RLBOX_TIFF_TYPES_H_ | |
+ | |
+#include <stddef.h> | |
+#include "core/fxcodec/rlbox/rlbox_types.hpp" | |
+ | |
+using rlbox_tiff_sandbox_type = rlbox::rlbox_noop_sandbox; | |
+ | |
+using rlbox_sandbox_tiff = rlbox::rlbox_sandbox<rlbox_tiff_sandbox_type>; | |
+template <typename T> | |
+using sandbox_callback_tiff = | |
+ rlbox::sandbox_callback<T, rlbox_tiff_sandbox_type>; | |
+template <typename T> | |
+using tainted_tiff = rlbox::tainted<T, rlbox_tiff_sandbox_type>; | |
+template <typename T> | |
+using tainted_opaque_tiff = rlbox::tainted_opaque<T, rlbox_tiff_sandbox_type>; | |
+template <typename T> | |
+using tainted_volatile_tiff = | |
+ rlbox::tainted_volatile<T, rlbox_tiff_sandbox_type>; | |
+using rlbox::tainted_boolean_hint; | |
+ | |
+#endif | |
diff --git a/core/fxcodec/tiff/tiff_decoder.cpp b/core/fxcodec/tiff/tiff_decoder.cpp | |
index 4f5729950..f85b98380 100644 | |
--- a/core/fxcodec/tiff/tiff_decoder.cpp | |
+++ b/core/fxcodec/tiff/tiff_decoder.cpp | |
@@ -21,23 +21,63 @@ | |
#include "third_party/base/check.h" | |
#include "third_party/base/notreached.h" | |
+#define RLBOX_SINGLE_THREADED_INVOCATIONS | |
+#define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol | |
+#include "core/fxcodec/rlbox/rlbox.hpp" | |
+#include "core/fxcodec/rlbox/rlbox_noop_sandbox.hpp" | |
+#include "core/fxcodec/tiff/rlbox_tiff_types.h" | |
+ | |
extern "C" { | |
#include "third_party/libtiff/tiffiop.h" | |
} // extern C | |
+ | |
+// RLBOX ------------------------------------------- | |
namespace { | |
-// For use with std::unique_ptr<TIFF>. | |
-struct TiffDeleter { | |
- inline void operator()(TIFF* context) { TIFFClose(context); } | |
-}; | |
+// We don't have great support for varargs, will need to add this to libtiff | |
+template <typename T> | |
+static int TIFFGetField(TIFF* tif, uint32_t tag, T* res) { | |
+ return TIFFGetField(tif, tag, res); | |
+} | |
+template <typename T> | |
+static int TIFFSetField(TIFF* tif, uint32_t tag, T val) { | |
+ return TIFFSetField(tif, tag, val); | |
+} | |
+template <typename T> | |
+static int TIFFGetFieldDefaulted(TIFF* tif, uint32_t tag, T* res) { | |
+ return TIFFGetFieldDefaulted(tif, tag, res); | |
+} | |
+static int TTIFFGetFieldColorMap(TIFF* tif, uint32_t tag, uint16_t** r, uint16_t** g, uint16_t** b) { | |
+ return TIFFGetField(tif, tag, r, g, b); | |
+} | |
+ | |
+// --- | |
+ | |
+ | |
+// Helpers for calling sandboxed tiff functions in handlers | |
+ | |
+#define RLBOX_TIFF_SAFE_CALL(foo, verifier, ...) \ | |
+ m_tif_sbx->invoke_sandbox_function(foo, m_tif_ctx_t, ##__VA_ARGS__) \ | |
+ .copy_and_verify(verifier) | |
+ | |
+#define RLBOX_TIFF_CALL(foo, ...) \ | |
+ m_tif_sbx->invoke_sandbox_function(foo, m_tif_ctx_t, ##__VA_ARGS__) | |
+ | |
+template <typename T> | |
+static T no_verifier(T val) { | |
+ return val; | |
+} | |
+ | |
+} // namespace | |
+// RLBOX ------------------------------------------- | |
+ | |
-} // namespace | |
class CTiffContext final : public ProgressiveDecoderIface::Context { | |
public: | |
CTiffContext() = default; | |
- ~CTiffContext() override = default; | |
+ ~CTiffContext(); | |
bool InitDecoder(const RetainPtr<IFX_SeekableReadStream>& file_ptr); | |
bool LoadFrameInfo(int32_t frame, | |
@@ -73,9 +113,37 @@ class CTiffContext final : public ProgressiveDecoderIface::Context { | |
RetainPtr<IFX_SeekableReadStream> m_io_in; | |
uint32_t m_offset = 0; | |
- std::unique_ptr<TIFF, TiffDeleter> m_tif_ctx; | |
+ // TIFF sandbox, context, and sandbox callbacks | |
+ rlbox_sandbox_tiff* m_tif_sbx; | |
+ mutable tainted_tiff<TIFF*> m_tif_ctx_t; | |
+ sandbox_callback_tiff<tsize_t (*) (thandle_t, tdata_t, tsize_t)> m_tiff_read; | |
+ sandbox_callback_tiff<tsize_t (*)(thandle_t, tdata_t, tsize_t)> m_tiff_write; | |
+ sandbox_callback_tiff<toff_t (*)(thandle_t, toff_t, int)> m_tiff_seek; | |
+ sandbox_callback_tiff<int (*)(thandle_t)> m_tiff_close; | |
+ sandbox_callback_tiff<toff_t (*)(thandle_t)> m_tiff_get_size; | |
+ sandbox_callback_tiff<int (*)(thandle_t, tdata_t*, toff_t*)> m_tiff_map; | |
+ sandbox_callback_tiff<void (*)(thandle_t, tdata_t, toff_t)> m_tiff_unmap; | |
}; | |
+CTiffContext::~CTiffContext() { | |
+ RLBOX_TIFF_CALL(TIFFClose); | |
+ | |
+ // unregister callbacks | |
+ m_tiff_read.unregister(); | |
+ m_tiff_write.unregister(); | |
+ m_tiff_seek.unregister(); | |
+ m_tiff_close.unregister(); | |
+ m_tiff_get_size.unregister(); | |
+ m_tiff_map.unregister(); | |
+ m_tiff_unmap.unregister(); | |
+ | |
+ // free context | |
+ m_tif_sbx->free_in_sandbox(m_tif_ctx_t); | |
+ // destroy sandbox | |
+ m_tif_sbx->destroy_sandbox(); | |
+} | |
+ | |
+// TODO: these should be moved into the sandbox to use standard libc | |
void* _TIFFcalloc(tmsize_t nmemb, tmsize_t siz) { | |
return FXMEM_DefaultCalloc(nmemb, siz); | |
} | |
@@ -107,19 +175,33 @@ int _TIFFmemcmp(const void* ptr1, const void* ptr2, tmsize_t size) { | |
TIFFErrorHandler _TIFFwarningHandler = nullptr; | |
TIFFErrorHandler _TIFFerrorHandler = nullptr; | |
+// -- | |
namespace { | |
-tsize_t tiff_read(thandle_t context, tdata_t buf, tsize_t length) { | |
- CTiffContext* pTiffContext = reinterpret_cast<CTiffContext*>(context); | |
+tainted_tiff<tsize_t> tiff_read(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>, tainted_tiff<tdata_t> t_buf, tainted_tiff<tsize_t> t_length) { | |
+ size_t length = t_length.copy_and_verify(no_verifier<tsize_t>); // sanity checked below | |
+ CTiffContext* pTiffContext = reinterpret_cast<CTiffContext*>(sbx.sandbox_storage); | |
FX_SAFE_UINT32 increment = pTiffContext->offset(); | |
increment += length; | |
if (!increment.IsValid()) | |
return 0; | |
FX_FILESIZE offset = pTiffContext->offset(); | |
- if (!pTiffContext->io_in()->ReadBlockAtOffset(buf, offset, length)) | |
+ // allocate temporary buffer | |
+ tdata_t buf = malloc(length); | |
+ if (!buf) | |
+ return 0; | |
+ // we copy from buf, so zero-initialize it | |
+ bzero(buf, length); | |
+ if (!pTiffContext->io_in()->ReadBlockAtOffset(buf, offset, length)) { | |
+ free(buf); | |
return 0; | |
+ } | |
+ // copy buffer into sandbox | |
+ rlbox::memcpy(sbx, t_buf, buf, length); | |
+ // free the temp buffer | |
+ free(buf); | |
pTiffContext->set_offset(increment.ValueOrDie()); | |
if (offset + length > pTiffContext->io_in()->GetSize()) | |
@@ -128,18 +210,19 @@ tsize_t tiff_read(thandle_t context, tdata_t buf, tsize_t length) { | |
return length; | |
} | |
-tsize_t tiff_write(thandle_t context, tdata_t buf, tsize_t length) { | |
+tainted_tiff<tsize_t> tiff_write(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>, tainted_tiff<tdata_t>, tainted_tiff<tsize_t>) { | |
NOTREACHED(); | |
return 0; | |
} | |
-toff_t tiff_seek(thandle_t context, toff_t offset, int whence) { | |
- CTiffContext* pTiffContext = reinterpret_cast<CTiffContext*>(context); | |
- FX_SAFE_FILESIZE safe_offset = offset; | |
+tainted_tiff<toff_t> tiff_seek(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>, tainted_tiff<toff_t> t_offset, tainted_tiff<int> t_whence) { | |
+ CTiffContext* pTiffContext = reinterpret_cast<CTiffContext*>(sbx.sandbox_storage); | |
+ FX_SAFE_FILESIZE safe_offset = t_offset.copy_and_verify(no_verifier<toff_t>); // check on assignment | |
if (!safe_offset.IsValid()) | |
return static_cast<toff_t>(-1); | |
FX_FILESIZE file_offset = safe_offset.ValueOrDie(); | |
+ int whence = t_whence.copy_and_verify(no_verifier<int>); // checked next: | |
switch (whence) { | |
case 0: { | |
if (file_offset > pTiffContext->io_in()->GetSize()) | |
@@ -166,55 +249,47 @@ toff_t tiff_seek(thandle_t context, toff_t offset, int whence) { | |
} | |
} | |
-int tiff_close(thandle_t context) { | |
+tainted_tiff<int> tiff_close(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>) { | |
return 0; | |
} | |
-toff_t tiff_get_size(thandle_t context) { | |
- CTiffContext* pTiffContext = reinterpret_cast<CTiffContext*>(context); | |
+tainted_tiff<toff_t> tiff_get_size(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>) { | |
+ CTiffContext* pTiffContext = reinterpret_cast<CTiffContext*>(sbx.sandbox_storage); | |
return static_cast<toff_t>(pTiffContext->io_in()->GetSize()); | |
} | |
-int tiff_map(thandle_t context, tdata_t*, toff_t*) { | |
+tainted_tiff<int> | |
+tiff_map(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>, tainted_tiff<tdata_t*>, tainted_tiff<toff_t*>) { | |
return 0; | |
} | |
-void tiff_unmap(thandle_t context, tdata_t, toff_t) {} | |
- | |
-TIFF* tiff_open(void* context, const char* mode) { | |
- TIFF* tif = TIFFClientOpen("Tiff Image", mode, (thandle_t)context, tiff_read, | |
- tiff_write, tiff_seek, tiff_close, tiff_get_size, | |
- tiff_map, tiff_unmap); | |
- if (tif) { | |
- tif->tif_fd = (int)(intptr_t)context; | |
- } | |
- return tif; | |
-} | |
+void tiff_unmap(rlbox_sandbox_tiff& sbx, tainted_tiff<thandle_t>, tainted_tiff<tdata_t>, tainted_tiff<toff_t>) {} | |
-template <class T> | |
-bool Tiff_Exif_GetInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttribute* pAttr) { | |
- T val = 0; | |
- TIFFGetField(tif_ctx, tag, &val); | |
+template <class T, typename TFunc> | |
+bool RLBox_Tiff_Exif_GetInfo(rlbox_sandbox_tiff* m_tif_sbx, tainted_tiff<TIFF*> m_tif_ctx_t, ttag_t tag, CFX_DIBAttribute* pAttr, TFunc verifier) { | |
+ tainted_tiff<T*> val = m_tif_sbx->malloc_in_sandbox<T>(); | |
+ RLBOX_TIFF_CALL(TIFFGetField<T>, tag, val); | |
if (!val) | |
return false; | |
T* ptr = FX_Alloc(T, 1); | |
- *ptr = val; | |
+ *ptr = (*val).copy_and_verify(verifier); | |
pAttr->m_Exif[tag] = ptr; | |
+ m_tif_sbx->free_in_sandbox(val); | |
return true; | |
} | |
-void Tiff_Exif_GetStringInfo(TIFF* tif_ctx, | |
+void RLBox_Tiff_Exif_GetStringInfo(rlbox_sandbox_tiff* m_tif_sbx, tainted_tiff<TIFF*> m_tif_ctx_t, | |
ttag_t tag, | |
CFX_DIBAttribute* pAttr) { | |
- char* buf = nullptr; | |
- TIFFGetField(tif_ctx, tag, &buf); | |
- if (!buf) | |
+ tainted_tiff<char**> t_ptr_buf = m_tif_sbx->malloc_in_sandbox<char*>(); | |
+ RLBOX_TIFF_CALL(TIFFGetField<char*>, tag, t_ptr_buf); | |
+ tainted_tiff<char*> t_buf = *t_ptr_buf; | |
+ if (!t_buf) | |
return; | |
- size_t size = strlen(buf); | |
- uint8_t* ptr = FX_AllocUninit(uint8_t, size + 1); | |
- memcpy(ptr, buf, size); | |
- ptr[size] = 0; | |
- pAttr->m_Exif[tag] = ptr; | |
+ t_buf.copy_and_verify_string([&](std::unique_ptr<char[]> str) { | |
+ pAttr->m_Exif[tag] = str.release(); | |
+ }); | |
+ m_tif_sbx->free_in_sandbox(t_ptr_buf); | |
} | |
void TiffBGRA2RGBA(uint8_t* pBuf, int32_t pixel, int32_t spp) { | |
@@ -228,11 +303,46 @@ void TiffBGRA2RGBA(uint8_t* pBuf, int32_t pixel, int32_t spp) { | |
} // namespace | |
+ | |
+static inline tainted_tiff<char*> sandbox_str(rlbox_sandbox_tiff* m_tif_sbx, char* str, bool& copied) { | |
+ size_t size = strlen(str) + 1; | |
+ return rlbox::copy_memory_or_grant_access(*m_tif_sbx, str, size, false, copied); | |
+} | |
+ | |
bool CTiffContext::InitDecoder( | |
const RetainPtr<IFX_SeekableReadStream>& file_ptr) { | |
m_io_in = file_ptr; | |
- m_tif_ctx.reset(tiff_open(this, "r")); | |
- return !!m_tif_ctx; | |
+ | |
+ // create sandbox | |
+ m_tif_sbx = new rlbox_sandbox_tiff(); | |
+ m_tif_sbx->create_sandbox(); | |
+ | |
+ // save context to sandbox storage | |
+ m_tif_sbx->sandbox_storage = this; | |
+ | |
+ // create tiff client | |
+ bool copied_filename = false; | |
+ auto t_filename = sandbox_str(m_tif_sbx, "TiffImage", copied_filename); | |
+ bool copied_mode = false; | |
+ auto t_mode = sandbox_str(m_tif_sbx, "r", copied_mode); | |
+ | |
+ m_tiff_read = m_tif_sbx->register_callback(tiff_read); | |
+ m_tiff_write = m_tif_sbx->register_callback(tiff_write); | |
+ m_tiff_seek = m_tif_sbx->register_callback(tiff_seek); | |
+ m_tiff_close = m_tif_sbx->register_callback(tiff_close); | |
+ m_tiff_get_size = m_tif_sbx->register_callback(tiff_get_size); | |
+ m_tiff_map = m_tif_sbx->register_callback(tiff_map); | |
+ m_tiff_unmap = m_tif_sbx->register_callback(tiff_unmap); | |
+ | |
+ m_tif_ctx_t = m_tif_sbx->invoke_sandbox_function(TIFFClientOpen, t_filename, t_mode, nullptr, | |
+ m_tiff_read, m_tiff_write, m_tiff_seek, m_tiff_close, m_tiff_get_size, m_tiff_map, m_tiff_unmap); | |
+ if (copied_filename) | |
+ m_tif_sbx->free_in_sandbox(t_filename); | |
+ if (copied_mode) | |
+ m_tif_sbx->free_in_sandbox(t_mode); | |
+ if (!m_tif_ctx_t) | |
+ return false; | |
+ return true; | |
} | |
bool CTiffContext::LoadFrameInfo(int32_t frame, | |
@@ -241,7 +351,7 @@ bool CTiffContext::LoadFrameInfo(int32_t frame, | |
int32_t* comps, | |
int32_t* bpc, | |
CFX_DIBAttribute* pAttribute) { | |
- if (!TIFFSetDirectory(m_tif_ctx.get(), (uint16)frame)) | |
+ if (!RLBOX_TIFF_SAFE_CALL(TIFFSetDirectory, no_verifier<int>, (uint16)frame)) | |
return false; | |
uint32_t tif_width = 0; | |
@@ -249,34 +359,61 @@ bool CTiffContext::LoadFrameInfo(int32_t frame, | |
uint16_t tif_comps = 0; | |
uint16_t tif_bpc = 0; | |
uint32_t tif_rps = 0; | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_IMAGEWIDTH, &tif_width); | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_IMAGELENGTH, &tif_height); | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_SAMPLESPERPIXEL, &tif_comps); | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_BITSPERSAMPLE, &tif_bpc); | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_ROWSPERSTRIP, &tif_rps); | |
+ { | |
+ tainted_tiff<uint32_t*> t_tif_width = m_tif_sbx->malloc_in_sandbox<uint32_t>(); | |
+ tainted_tiff<uint32_t*> t_tif_height = m_tif_sbx->malloc_in_sandbox<uint32_t>(); | |
+ tainted_tiff<uint16_t*> t_tif_comps = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ tainted_tiff<uint16_t*> t_tif_bpc = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ tainted_tiff<uint32_t*> t_tif_rps = m_tif_sbx->malloc_in_sandbox<uint32_t>(); | |
+ | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint32_t>, TIFFTAG_IMAGEWIDTH, t_tif_width); | |
+ tif_width = (*t_tif_width).copy_and_verify(no_verifier<uint32_t>); // checked later | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint32_t>, TIFFTAG_IMAGELENGTH, t_tif_height); | |
+ tif_height = (*t_tif_height).copy_and_verify(no_verifier<uint32_t>); // checked later | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint16_t>, TIFFTAG_SAMPLESPERPIXEL, t_tif_comps); | |
+ tif_comps = (*t_tif_comps).copy_and_verify(no_verifier<uint16_t>); // should check | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint16_t>, TIFFTAG_BITSPERSAMPLE, t_tif_bpc); | |
+ tif_bpc = (*t_tif_bpc).copy_and_verify(no_verifier<uint16_t>); // should check | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint32_t>, TIFFTAG_ROWSPERSTRIP, t_tif_rps); | |
+ tif_rps = (*t_tif_rps).copy_and_verify(no_verifier<uint32_t>); // checked later | |
+ | |
+ m_tif_sbx->free_in_sandbox(t_tif_width); | |
+ m_tif_sbx->free_in_sandbox(t_tif_height); | |
+ m_tif_sbx->free_in_sandbox(t_tif_comps); | |
+ m_tif_sbx->free_in_sandbox(t_tif_bpc); | |
+ m_tif_sbx->free_in_sandbox(t_tif_rps); | |
+ } | |
+ | |
+ | |
+ tainted_tiff<uint16_t*> t_wDPIUnit = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_INCH; | |
- if (TIFFGetField(m_tif_ctx.get(), TIFFTAG_RESOLUTIONUNIT, | |
- &pAttribute->m_wDPIUnit)) { | |
+ auto dpi_stat_verifier = [&](auto stat) { | |
+ pAttribute->m_wDPIUnit = (*t_wDPIUnit).copy_and_verify(no_verifier<uint16_t>); // should check | |
+ if (stat) { | |
pAttribute->m_wDPIUnit--; | |
- } | |
- Tiff_Exif_GetInfo<uint16_t>(m_tif_ctx.get(), TIFFTAG_ORIENTATION, pAttribute); | |
- if (Tiff_Exif_GetInfo<float>(m_tif_ctx.get(), TIFFTAG_XRESOLUTION, | |
- pAttribute)) { | |
+ } | |
+ }; | |
+ RLBOX_TIFF_SAFE_CALL(TIFFGetField<uint16_t>, dpi_stat_verifier, TIFFTAG_RESOLUTIONUNIT, t_wDPIUnit); | |
+ m_tif_sbx->free_in_sandbox(t_wDPIUnit); | |
+ | |
+ RLBox_Tiff_Exif_GetInfo<uint16_t>(m_tif_sbx, m_tif_ctx_t, TIFFTAG_ORIENTATION, pAttribute, no_verifier<float>); | |
+ if (RLBox_Tiff_Exif_GetInfo<float>(m_tif_sbx, m_tif_ctx_t, TIFFTAG_XRESOLUTION, | |
+ pAttribute, no_verifier<float>)) { | |
void* val = pAttribute->m_Exif[TIFFTAG_XRESOLUTION]; | |
float fDpi = val ? *reinterpret_cast<float*>(val) : 0; | |
pAttribute->m_nXDPI = static_cast<int32_t>(fDpi + 0.5f); | |
} | |
- if (Tiff_Exif_GetInfo<float>(m_tif_ctx.get(), TIFFTAG_YRESOLUTION, | |
- pAttribute)) { | |
+ if (RLBox_Tiff_Exif_GetInfo<float>(m_tif_sbx, m_tif_ctx_t, TIFFTAG_YRESOLUTION, | |
+ pAttribute, no_verifier<float>)) { | |
void* val = pAttribute->m_Exif[TIFFTAG_YRESOLUTION]; | |
float fDpi = val ? *reinterpret_cast<float*>(val) : 0; | |
pAttribute->m_nYDPI = static_cast<int32_t>(fDpi + 0.5f); | |
} | |
- Tiff_Exif_GetStringInfo(m_tif_ctx.get(), TIFFTAG_IMAGEDESCRIPTION, | |
+ RLBox_Tiff_Exif_GetStringInfo(m_tif_sbx, m_tif_ctx_t, TIFFTAG_IMAGEDESCRIPTION, | |
pAttribute); | |
- Tiff_Exif_GetStringInfo(m_tif_ctx.get(), TIFFTAG_MAKE, pAttribute); | |
- Tiff_Exif_GetStringInfo(m_tif_ctx.get(), TIFFTAG_MODEL, pAttribute); | |
+ RLBox_Tiff_Exif_GetStringInfo(m_tif_sbx, m_tif_ctx_t, TIFFTAG_MAKE, pAttribute); | |
+ RLBox_Tiff_Exif_GetStringInfo(m_tif_sbx, m_tif_ctx_t, TIFFTAG_MODEL, pAttribute); | |
FX_SAFE_INT32 checked_width = tif_width; | |
FX_SAFE_INT32 checked_height = tif_height; | |
@@ -289,18 +426,24 @@ bool CTiffContext::LoadFrameInfo(int32_t frame, | |
*bpc = tif_bpc; | |
if (tif_rps > tif_height) { | |
tif_rps = tif_height; | |
- TIFFSetField(m_tif_ctx.get(), TIFFTAG_ROWSPERSTRIP, tif_rps); | |
+ RLBOX_TIFF_CALL(TIFFSetField<uint32_t>, TIFFTAG_ROWSPERSTRIP, tif_rps); | |
} | |
return true; | |
} | |
bool CTiffContext::IsSupport(const RetainPtr<CFX_DIBitmap>& pDIBitmap) const { | |
- if (TIFFIsTiled(m_tif_ctx.get())) | |
+ | |
+ if (RLBOX_TIFF_SAFE_CALL(TIFFIsTiled, no_verifier<int>)) | |
return false; | |
uint16_t photometric = 0; | |
- if (!TIFFGetField(m_tif_ctx.get(), TIFFTAG_PHOTOMETRIC, &photometric)) | |
- return false; | |
+ { | |
+ tainted_tiff<uint16_t*> t_photometric = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ if (!RLBOX_TIFF_SAFE_CALL(TIFFGetField<uint16_t>, no_verifier<int>, TIFFTAG_PHOTOMETRIC, t_photometric)) | |
+ return false; | |
+ photometric = (*t_photometric).copy_and_verify(no_verifier<uint16_t>); // checked next | |
+ m_tif_sbx->free_in_sandbox(t_photometric); | |
+ } | |
switch (pDIBitmap->GetBPP()) { | |
case 1: | |
@@ -317,21 +460,36 @@ bool CTiffContext::IsSupport(const RetainPtr<CFX_DIBitmap>& pDIBitmap) const { | |
default: | |
return false; | |
} | |
+ | |
uint16_t planarconfig = 0; | |
- if (!TIFFGetFieldDefaulted(m_tif_ctx.get(), TIFFTAG_PLANARCONFIG, | |
- &planarconfig)) | |
- return false; | |
+ { | |
+ tainted_tiff<uint16_t*> t_planarconfig = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ if (!RLBOX_TIFF_SAFE_CALL(TIFFGetFieldDefaulted<uint16_t>, no_verifier<int>, TIFFTAG_PLANARCONFIG, t_planarconfig)) | |
+ return false; | |
+ planarconfig = (*t_planarconfig).copy_and_verify(no_verifier<uint16_t>); // checked next | |
+ m_tif_sbx->free_in_sandbox(t_planarconfig); | |
+ } | |
return planarconfig != PLANARCONFIG_SEPARATE; | |
} | |
void CTiffContext::SetPalette(const RetainPtr<CFX_DIBitmap>& pDIBitmap, | |
uint16_t bps) { | |
- uint16_t* red_orig = nullptr; | |
- uint16_t* green_orig = nullptr; | |
- uint16_t* blue_orig = nullptr; | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_COLORMAP, &red_orig, &green_orig, | |
- &blue_orig); | |
+ tainted_tiff<uint16_t**> t_red_orig = m_tif_sbx->malloc_in_sandbox<uint16_t*>(); | |
+ tainted_tiff<uint16_t**> t_green_orig = m_tif_sbx->malloc_in_sandbox<uint16_t*>(); | |
+ tainted_tiff<uint16_t**> t_blue_orig = m_tif_sbx->malloc_in_sandbox<uint16_t*>(); | |
+ | |
+ RLBOX_TIFF_SAFE_CALL(TTIFFGetFieldColorMap, no_verifier<int>, TIFFTAG_COLORMAP, t_red_orig, t_green_orig, t_blue_orig); | |
+ tainted_tiff<uint16_t*> tt_red_orig = *t_red_orig; | |
+ tainted_tiff<uint16_t*> tt_green_orig = *t_green_orig; | |
+ tainted_tiff<uint16_t*> tt_blue_orig = *t_blue_orig; | |
+ | |
+ bool copied = false; // not sure we care about copy or transfer; shr? | |
+ size_t size = (1 << bps) * sizeof(uint16_t); | |
+ uint16_t* red_orig = rlbox::copy_memory_or_deny_access(*m_tif_sbx, tt_red_orig, size, false, copied); | |
+ uint16_t* green_orig = rlbox::copy_memory_or_deny_access(*m_tif_sbx, tt_green_orig, size, false, copied); | |
+ uint16_t* blue_orig = rlbox::copy_memory_or_deny_access(*m_tif_sbx, tt_blue_orig, size, false, copied); | |
+ | |
for (int32_t i = (1L << bps) - 1; i >= 0; i--) { | |
#define CVT(x) ((uint16_t)((x) >> 8)) | |
red_orig[i] = CVT(red_orig[i]); | |
@@ -348,6 +506,10 @@ void CTiffContext::SetPalette(const RetainPtr<CFX_DIBitmap>& pDIBitmap, | |
(((uint32)0xffL) << 24); | |
pDIBitmap->SetPaletteArgb(index, color); | |
} | |
+ m_tif_sbx->free_in_sandbox(t_red_orig); | |
+ m_tif_sbx->free_in_sandbox(t_green_orig); | |
+ m_tif_sbx->free_in_sandbox(t_blue_orig); | |
+ | |
} | |
bool CTiffContext::Decode1bppRGB(const RetainPtr<CFX_DIBitmap>& pDIBitmap, | |
@@ -360,21 +522,22 @@ bool CTiffContext::Decode1bppRGB(const RetainPtr<CFX_DIBitmap>& pDIBitmap, | |
return false; | |
} | |
SetPalette(pDIBitmap, bps); | |
- int32_t size = static_cast<int32_t>(TIFFScanlineSize(m_tif_ctx.get())); | |
- uint8_t* buf = (uint8_t*)_TIFFmalloc(size); | |
- if (!buf) { | |
- TIFFError(TIFFFileName(m_tif_ctx.get()), "No space for scanline buffer"); | |
+ int32_t size = static_cast<int32_t>(RLBOX_TIFF_SAFE_CALL(TIFFScanlineSize, no_verifier<size_t>)); // should check overflow | |
+ tainted_tiff<uint8_t*> t_buf = m_tif_sbx->malloc_in_sandbox<uint8_t>(size); | |
+ if (!t_buf) { | |
+ // error handling is suppressed | |
+ // TIFFError(TIFFFileName(m_tif_ctx.get()), "No space for scanline buffer"); | |
return false; | |
} | |
uint8_t* bitMapbuffer = (uint8_t*)pDIBitmap->GetBuffer(); | |
uint32_t pitch = pDIBitmap->GetPitch(); | |
for (int32_t row = 0; row < height; row++) { | |
- TIFFReadScanline(m_tif_ctx.get(), buf, row, 0); | |
+ RLBOX_TIFF_CALL(TIFFReadScanline, t_buf, row, 0); | |
for (int32_t j = 0; j < size; j++) { | |
- bitMapbuffer[row * pitch + j] = buf[j]; | |
+ bitMapbuffer[row * pitch + j] = t_buf[j].copy_and_verify(no_verifier<uint8_t>); // nothing to check | |
} | |
} | |
- _TIFFfree(buf); | |
+ m_tif_sbx->free_in_sandbox(t_buf); | |
return true; | |
} | |
@@ -388,29 +551,31 @@ bool CTiffContext::Decode8bppRGB(const RetainPtr<CFX_DIBitmap>& pDIBitmap, | |
return false; | |
} | |
SetPalette(pDIBitmap, bps); | |
- int32_t size = static_cast<int32_t>(TIFFScanlineSize(m_tif_ctx.get())); | |
- uint8_t* buf = (uint8_t*)_TIFFmalloc(size); | |
- if (!buf) { | |
- TIFFError(TIFFFileName(m_tif_ctx.get()), "No space for scanline buffer"); | |
+ int32_t size = static_cast<int32_t>(RLBOX_TIFF_SAFE_CALL(TIFFScanlineSize, no_verifier<size_t>)); // should check overflow | |
+ tainted_tiff<uint8_t*> t_buf = m_tif_sbx->malloc_in_sandbox<uint8_t>(size); | |
+ if (!t_buf) { | |
+ // error handling is suppressed | |
+ // TIFFError(TIFFFileName(m_tif_ctx.get()), "No space for scanline buffer"); | |
return false; | |
} | |
uint8_t* bitMapbuffer = (uint8_t*)pDIBitmap->GetBuffer(); | |
uint32_t pitch = pDIBitmap->GetPitch(); | |
for (int32_t row = 0; row < height; row++) { | |
- TIFFReadScanline(m_tif_ctx.get(), buf, row, 0); | |
+ RLBOX_TIFF_CALL(TIFFReadScanline, t_buf, row, 0); | |
for (int32_t j = 0; j < size; j++) { | |
+ uint8_t buf_j = t_buf[j].copy_and_verify(no_verifier<uint8_t>); // copy once, nothing to verify | |
switch (bps) { | |
case 4: | |
- bitMapbuffer[row * pitch + 2 * j + 0] = (buf[j] & 0xF0) >> 4; | |
- bitMapbuffer[row * pitch + 2 * j + 1] = (buf[j] & 0x0F) >> 0; | |
+ bitMapbuffer[row * pitch + 2 * j + 0] = (buf_j & 0xF0) >> 4; | |
+ bitMapbuffer[row * pitch + 2 * j + 1] = (buf_j & 0x0F) >> 0; | |
break; | |
case 8: | |
- bitMapbuffer[row * pitch + j] = buf[j]; | |
+ bitMapbuffer[row * pitch + j] = buf_j; | |
break; | |
} | |
} | |
} | |
- _TIFFfree(buf); | |
+ m_tif_sbx->free_in_sandbox(t_buf); | |
return true; | |
} | |
@@ -422,53 +587,83 @@ bool CTiffContext::Decode24bppRGB(const RetainPtr<CFX_DIBitmap>& pDIBitmap, | |
if (pDIBitmap->GetBPP() != 24 || !IsSupport(pDIBitmap)) | |
return false; | |
- int32_t size = static_cast<int32_t>(TIFFScanlineSize(m_tif_ctx.get())); | |
- uint8_t* buf = (uint8_t*)_TIFFmalloc(size); | |
- if (!buf) { | |
- TIFFError(TIFFFileName(m_tif_ctx.get()), "No space for scanline buffer"); | |
+ int32_t size = static_cast<int32_t>(RLBOX_TIFF_SAFE_CALL(TIFFScanlineSize, no_verifier<size_t>)); // should check overflow | |
+ tainted_tiff<uint8_t*> t_buf = m_tif_sbx->malloc_in_sandbox<uint8_t>(size); | |
+ if (!t_buf) { | |
+ // error handling is suppressed | |
+ // TIFFError(TIFFFileName(m_tif_ctx.get()), "No space for scanline buffer"); | |
return false; | |
} | |
uint8_t* bitMapbuffer = (uint8_t*)pDIBitmap->GetBuffer(); | |
uint32_t pitch = pDIBitmap->GetPitch(); | |
for (int32_t row = 0; row < height; row++) { | |
- TIFFReadScanline(m_tif_ctx.get(), buf, row, 0); | |
+ RLBOX_TIFF_CALL(TIFFReadScanline, t_buf, row, 0); | |
for (int32_t j = 0; j < size - 2; j += 3) { | |
- bitMapbuffer[row * pitch + j + 0] = buf[j + 2]; | |
- bitMapbuffer[row * pitch + j + 1] = buf[j + 1]; | |
- bitMapbuffer[row * pitch + j + 2] = buf[j + 0]; | |
+ bitMapbuffer[row * pitch + j + 0] = t_buf[j + 2].copy_and_verify(no_verifier<uint8_t>); // nothing | |
+ bitMapbuffer[row * pitch + j + 1] = t_buf[j + 1].copy_and_verify(no_verifier<uint8_t>); // to | |
+ bitMapbuffer[row * pitch + j + 2] = t_buf[j + 0].copy_and_verify(no_verifier<uint8_t>); // check | |
} | |
} | |
- _TIFFfree(buf); | |
+ m_tif_sbx->free_in_sandbox(t_buf); | |
return true; | |
} | |
bool CTiffContext::Decode(const RetainPtr<CFX_DIBitmap>& pDIBitmap) { | |
uint32_t img_width = pDIBitmap->GetWidth(); | |
uint32_t img_height = pDIBitmap->GetHeight(); | |
+ | |
uint32_t width = 0; | |
uint32_t height = 0; | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_IMAGEWIDTH, &width); | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_IMAGELENGTH, &height); | |
+ { | |
+ tainted_tiff<uint32_t*> t_width = m_tif_sbx->malloc_in_sandbox<uint32_t>(); | |
+ tainted_tiff<uint32_t*> t_height = m_tif_sbx->malloc_in_sandbox<uint32_t>(); | |
+ | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint32_t>, TIFFTAG_IMAGEWIDTH, t_width); | |
+ width = (*t_width).copy_and_verify(no_verifier<uint32_t>); // checked below | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint32_t>, TIFFTAG_IMAGELENGTH, t_height); | |
+ height = (*t_height).copy_and_verify(no_verifier<uint32_t>); // checked below | |
+ m_tif_sbx->free_in_sandbox(t_width); | |
+ m_tif_sbx->free_in_sandbox(t_height); | |
+ } | |
+ | |
if (img_width != width || img_height != height) | |
return false; | |
if (pDIBitmap->GetBPP() == 32) { | |
- uint16_t rotation = ORIENTATION_TOPLEFT; | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_ORIENTATION, &rotation); | |
- if (TIFFReadRGBAImageOriented(m_tif_ctx.get(), img_width, img_height, | |
- (uint32*)pDIBitmap->GetBuffer(), rotation, | |
- 1)) { | |
+ tainted_tiff<uint16_t*> t_rotation = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint16_t>, TIFFTAG_ORIENTATION, t_rotation); | |
+ uint16_t rotation = (*t_rotation).copy_and_verify(no_verifier<uint16_t>); // should check | |
+ | |
+ size_t size = img_width * img_height; | |
+ tainted_tiff<uint32_t*> t_buf = m_tif_sbx->malloc_in_sandbox<uint32_t>(size); | |
+ if (RLBOX_TIFF_SAFE_CALL(TIFFReadRGBAImageOriented, no_verifier<int>, | |
+ img_width, img_height, t_buf, rotation, 1)) { | |
+ // Copy decoded image. We copy it twice, but shouldn't need to do this. | |
+ // TODO(shr): do we have an alternative API? | |
+ t_buf.copy_and_verify_range([&](std::unique_ptr<uint32_t[]> img) { | |
+ memcpy(pDIBitmap->GetBuffer(), img.release(), size*sizeof(uint32_t)); | |
+ }, size); | |
+ m_tif_sbx->free_in_sandbox(t_buf); | |
for (uint32_t row = 0; row < img_height; row++) { | |
uint8_t* row_buf = pDIBitmap->GetWritableScanline(row); | |
TiffBGRA2RGBA(row_buf, img_width, 4); | |
} | |
return true; | |
} | |
+ m_tif_sbx->free_in_sandbox(t_buf); | |
} | |
uint16_t spp = 0; | |
uint16_t bps = 0; | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_SAMPLESPERPIXEL, &spp); | |
- TIFFGetField(m_tif_ctx.get(), TIFFTAG_BITSPERSAMPLE, &bps); | |
+ { | |
+ tainted_tiff<uint16_t*> t_spp = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ tainted_tiff<uint16_t*> t_bps = m_tif_sbx->malloc_in_sandbox<uint16_t>(); | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint16_t>, TIFFTAG_SAMPLESPERPIXEL, t_spp); | |
+ RLBOX_TIFF_CALL(TIFFGetField<uint16_t>, TIFFTAG_BITSPERSAMPLE, t_bps); | |
+ spp = (*t_spp).copy_and_verify(no_verifier<uint16_t>); // checked below | |
+ bps = (*t_bps).copy_and_verify(no_verifier<uint16_t>); // checked below | |
+ m_tif_sbx->free_in_sandbox(t_spp); | |
+ m_tif_sbx->free_in_sandbox(t_bps); | |
+ } | |
FX_SAFE_UINT32 safe_bpp = bps; | |
safe_bpp *= spp; | |
if (!safe_bpp.IsValid()) | |
-- | |
2.27.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment