From: Chao Yu <yuch...@huawei.com>

[ Upstream commit 2c28aba8b2e2a51749fa66e01b68e1cd5b53e022 ]

With below testcase, we will fail to find existed xattr entry:

1. mkfs.f2fs -O extra_attr -O flexible_inline_xattr /dev/zram0
2. mount -t f2fs -o inline_xattr_size=1 /dev/zram0 /mnt/f2fs/
3. touch /mnt/f2fs/file
4. setfattr -n "user.name" -v 0 /mnt/f2fs/file
5. getfattr -n "user.name" /mnt/f2fs/file

/mnt/f2fs/file: user.name: No such attribute

The reason is for inode which has very small inline xattr size,
__find_inline_xattr() will fail to traverse any entry due to first
entry may not be loaded from xattr node yet, later, we may skip to
check entire xattr datas in __find_xattr(), result in such wrong
condition.

This patch adds condition to check such case to avoid this issue.

Signed-off-by: Chao Yu <yuch...@huawei.com>
Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 fs/f2fs/xattr.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 18d5ffbc5e8c..73b92985198b 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -224,11 +224,11 @@ static struct f2fs_xattr_entry 
*__find_inline_xattr(struct inode *inode,
 {
        struct f2fs_xattr_entry *entry;
        unsigned int inline_size = inline_xattr_size(inode);
+       void *max_addr = base_addr + inline_size;
 
        list_for_each_xattr(entry, base_addr) {
-               if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
-                       (void *)XATTR_NEXT_ENTRY(entry) + sizeof(__u32) >
-                       base_addr + inline_size) {
+               if ((void *)entry + sizeof(__u32) > max_addr ||
+                       (void *)XATTR_NEXT_ENTRY(entry) > max_addr) {
                        *last_addr = entry;
                        return NULL;
                }
@@ -239,6 +239,13 @@ static struct f2fs_xattr_entry *__find_inline_xattr(struct 
inode *inode,
                if (!memcmp(entry->e_name, name, len))
                        break;
        }
+
+       /* inline xattr header or entry across max inline xattr size */
+       if (IS_XATTR_LAST_ENTRY(entry) &&
+               (void *)entry + sizeof(__u32) > max_addr) {
+               *last_addr = entry;
+               return NULL;
+       }
        return entry;
 }
 
-- 
2.19.1

Reply via email to