aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2006-08-23 18:00:30 +0200
committerAdrian Bunk <bunk@stusta.de>2006-08-23 18:00:30 +0200
commitb9a96aa8fa91f4f3187d141a84f0aeaed2935cbe (patch)
treec18f8072d6b4f7f34996bdc782842081f4c4a0e4 /fs
parentccef2db6c097ff35d4e446a6d85c657afb5567d2 (diff)
Fix possible UDF deadlock and memory corruption (CVE-2006-4145)
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 <jack@suse.cz> Signed-off-by: Adrian Bunk <bunk@stusta.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/udf/truncate.c64
2 files changed, 40 insertions, 26 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 368d8f81fe5..c5191e1d7fc 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1657,7 +1657,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:
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index e1b0e8cfecb..0abd66ce36e 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);
}
}
}