提交 ab9a3a73 编写于 作者: S Steven J. Magnani 提交者: Jan Kara

udf: reduce leakage of blocks related to named streams

Windows is capable of creating UDF files having named streams.
One example is the "Zone.Identifier" stream attached automatically
to files downloaded from a network. See:
  https://msdn.microsoft.com/en-us/library/dn392609.aspx

Modification of a file having one or more named streams in Linux causes
the stream directory to become detached from the file, essentially leaking
all blocks pertaining to the file's streams.

Fix by saving off information about an inode's streams when reading it,
for later use when its on-disk data is updated.

Link: https://lore.kernel.org/r/20190814125002.10869-1-steve@digidescorp.comSigned-off-by: NSteven J. Magnani <steve@digidescorp.com>
Signed-off-by: NJan Kara <jack@suse.cz>
上级 56db1991
......@@ -1485,6 +1485,8 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs);
iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint);
iinfo->i_streamdir = 0;
iinfo->i_lenStreams = 0;
} else {
inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9);
......@@ -1498,6 +1500,16 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
/* Named streams */
iinfo->i_streamdir = (efe->streamDirectoryICB.extLength != 0);
iinfo->i_locStreamdir =
lelb_to_cpu(efe->streamDirectoryICB.extLocation);
iinfo->i_lenStreams = le64_to_cpu(efe->objectSize);
if (iinfo->i_lenStreams >= inode->i_size)
iinfo->i_lenStreams -= inode->i_size;
else
iinfo->i_lenStreams = 0;
}
inode->i_generation = iinfo->i_unique;
......@@ -1760,9 +1772,19 @@ static int udf_update_inode(struct inode *inode, int do_sync)
iinfo->i_ext.i_data,
inode->i_sb->s_blocksize -
sizeof(struct extendedFileEntry));
efe->objectSize = cpu_to_le64(inode->i_size);
efe->objectSize =
cpu_to_le64(inode->i_size + iinfo->i_lenStreams);
efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
if (iinfo->i_streamdir) {
struct long_ad *icb_lad = &efe->streamDirectoryICB;
icb_lad->extLocation =
cpu_to_lelb(iinfo->i_locStreamdir);
icb_lad->extLength =
cpu_to_le32(inode->i_sb->s_blocksize);
}
udf_adjust_time(iinfo, inode->i_atime);
udf_adjust_time(iinfo, inode->i_mtime);
udf_adjust_time(iinfo, inode->i_ctime);
......
......@@ -151,9 +151,11 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
ei->i_unique = 0;
ei->i_lenExtents = 0;
ei->i_lenStreams = 0;
ei->i_next_alloc_block = 0;
ei->i_next_alloc_goal = 0;
ei->i_strat4096 = 0;
ei->i_streamdir = 0;
init_rwsem(&ei->i_data_sem);
ei->cached_extent.lstart = -1;
spin_lock_init(&ei->i_extent_cache_lock);
......
......@@ -42,12 +42,15 @@ struct udf_inode_info {
unsigned i_efe : 1; /* extendedFileEntry */
unsigned i_use : 1; /* unallocSpaceEntry */
unsigned i_strat4096 : 1;
unsigned reserved : 26;
unsigned i_streamdir : 1;
unsigned reserved : 25;
union {
struct short_ad *i_sad;
struct long_ad *i_lad;
__u8 *i_data;
} i_ext;
struct kernel_lb_addr i_locStreamdir;
__u64 i_lenStreams;
struct rw_semaphore i_data_sem;
struct udf_ext_cache cached_extent;
/* Spinlock for protecting extent cache */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册