ext4: Verify fast symlink length
Jan Kara
reviewerPATCH 1/1 ext4: Verify fast symlink length
Verify fast symlink length stored in inode->i_size matches the string stored in the inode to avoid surprises from corrupted filesystems.
--- fs/ext4/inode.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
fs/ext4/inode.c +10 -2
@@ -5007,8 +5007,16 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -nd_terminate_link (ei->i_data, inode->i_size, -sizeof (ei->i_data) -1 ); +if (inode->i_size ==0 || + inode->i_size >=sizeof (ei->i_data) || +strnlen ((char *)ei->i_data, inode->i_size +1 ) != + inode->i_size) { +ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + }inode_set_cached_link (inode, (char *)ei->i_data, inode->i_size); }else {
Signature · 1 line
2.43.0
Theodore Ts'o
maintainerQuoted 24 lines · Jan Kara
Verify fast symlink length stored in
inode->i_sizematches the string stored in the inode to avoid surprises from corrupted filesystems.Reported-by [email protected]Tested-by [email protected]Fixes bae80473f7b0 ("ext4: use inode_set_cached_link()")Suggested-by "Darrick J. Wong" <[email protected]>Signed-off-by Jan Kara <[email protected]>--- fs/ext4/inode.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)fs/ext4/inode.c +2
-2@@ -5007,8 +5007,16 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -nd_terminate_link (ei->i_data, inode->i_size, -sizeof (ei->i_data) -1 ); + if (inode->i_size == 0 || + inode->i_size >= sizeof(ei->i_data) ||
fs/ext4/inode.c struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, · line 5021
Quoted 10 lines
fs/ext4/inode.c +8
-0+ strnlen((char *)ei->i_data, inode->i_size + 1) != + inode->i_size) { +ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + }inode_set_cached_link (inode, (char *)ei->i_data, inode->i_size);
I don't think this will do the right thing if the fast symlink is encrypted. See ext4_encrypted_get_link() in fs/ext4/symlink.c in the kernel sources, and also look at how e2fsck_pass1_check_symlink() handles checking the size of an encrypted, fast symlink.
Thanks,
- Ted
Quoted 33 lines · Theodore Ts'o
Quoted 32 lines · Jan Kara
Verify fast symlink length stored in
inode->i_sizematches the string stored in the inode to avoid surprises from corrupted filesystems.Reported-by [email protected]Tested-by [email protected]Fixes bae80473f7b0 ("ext4: use inode_set_cached_link()")Suggested-by "Darrick J. Wong" <[email protected]>Signed-off-by Jan Kara <[email protected]>--- fs/ext4/inode.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)fs/ext4/inode.c +10
-2@@ -5007,8 +5007,16 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -nd_terminate_link (ei->i_data, inode->i_size, -sizeof (ei->i_data) -1 ); +if (inode->i_size ==0 || + inode->i_size >=sizeof (ei->i_data) || +strnlen ((char *)ei->i_data, inode->i_size +1 ) != + inode->i_size) { +ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + }
Quoted 9 lines
fs/ext4/inode.c struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, · line 5021
Quoted 2 lines
fs/ext4/inode.c +0
-0inode_set_cached_link (inode, (char *)ei->i_data, inode->i_size);I don't think this will do the right thing if the fast symlink is encrypted. See
ext4_encrypted_get_link()infs/ext4/symlink.cin the kernel sources, and also look at howe2fsck_pass1_check_symlink()handles checking the size of an encrypted, fast symlink.
Encrypted symlinks are handled separately just a couple lines above.
- Eric
Jan Kara
reviewerQuoted 21 lines · Theodore Ts'o
Quoted 20 lines · Jan Kara
fs/ext4/inode.c +10
-2@@ -5007,8 +5007,16 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -nd_terminate_link (ei->i_data, inode->i_size, -sizeof (ei->i_data) -1 ); +if (inode->i_size ==0 || + inode->i_size >=sizeof (ei->i_data) || +strnlen ((char *)ei->i_data, inode->i_size +1 ) != + inode->i_size) { +ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + }
Quoted 8 lines
fs/ext4/inode.c struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, · line 5021
Quoted 2 lines
fs/ext4/inode.c +0
-0inode_set_cached_link (inode, (char *)ei->i_data, inode->i_size);I don't think this will do the right thing if the fast symlink is encrypted. See
ext4_encrypted_get_link()infs/ext4/symlink.cin the kernel sources, and also look at howe2fsck_pass1_check_symlink()handles checking the size of an encrypted, fast symlink.
Thanks for having a look but as Eric writes, there's:
if (IS_ENCRYPTED(inode)) {
inode->i_op = &ext4_encrypted_symlink_inode_operations;
} else if (ext4_inode_is_fast_symlink(inode)) {just above the context of this hunk so I *think* encrypted symlinks cannot get into this code?
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Quoted 17 lines · Jan Kara
Verify fast symlink length stored in
inode->i_sizematches the string stored in the inode to avoid surprises from corrupted filesystems.Reported-by [email protected]Tested-by [email protected]Fixes bae80473f7b0 ("ext4: use inode_set_cached_link()")Suggested-by "Darrick J. Wong" <[email protected]>Signed-off-by Jan Kara <[email protected]>--- fs/ext4/inode.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)fs/ext4/inode.c +0
-0
fs/ext4/inode.c struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, · line 5013
Quoted 9 lines
fs/ext4/inode.c +4
-2@@ -5007,8 +5007,16 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -nd_terminate_link (ei->i_data, inode->i_size, -sizeof (ei->i_data) -1 ); +if (inode->i_size ==0 || + inode->i_size >=sizeof (ei->i_data) || +strnlen ((char *)ei->i_data, inode->i_size +1 ) != + inode->i_size) {
Oooh, a validation I overlooked! :D
--D
Quoted 12 lines
fs/ext4/inode.c +6
-0+ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + }inode_set_cached_link (inode, (char *)ei->i_data, inode->i_size); }else {Signature · 1 line
2.43.0
Quoted 9 lines · Jan Kara
Verify fast symlink length stored in
inode->i_sizematches the string stored in the inode to avoid surprises from corrupted filesystems.Reported-by [email protected]Tested-by [email protected]Fixes bae80473f7b0 ("ext4: use inode_set_cached_link()")Suggested-by "Darrick J. Wong" <[email protected]>Signed-off-by Jan Kara <[email protected]>---
Looks good to me, thanks for the patch!
Quoted 26 lines
fs/ext4/inode.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)fs/ext4/inode.c +10
-2@@ -5007,8 +5007,16 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -nd_terminate_link (ei->i_data, inode->i_size, -sizeof (ei->i_data) -1 ); +if (inode->i_size ==0 || + inode->i_size >=sizeof (ei->i_data) || +strnlen ((char *)ei->i_data, inode->i_size +1 ) != + inode->i_size) { +ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + }inode_set_cached_link (inode, (char *)ei->i_data, inode->i_size); }else {
Quoted 4 lines · Jan Kara
Verify fast symlink length stored in
inode->i_sizematches the string stored in the inode to avoid surprises from corrupted filesystems.
Applied, thanks!
[1/1] ext4: Verify fast symlink length
commit: 5f920d5d60839f7cbbb1ed50eac68d8bc0a73a7c
Best regards,
Signature · 1 line
Theodore Ts'o <[email protected]>