]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
udf: reduce leakage of blocks related to named streams
authorSteven J. Magnani <steve.magnani@digidescorp.com>
Wed, 14 Aug 2019 12:50:02 +0000 (07:50 -0500)
committerJan Kara <jack@suse.cz>
Mon, 26 Aug 2019 09:17:55 +0000 (11:17 +0200)
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.com
Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/udf/inode.c
fs/udf/super.c
fs/udf/udf_i.h

index 9bb18311a22fc1a60bb642c8b68891c2e5a05949..54eee39f26989e981f0edcc0e60bd7a3943efdb3 100644 (file)
@@ -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);
index f34e06b4d8fac0ee4614682694681aa6c1ed892a..00e2d7190b522685048214999a1c37b865cbe688 100644 (file)
@@ -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);
index 2ef0e212f08a3d55ce25b8c6e34843a03fa5f88c..00d773d1b7cf0c8704deda6b49b1dcf5919769ae 100644 (file)
@@ -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 */