Skip to content

Instantly share code, notes, and snippets.

@deian
Last active March 8, 2021 06:23
Show Gist options
  • Save deian/6ce46eb8c3e079034d8698cf3ca99a51 to your computer and use it in GitHub Desktop.
Save deian/6ce46eb8c3e079034d8698cf3ca99a51 to your computer and use it in GitHub Desktop.
Retrofit libtiff use in pdfium to use RLBox
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