[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Libcdio-devel] proposed fix for bug #22865
From: |
Pete Batard |
Subject: |
Re: [Libcdio-devel] proposed fix for bug #22865 |
Date: |
Mon, 23 Jan 2012 17:43:14 +0000 |
User-agent: |
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0) Gecko/20111222 Thunderbird/9.0.1 |
OK, here is my actual proposed fix for #22865.
Haven't applied it to my branch as I want to see if it looks sound to
you, or if you prefer something different.
Also note that I'm adding an assert for the size of udf_file_entry_t in
udf_open.
Once this patch is applied, and if you test against the Windows 8
preview, you will still end up with "Error reading UDF file
/sources/install.wim" on Linux 32 bit (haven't test x64), but this time
it should be due to a 32 bit offset issue. I'll discuss that in an
upcoming mail.
Regards,
/Pete
>From 0d5e54af5ce136929ef714f5988ba689e8d42656 Mon Sep 17 00:00:00 2001
From: Pete Batard <address@hidden>
Date: Mon, 23 Jan 2012 12:34:11 +0000
Subject: [PATCH] Fix buffer overflow when reusing an UDF file entry
* use an union to ensure a file entry is always the maximum
allocatable size as per specs
* this is bug #22865
---
include/cdio/ecma_167.h | 10 ++++++++--
lib/udf/udf_file.c | 5 ++---
lib/udf/udf_fs.c | 36 +++++++++++++++---------------------
3 files changed, 25 insertions(+), 26 deletions(-)
diff --git a/include/cdio/ecma_167.h b/include/cdio/ecma_167.h
index 78da7ae..9c7c1bb 100644
--- a/include/cdio/ecma_167.h
+++ b/include/cdio/ecma_167.h
@@ -727,8 +727,14 @@ struct udf_file_entry_s
udf_Uint64_t unique_ID;
udf_Uint32_t i_extended_attr;
udf_Uint32_t i_alloc_descs;
- udf_Uint8_t ext_attr[0];
- udf_Uint8_t alloc_descs[0];
+ /* The following union allows file entry reuse without worrying
+ about overflows, by ensuring the struct is always the
+ maximum possible size allowed by the specs: one UDF block. */
+ union {
+ udf_Uint8_t ext_attr[0];
+ udf_Uint8_t alloc_descs[0];
+ udf_Uint8_t pad_to_one_block[2048-176];
+ } u;
} GNUC_PACKED;
typedef struct udf_file_entry_s udf_file_entry_t;
diff --git a/lib/udf/udf_file.c b/lib/udf/udf_file.c
index ee766a8..ca4d920 100644
--- a/lib/udf/udf_file.c
+++ b/lib/udf/udf_file.c
@@ -34,7 +34,7 @@
#define CEILING(x, y) ((x+(y-1))/y)
#define GETICB(offset) \
- &p_udf_fe->alloc_descs[offset]
+ &p_udf_fe->u.alloc_descs[offset]
const char *
udf_get_filename(const udf_dirent_t *p_udf_dirent)
@@ -44,8 +44,7 @@ udf_get_filename(const udf_dirent_t *p_udf_dirent)
return p_udf_dirent->psz_name;
}
-/* Get UDF File Entry. However we do NOT get the variable-length extended
- attributes. */
+/* Copy an UDF File Entry into a Directory Entry structure. */
bool
udf_get_file_entry(const udf_dirent_t *p_udf_dirent,
/*out*/ udf_file_entry_t *p_udf_fe)
diff --git a/lib/udf/udf_fs.c b/lib/udf/udf_fs.c
index dcd6e53..eb1da77 100644
--- a/lib/udf/udf_fs.c
+++ b/lib/udf/udf_fs.c
@@ -68,6 +68,7 @@ const char VSD_STD_ID_TEA01[] = {'T', 'E', 'A', '0', '1'};
#include <cdio/bytesex.h>
#include "udf_private.h"
#include "udf_fs.h"
+#include "cdio_assert.h"
/*
* The UDF specs are pretty clear on how each data structure is made
@@ -154,7 +155,7 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
{
/* The allocation descriptor field is filled with short_ad's. */
udf_short_ad_t *p_ad = (udf_short_ad_t *)
- (p_udf_fe->ext_attr + p_udf_fe->i_extended_attr);
+ (p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr);
*start = uint32_from_le(p_ad->pos);
*end = *start +
@@ -166,7 +167,7 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
{
/* The allocation descriptor field is filled with long_ad's */
udf_long_ad_t *p_ad = (udf_long_ad_t *)
- (p_udf_fe->ext_attr + p_udf_fe->i_extended_attr);
+ (p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr);
*start = uint32_from_le(p_ad->loc.lba); /* ignore partition number */
*end = *start +
@@ -177,7 +178,7 @@ udf_get_lba(const udf_file_entry_t *p_udf_fe,
case ICBTAG_FLAG_AD_EXTENDED:
{
udf_ext_ad_t *p_ad = (udf_ext_ad_t *)
- (p_udf_fe->ext_attr + p_udf_fe->i_extended_attr);
+ (p_udf_fe->u.ext_attr + p_udf_fe->i_extended_attr);
*start = uint32_from_le(p_ad->ext_loc.lba); /* ignore partition number */
*end = *start +
@@ -287,11 +288,8 @@ static udf_dirent_t *
udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf,
const char *psz_name, bool b_dir, bool b_parent)
{
- const unsigned int i_alloc_size = p_udf_fe->i_alloc_descs
- + p_udf_fe->i_extended_attr;
-
udf_dirent_t *p_udf_dirent = (udf_dirent_t *)
- calloc(1, sizeof(udf_dirent_t) + i_alloc_size);
+ calloc(1, sizeof(udf_dirent_t));
if (!p_udf_dirent) return NULL;
p_udf_dirent->psz_name = strdup(psz_name);
@@ -302,7 +300,7 @@ udf_new_dirent(udf_file_entry_t *p_udf_fe, udf_t *p_udf,
p_udf_dirent->dir_left = uint64_from_le(p_udf_fe->info_len);
memcpy(&(p_udf_dirent->fe), p_udf_fe,
- sizeof(udf_file_entry_t) + i_alloc_size);
+ sizeof(udf_file_entry_t));
udf_get_lba( p_udf_fe, &(p_udf_dirent->i_loc),
&(p_udf_dirent->i_loc_end) );
return p_udf_dirent;
@@ -349,6 +347,9 @@ udf_open (const char *psz_path)
if (!p_udf) return NULL;
+ /* Sanity check */
+ cdio_assert(sizeof(udf_file_entry_t) == UDF_BLOCKSIZE);
+
p_udf->cdio = cdio_open(psz_path, DRIVER_UNKNOWN);
if (!p_udf->cdio) {
/* Not a CD-ROM drive or CD Image. Maybe it's a UDF file not
@@ -585,19 +586,18 @@ udf_opendir(const udf_dirent_t *p_udf_dirent)
{
if (p_udf_dirent->b_dir && !p_udf_dirent->b_parent && p_udf_dirent->fid) {
udf_t *p_udf = p_udf_dirent->p_udf;
- uint8_t data[UDF_BLOCKSIZE];
- udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data;
+ udf_file_entry_t udf_fe;
driver_return_code_t i_ret =
- udf_read_sectors(p_udf, p_udf_fe, p_udf->i_part_start
+ udf_read_sectors(p_udf, &udf_fe, p_udf->i_part_start
+ p_udf_dirent->fid->icb.loc.lba, 1);
if (DRIVER_OP_SUCCESS == i_ret
- && !udf_checktag(&p_udf_fe->tag, TAGID_FILE_ENTRY)) {
+ && !udf_checktag(&udf_fe.tag, TAGID_FILE_ENTRY)) {
- if (ICBTAG_FILE_TYPE_DIRECTORY == p_udf_fe->icb_tag.file_type) {
+ if (ICBTAG_FILE_TYPE_DIRECTORY == udf_fe.icb_tag.file_type) {
udf_dirent_t *p_udf_dirent_new =
- udf_new_dirent(p_udf_fe, p_udf, p_udf_dirent->psz_name, true, true);
+ udf_new_dirent(&udf_fe, p_udf, p_udf_dirent->psz_name, true, true);
return p_udf_dirent_new;
}
}
@@ -661,16 +661,10 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
{
const unsigned int i_len = p_udf_dirent->fid->i_file_id;
- uint8_t data[UDF_BLOCKSIZE] = {0};
- udf_file_entry_t *p_udf_fe = (udf_file_entry_t *) &data;
- if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, p_udf_fe,
p_udf->i_part_start
+ if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &p_udf_dirent->fe,
p_udf->i_part_start
+ p_udf_dirent->fid->icb.loc.lba, 1))
return NULL;
-
- memcpy(&(p_udf_dirent->fe), p_udf_fe,
- sizeof(udf_file_entry_t) + p_udf_fe->i_alloc_descs
- + p_udf_fe->i_extended_attr );
if (strlen(p_udf_dirent->psz_name) < i_len)
p_udf_dirent->psz_name = (char *)
--
1.7.8.msysgit.0