lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri,  2 Mar 2018 16:59:15 -0800
From:   Eric Biggers <ebiggers3@...il.com>
To:     linux-ext4@...r.kernel.org
Cc:     Eric Biggers <ebiggers@...gle.com>
Subject: [PATCH 02/10] libext2fs: make sure the system.data xattr gets created

From: Eric Biggers <ebiggers@...gle.com>

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@...gle.com>
---
 lib/ext2fs/inline_data.c       | 50 +++++++++++++++++-----------------
 tests/f_create_symlinks/expect | 20 +++++++++++---
 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 7215c517..0cf80b9a 100644
--- a/lib/ext2fs/inline_data.c
+++ b/lib/ext2fs/inline_data.c
@@ -535,7 +535,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;
 
@@ -548,37 +551,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 1794e0a7..3033f8aa 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
+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
 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
@@ -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
@@ -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 73f95a6e..1a97216a 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
-- 
2.16.2.395.g2e18187dfd-goog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ