Make TIFF parsing a bit safer
At least on 64-bit systems, 32-bit may still have holes.
This commit is contained in:
parent
df7c7b9f6b
commit
902eaf5a01
9
fiv-io.c
9
fiv-io.c
@ -1844,11 +1844,10 @@ tiff_ep_find_jpeg_evaluate(const struct tiffer *T, struct tiff_ep_jpeg *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t ipointer = 0, ilength = 0;
|
int64_t ipointer = 0, ilength = 0;
|
||||||
if (!tiffer_find_integer(T, tag_pointer, &ipointer) ||
|
if (!tiffer_find_integer(T, tag_pointer, &ipointer) || ipointer <= 0 ||
|
||||||
!tiffer_find_integer(T, tag_length, &ilength) ||
|
!tiffer_find_integer(T, tag_length, &ilength) || ilength <= 0 ||
|
||||||
ipointer <= 0 || ilength <= 0 ||
|
ipointer > T->end - T->begin ||
|
||||||
(uint64_t) ilength > SIZE_MAX ||
|
T->end - T->begin - ipointer < ilength)
|
||||||
ipointer + ilength > (T->end - T->begin))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Note that to get the largest JPEG,
|
// Note that to get the largest JPEG,
|
||||||
|
15
tiffer.h
15
tiffer.h
@ -15,9 +15,10 @@
|
|||||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// --- Utilities ---------------------------------------------------------------
|
// --- Utilities ---------------------------------------------------------------
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ struct tiffer {
|
|||||||
static bool
|
static bool
|
||||||
tiffer_u32(struct tiffer *self, uint32_t *u)
|
tiffer_u32(struct tiffer *self, uint32_t *u)
|
||||||
{
|
{
|
||||||
if (self->p < self->begin || self->p + 4 > self->end)
|
if (self->end - self->p < 4)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*u = self->un->u32(self->p);
|
*u = self->un->u32(self->p);
|
||||||
@ -96,7 +97,7 @@ tiffer_u32(struct tiffer *self, uint32_t *u)
|
|||||||
static bool
|
static bool
|
||||||
tiffer_u16(struct tiffer *self, uint16_t *u)
|
tiffer_u16(struct tiffer *self, uint16_t *u)
|
||||||
{
|
{
|
||||||
if (self->p < self->begin || self->p + 2 > self->end)
|
if (self->end - self->p < 2)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*u = self->un->u16(self->p);
|
*u = self->un->u16(self->p);
|
||||||
@ -160,6 +161,9 @@ static bool
|
|||||||
tiffer_subifd(
|
tiffer_subifd(
|
||||||
const struct tiffer *self, uint32_t offset, struct tiffer *subreader)
|
const struct tiffer *self, uint32_t offset, struct tiffer *subreader)
|
||||||
{
|
{
|
||||||
|
if (self->end - self->begin < offset)
|
||||||
|
return false;
|
||||||
|
|
||||||
*subreader = *self;
|
*subreader = *self;
|
||||||
subreader->p = subreader->begin + offset;
|
subreader->p = subreader->begin + offset;
|
||||||
return tiffer_u16(subreader, &subreader->remaining_fields);
|
return tiffer_u16(subreader, &subreader->remaining_fields);
|
||||||
@ -323,14 +327,15 @@ tiffer_next_entry(struct tiffer *self, struct tiffer_entry *entry)
|
|||||||
if (values_size <= sizeof offset) {
|
if (values_size <= sizeof offset) {
|
||||||
entry->p = self->p;
|
entry->p = self->p;
|
||||||
self->p += sizeof offset;
|
self->p += sizeof offset;
|
||||||
} else if (tiffer_u32(self, &offset)) {
|
} else if (tiffer_u32(self, &offset) && self->end - self->begin >= offset) {
|
||||||
entry->p = self->begin + offset;
|
entry->p = self->begin + offset;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All entries are pre-checked not to overflow.
|
// All entries are pre-checked not to overflow.
|
||||||
if (entry->p + values_size > self->end)
|
if (values_size > PTRDIFF_MAX ||
|
||||||
|
self->end - entry->p < (ptrdiff_t) values_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Setting it at the end may provide an indication while debugging.
|
// Setting it at the end may provide an indication while debugging.
|
||||||
|
15
tools/info.h
15
tools/info.h
@ -92,8 +92,8 @@ static jv parse_jpeg(jv o, const uint8_t *p, size_t len);
|
|||||||
static jv parse_exif_ifd(struct tiffer *T, const struct tiff_entry *info);
|
static jv parse_exif_ifd(struct tiffer *T, const struct tiff_entry *info);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_exif_subifds_entry(struct tiffer *T, const struct tiffer_entry *entry,
|
parse_exif_subifds_entry(const struct tiffer *T,
|
||||||
struct tiffer *subT)
|
const struct tiffer_entry *entry, struct tiffer *subT)
|
||||||
{
|
{
|
||||||
int64_t offset = 0;
|
int64_t offset = 0;
|
||||||
return tiffer_integer(T, entry, &offset) &&
|
return tiffer_integer(T, entry, &offset) &&
|
||||||
@ -101,7 +101,7 @@ parse_exif_subifds_entry(struct tiffer *T, const struct tiffer_entry *entry,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static jv
|
static jv
|
||||||
parse_exif_subifds(struct tiffer *T, struct tiffer_entry *entry,
|
parse_exif_subifds(const struct tiffer *T, struct tiffer_entry *entry,
|
||||||
struct tiff_entry *info)
|
struct tiff_entry *info)
|
||||||
{
|
{
|
||||||
struct tiffer subT = {};
|
struct tiffer subT = {};
|
||||||
@ -173,7 +173,7 @@ parse_exif_extract_sole_array_element(jv a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static jv
|
static jv
|
||||||
parse_exif_entry(jv o, struct tiffer *T, struct tiffer_entry *entry,
|
parse_exif_entry(jv o, const struct tiffer *T, struct tiffer_entry *entry,
|
||||||
const struct tiff_entry *info)
|
const struct tiff_entry *info)
|
||||||
{
|
{
|
||||||
static struct tiff_entry empty[] = {{}};
|
static struct tiff_entry empty[] = {{}};
|
||||||
@ -679,7 +679,7 @@ static struct tiff_entry mpf_entries[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
parse_mpf_mpentry(jv *a, const uint8_t *p, struct tiffer *T)
|
parse_mpf_mpentry(jv *a, const uint8_t *p, const struct tiffer *T)
|
||||||
{
|
{
|
||||||
uint32_t attrs = T->un->u32(p);
|
uint32_t attrs = T->un->u32(p);
|
||||||
uint32_t offset = T->un->u32(p + 8);
|
uint32_t offset = T->un->u32(p + 8);
|
||||||
@ -725,7 +725,7 @@ parse_mpf_mpentry(jv *a, const uint8_t *p, struct tiffer *T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static jv
|
static jv
|
||||||
parse_mpf_index_entry(jv o, const uint8_t ***offsets, struct tiffer *T,
|
parse_mpf_index_entry(jv o, const uint8_t ***offsets, const struct tiffer *T,
|
||||||
struct tiffer_entry *entry)
|
struct tiffer_entry *entry)
|
||||||
{
|
{
|
||||||
// 5.2.3.3. MP Entry
|
// 5.2.3.3. MP Entry
|
||||||
@ -738,6 +738,9 @@ parse_mpf_index_entry(jv o, const uint8_t ***offsets, struct tiffer *T,
|
|||||||
jv a = jv_array_sized(count);
|
jv a = jv_array_sized(count);
|
||||||
const uint8_t **out = *offsets = calloc(sizeof *out, count + 1);
|
const uint8_t **out = *offsets = calloc(sizeof *out, count + 1);
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
// 5.2.3.3.3. Individual Image Data Offset
|
||||||
|
// XXX: We might want to warn about out-of-bounds pointers,
|
||||||
|
// however T->end is for the MPF segment and ends too early.
|
||||||
uint32_t offset = parse_mpf_mpentry(&a, entry->p + i * 16, T);
|
uint32_t offset = parse_mpf_mpentry(&a, entry->p + i * 16, T);
|
||||||
if (offset)
|
if (offset)
|
||||||
*out++ = T->begin + offset;
|
*out++ = T->begin + offset;
|
||||||
|
Loading…
Reference in New Issue
Block a user