summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven J. Magnani <steve.magnani@digidescorp.com>2019-08-14 08:50:02 -0400
committerJan Kara <jack@suse.cz>2019-08-26 05:17:55 -0400
commitab9a3a737284b3d9e1d2ba43a0ef31b3ef2e2417 (patch)
treeda1ecd5168487841b078727bfcb357edc1172e15
parent56db1991690f076c2a7e3b2a226629cd10901690 (diff)
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.com Signed-off-by: Steven J. Magnani <steve@digidescorp.com> Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/udf/inode.c24
-rw-r--r--fs/udf/super.c2
-rw-r--r--fs/udf/udf_i.h5
3 files changed, 29 insertions, 2 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 9bb18311a22f..54eee39f2698 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1485,6 +1485,8 @@ reread:
1485 iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); 1485 iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
1486 iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs); 1486 iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs);
1487 iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint); 1487 iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint);
1488 iinfo->i_streamdir = 0;
1489 iinfo->i_lenStreams = 0;
1488 } else { 1490 } else {
1489 inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << 1491 inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
1490 (inode->i_sb->s_blocksize_bits - 9); 1492 (inode->i_sb->s_blocksize_bits - 9);
@@ -1498,6 +1500,16 @@ reread:
1498 iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); 1500 iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
1499 iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs); 1501 iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
1500 iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint); 1502 iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
1503
1504 /* Named streams */
1505 iinfo->i_streamdir = (efe->streamDirectoryICB.extLength != 0);
1506 iinfo->i_locStreamdir =
1507 lelb_to_cpu(efe->streamDirectoryICB.extLocation);
1508 iinfo->i_lenStreams = le64_to_cpu(efe->objectSize);
1509 if (iinfo->i_lenStreams >= inode->i_size)
1510 iinfo->i_lenStreams -= inode->i_size;
1511 else
1512 iinfo->i_lenStreams = 0;
1501 } 1513 }
1502 inode->i_generation = iinfo->i_unique; 1514 inode->i_generation = iinfo->i_unique;
1503 1515
@@ -1760,9 +1772,19 @@ static int udf_update_inode(struct inode *inode, int do_sync)
1760 iinfo->i_ext.i_data, 1772 iinfo->i_ext.i_data,
1761 inode->i_sb->s_blocksize - 1773 inode->i_sb->s_blocksize -
1762 sizeof(struct extendedFileEntry)); 1774 sizeof(struct extendedFileEntry));
1763 efe->objectSize = cpu_to_le64(inode->i_size); 1775 efe->objectSize =
1776 cpu_to_le64(inode->i_size + iinfo->i_lenStreams);
1764 efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded); 1777 efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
1765 1778
1779 if (iinfo->i_streamdir) {
1780 struct long_ad *icb_lad = &efe->streamDirectoryICB;
1781
1782 icb_lad->extLocation =
1783 cpu_to_lelb(iinfo->i_locStreamdir);
1784 icb_lad->extLength =
1785 cpu_to_le32(inode->i_sb->s_blocksize);
1786 }
1787
1766 udf_adjust_time(iinfo, inode->i_atime); 1788 udf_adjust_time(iinfo, inode->i_atime);
1767 udf_adjust_time(iinfo, inode->i_mtime); 1789 udf_adjust_time(iinfo, inode->i_mtime);
1768 udf_adjust_time(iinfo, inode->i_ctime); 1790 udf_adjust_time(iinfo, inode->i_ctime);
diff --git a/fs/udf/super.c b/fs/udf/super.c
index f34e06b4d8fa..00e2d7190b52 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -151,9 +151,11 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
151 151
152 ei->i_unique = 0; 152 ei->i_unique = 0;
153 ei->i_lenExtents = 0; 153 ei->i_lenExtents = 0;
154 ei->i_lenStreams = 0;
154 ei->i_next_alloc_block = 0; 155 ei->i_next_alloc_block = 0;
155 ei->i_next_alloc_goal = 0; 156 ei->i_next_alloc_goal = 0;
156 ei->i_strat4096 = 0; 157 ei->i_strat4096 = 0;
158 ei->i_streamdir = 0;
157 init_rwsem(&ei->i_data_sem); 159 init_rwsem(&ei->i_data_sem);
158 ei->cached_extent.lstart = -1; 160 ei->cached_extent.lstart = -1;
159 spin_lock_init(&ei->i_extent_cache_lock); 161 spin_lock_init(&ei->i_extent_cache_lock);
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h
index 2ef0e212f08a..00d773d1b7cf 100644
--- a/fs/udf/udf_i.h
+++ b/fs/udf/udf_i.h
@@ -42,12 +42,15 @@ struct udf_inode_info {
42 unsigned i_efe : 1; /* extendedFileEntry */ 42 unsigned i_efe : 1; /* extendedFileEntry */
43 unsigned i_use : 1; /* unallocSpaceEntry */ 43 unsigned i_use : 1; /* unallocSpaceEntry */
44 unsigned i_strat4096 : 1; 44 unsigned i_strat4096 : 1;
45 unsigned reserved : 26; 45 unsigned i_streamdir : 1;
46 unsigned reserved : 25;
46 union { 47 union {
47 struct short_ad *i_sad; 48 struct short_ad *i_sad;
48 struct long_ad *i_lad; 49 struct long_ad *i_lad;
49 __u8 *i_data; 50 __u8 *i_data;
50 } i_ext; 51 } i_ext;
52 struct kernel_lb_addr i_locStreamdir;
53 __u64 i_lenStreams;
51 struct rw_semaphore i_data_sem; 54 struct rw_semaphore i_data_sem;
52 struct udf_ext_cache cached_extent; 55 struct udf_ext_cache cached_extent;
53 /* Spinlock for protecting extent cache */ 56 /* Spinlock for protecting extent cache */