Whamcloud - gitweb
libext2fs: make sure the system.data xattr gets created
authorEric Biggers <ebiggers@google.com>
Sat, 3 Mar 2018 00:59:15 +0000 (16:59 -0800)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 3 Mar 2018 20:26:36 +0000 (15:26 -0500)
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>
lib/ext2fs/inline_data.c
tests/f_create_symlinks/expect
tests/f_create_symlinks/script

index e3ae2e8..21e8202 100644 (file)
@@ -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);
 }
 
index c21729a..71f0c62 100644 (file)
@@ -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
index 73f95a6..1a97216 100644 (file)
@@ -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