diff options
author | Eric Biggers <ebiggers@google.com> | 2018-03-02 16:59:15 -0800 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2018-03-03 15:26:36 -0500 |
commit | 198a2d0a77d1c33790855c7827da6f1520db103e (patch) | |
tree | 8784d40f72309be6c119fbb25c4e307dd4849755 | |
parent | c88970f2258459e84f3fbed3b80653b3e8746dfb (diff) | |
download | e2fsprogs-198a2d0a77d1c33790855c7827da6f1520db103e.tar.gz |
libext2fs: make sure the system.data xattr gets created
Both the kernel and e2fsck expect that if an inode has inline data, then
it contains a "system.data" xattr -- even if i_size <= 60 so the data
fits entirely in i_block.
But if a symlink of exactly 60 bytes (not counting a NUL terminator) was
created using ext2fs_symlink() and the inline data feature was enabled,
then the symlink inode ended up with inline data but without a
system.data xattr. This is possible because "fast" symlinks store a NUL
terminator but inline data symlinks do not. So 60 bytes is too long for
a real fast symlink, but still short enough to fit the entire target in
i_block as a "slow" symlink using inline data.
Some places use ext2fs_inline_data_init() to ensure the system.data
xattr is created, but the symlink path does not.
Fix this by making ext2fs_inline_data_set() set system.data to an empty
string when i_size <= 60.
Fixes: 54e880b870f7 ("libext2fs: handle inline data in read/write function")
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r-- | lib/ext2fs/inline_data.c | 50 | ||||
-rw-r--r-- | tests/f_create_symlinks/expect | 20 | ||||
-rw-r--r-- | tests/f_create_symlinks/script | 4 |
3 files changed, 43 insertions, 31 deletions
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c index e3ae2e84e..21e82027d 100644 --- a/lib/ext2fs/inline_data.c +++ b/lib/ext2fs/inline_data.c @@ -545,7 +545,10 @@ errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, void *buf, size_t size) { struct ext2_inode inode_buf; - struct ext2_inline_data data; + struct ext2_inline_data data = { + .fs = fs, + .ino = ino, + }; errcode_t retval; size_t free_ea_size, existing_size, free_inode_size; @@ -558,37 +561,34 @@ errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, if (size <= EXT4_MIN_INLINE_DATA_SIZE) { memcpy((void *)inode->i_block, buf, size); - return ext2fs_write_inode(fs, ino, inode); - } - - retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size); - if (retval) - return retval; + } else { + retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size); + if (retval) + return retval; - retval = ext2fs_inline_data_size(fs, ino, &existing_size); - if (retval) - return retval; + retval = ext2fs_inline_data_size(fs, ino, &existing_size); + if (retval) + return retval; - if (existing_size < EXT4_MIN_INLINE_DATA_SIZE) - free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - existing_size; - else - free_inode_size = 0; + if (existing_size < EXT4_MIN_INLINE_DATA_SIZE) { + free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - + existing_size; + } else { + free_inode_size = 0; + } - if (size != existing_size && - size > existing_size + free_ea_size + free_inode_size) - return EXT2_ET_INLINE_DATA_NO_SPACE; + if (size != existing_size && + size > existing_size + free_ea_size + free_inode_size) + return EXT2_ET_INLINE_DATA_NO_SPACE; - memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE); + memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE); + if (size > EXT4_MIN_INLINE_DATA_SIZE) + data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; + data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE; + } retval = ext2fs_write_inode(fs, ino, inode); if (retval) return retval; - data.fs = fs; - data.ino = ino; - if (size > EXT4_MIN_INLINE_DATA_SIZE) - data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; - else - data.ea_size = 0; - data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE; return ext2fs_inline_data_ea_set(&data); } diff --git a/tests/f_create_symlinks/expect b/tests/f_create_symlinks/expect index c21729a80..71f0c6299 100644 --- a/tests/f_create_symlinks/expect +++ b/tests/f_create_symlinks/expect @@ -7,6 +7,7 @@ Pass 5: Checking group summary information test_filesys: 11/128 files (0.0% non-contiguous), 441/1024 blocks Exit status is 0 debugfs -R "symlink /l_30 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img +debugfs -R "symlink /l_60 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img debugfs -R "symlink /l_70 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img debugfs -R "symlink /l_500 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img debugfs -R "symlink /l_1023 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img @@ -25,9 +26,20 @@ Links: 1 Blockcount: 0 Fragment: Address: 0 Number: 0 Size: 0 Size of extra inode fields: 32 Fast link dest: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -debugfs -R "stat /l_70" test.img +debugfs -R "stat /l_60" test.img Inode: 13 Type: symlink Mode: 0777 Flags: 0x10000000 Generation: 0 Version: 0x00000000:00000000 +User: 0 Group: 0 Project: 0 Size: 60 +File ACL: 0 Directory ACL: 0 +Links: 1 Blockcount: 0 +Fragment: Address: 0 Number: 0 Size: 0 +Size of extra inode fields: 32 +Extended attributes: + system.data (0) +Fast link dest: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +debugfs -R "stat /l_70" test.img +Inode: 14 Type: symlink Mode: 0777 Flags: 0x10000000 +Generation: 0 Version: 0x00000000:00000000 User: 0 Group: 0 Project: 0 Size: 70 File ACL: 0 Directory ACL: 0 Links: 1 Blockcount: 0 @@ -37,7 +49,7 @@ Extended attributes: system.data (10) Fast link dest: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" debugfs -R "stat /l_500" test.img -Inode: 14 Type: symlink Mode: 0777 Flags: 0x80000 +Inode: 15 Type: symlink Mode: 0777 Flags: 0x80000 Generation: 0 Version: 0x00000000:00000000 User: 0 Group: 0 Project: 0 Size: 500 File ACL: 0 Directory ACL: 0 @@ -47,7 +59,7 @@ Size of extra inode fields: 32 EXTENTS: (0):153 debugfs -R "stat /l_1023" test.img -Inode: 15 Type: symlink Mode: 0777 Flags: 0x80000 +Inode: 16 Type: symlink Mode: 0777 Flags: 0x80000 Generation: 0 Version: 0x00000000:00000000 User: 0 Group: 0 Project: 0 Size: 1023 File ACL: 0 Directory ACL: 0 @@ -65,5 +77,5 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -test_filesys: 15/128 files (0.0% non-contiguous), 443/1024 blocks +test_filesys: 16/128 files (0.0% non-contiguous), 443/1024 blocks Exit status is 0 diff --git a/tests/f_create_symlinks/script b/tests/f_create_symlinks/script index 73f95a6e8..1a97216aa 100644 --- a/tests/f_create_symlinks/script +++ b/tests/f_create_symlinks/script @@ -23,13 +23,13 @@ echo Exit status is $status >> $OUT.new sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT rm -f $OUT.new -for i in 30 70 500 1023 1024 1500; do +for i in 30 60 70 500 1023 1024 1500; do echo "debugfs -R \"symlink /l_$i $(perl -e "print 'x' x $i;")\" test.img" >> $OUT $DEBUGFS -w -R "symlink /l_$i $(perl -e "print 'x' x $i;")" $TMPFILE \ 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT done -for i in 30 70 500 1023 1024 1500; do +for i in 30 60 70 500 1023 1024 1500; do echo "debugfs -R \"stat /l_$i\" test.img" >> $OUT $DEBUGFS -R "stat /l_$i" $TMPFILE 2>&1 | \ sed -f $cmd_dir/filter.sed | grep -v "time: " >> $OUT |