projects/linux·commit 00a2b0f6

Fix possible UDF deadlock and memory corruption (CVE-2006-4145)

00a2b0f6 · Jan Kara <[email protected]> · 2006-08-15 13:56:26 +02:00

UDF code is not really ready to handle extents larger that 1GB. This is
the easy way to forbid creating those.

Also truncation code did not count with the case when there are no
extents in the file and we are extending the file.

Signed-off-by: Jan Kara <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
Commit
00a2b0f6dd2372842df73de72d51621b539fea44
Parents
c164a9ba

Changes

2 files changed · +40 −26

FileStatusAddDelContent
fs/udf/super.cmodified+1−1View file
fs/udf/truncate.cmodified+39−25View file

fs/udf/super.c

View file
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 7de172e..fcce1a2 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1659,7 +1659,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
iput(inode);
goto error_out;
}
- sb->s_maxbytes = MAX_LFS_FILESIZE;
+ sb->s_maxbytes = 1<<30;
return 0;
error_out:

fs/udf/truncate.c

View file
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index e1b0e8c..0abd66c 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -239,37 +239,51 @@ void udf_truncate_extents(struct inode * inode)
{
if (offset)
{
- extoffset -= adsize;
- etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
- if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- {
- extoffset -= adsize;
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
- udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
+ /*
+ * OK, there is not extent covering inode->i_size and
+ * no extent above inode->i_size => truncate is
+ * extending the file by 'offset'.
+ */
+ if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) ||
+ (bh && extoffset == sizeof(struct allocExtDesc))) {
+ /* File has no extents at all! */
+ memset(&eloc, 0x00, sizeof(kernel_lb_addr));
+ elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
+ udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
}
- else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- kernel_lb_addr neloc = { 0, 0 };
+ else {
extoffset -= adsize;
- nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
- ((elen + offset + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
- udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
- }
- else
- {
- if (elen & (inode->i_sb->s_blocksize - 1))
+ etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
+ if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
+ {
+ extoffset -= adsize;
+ elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
+ udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
+ }
+ else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
{
+ kernel_lb_addr neloc = { 0, 0 };
extoffset -= adsize;
- elen = EXT_RECORDED_ALLOCATED |
- ((elen + inode->i_sb->s_blocksize - 1) &
+ nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ ((elen + offset + inode->i_sb->s_blocksize - 1) &
~(inode->i_sb->s_blocksize - 1));
- udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
+ udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
+ udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
+ }
+ else
+ {
+ if (elen & (inode->i_sb->s_blocksize - 1))
+ {
+ extoffset -= adsize;
+ elen = EXT_RECORDED_ALLOCATED |
+ ((elen + inode->i_sb->s_blocksize - 1) &
+ ~(inode->i_sb->s_blocksize - 1));
+ udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
+ }
+ memset(&eloc, 0x00, sizeof(kernel_lb_addr));
+ elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
+ udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
}
- memset(&eloc, 0x00, sizeof(kernel_lb_addr));
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
}
}
}