[f2fs-dev] [PATCH] Introduce sg_read_buffer

2022-10-26 Thread Randall Huang via Linux-f2fs-devel
Support UFS error history dumping

Signed-off-by: Randall Huang 
---
 tools/sg_write_buffer/Android.bp   |  19 ++
 tools/sg_write_buffer/sg_read_buffer.c | 334 +
 2 files changed, 353 insertions(+)
 create mode 100644 tools/sg_write_buffer/sg_read_buffer.c

diff --git a/tools/sg_write_buffer/Android.bp b/tools/sg_write_buffer/Android.bp
index 5222a59..f488aea 100644
--- a/tools/sg_write_buffer/Android.bp
+++ b/tools/sg_write_buffer/Android.bp
@@ -25,3 +25,22 @@ cc_binary {
 "sg_pt_linux_nvme.c",
 ],
 }
+
+cc_binary {
+name: "sg_read_buffer",
+defaults: [ "sg3-utils-defaults" ],
+srcs: [
+"sg_read_buffer.c",
+"sg_cmds_basic.c",
+"sg_cmds_basic2.c",
+"sg_cmds_extra.c",
+"sg_cmds_mmc.c",
+"sg_io_linux.c",
+"sg_lib.c",
+"sg_lib_data.c",
+"sg_pt_common.c",
+"sg_pt_linux.c",
+"sg_pt_linux_nvme.c",
+],
+system_ext_specific: true,
+}
diff --git a/tools/sg_write_buffer/sg_read_buffer.c 
b/tools/sg_write_buffer/sg_read_buffer.c
new file mode 100644
index 000..1924c7d
--- /dev/null
+++ b/tools/sg_write_buffer/sg_read_buffer.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2006-2013 Luben Tuikov and Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+#include "sg_pt.h"  /* needed for scsi_pt_win32_direct() */
+
+/*
+ * This utility issues the SCSI READ BUFFER command to the given device.
+ */
+
+static const char * version_str = "1.09 20130507";
+
+
+static struct option long_options[] = {
+{"help", 0, 0, 'h'},
+{"hex", 0, 0, 'H'},
+{"id", 1, 0, 'i'},
+{"length", 1, 0, 'l'},
+{"mode", 1, 0, 'm'},
+{"offset", 1, 0, 'o'},
+{"raw", 0, 0, 'r'},
+{"verbose", 0, 0, 'v'},
+{"version", 0, 0, 'V'},
+{0, 0, 0, 0},
+};
+
+
+static void
+usage()
+{
+fprintf(stderr, "Usage: "
+  "sg_read_buffer [--help] [--hex] [--id=ID] [--length=LEN] "
+  "[--mode=MO]\n"
+  "  [--offset=OFF] [--raw] [--verbose] "
+  "[--version] DEVICE\n"
+  "  where:\n"
+  "--help|-h   print out usage message\n"
+  "--hex|-Hprint output in hex\n"
+  "--id=ID|-i ID   buffer identifier (0 (default) to 255)\n"
+  "--length=LEN|-l LENlength in bytes to read (def: 4)\n"
+  "--mode=MO|-m MO read buffer mode, MO is number or "
+  "acronym (def: 0)\n"
+  "--off=OFF|-o OFFbuffer offset (unit: bytes, def: 0)\n"
+  "--raw|-routput response to stdout\n"
+  "--verbose|-vincrease verbosity\n"
+  "--version|-Vprint version string and exit\n\n"
+  "  Numbers given in options are decimal unless they have a "
+  "hex indicator\n"
+  "Performs a SCSI READ BUFFER command\n"
+  );
+
+}
+
+#define MODE_HEADER_DATA0
+#define MODE_VENDOR 1
+#define MODE_DATA   2
+#define MODE_DESCRIPTOR 3
+#define MODE_ECHO_BUFFER0x0A
+#define MODE_ECHO_BDESC 0x0B
+#define MODE_EN_EX_ECHO 0x1A
+#define MODE_ERR_HISTORY0x1C
+
+static struct mode_s {
+const char *mode_string;
+int   mode;
+const char *comment;
+} modes[] = {
+{ "hd", MODE_HEADER_DATA, "combined header and data"},
+{ "vendor", MODE_VENDOR,"vendor specific"},
+{ "data",   MODE_DATA,  "data"},
+{ "desc",   MODE_DESCRIPTOR, "descriptor"},
+{ "echo",   MODE_ECHO_BUFFER, "read data from echo buffer "
+  "(spc-2)"},
+{ "echo_desc",  MODE_ECHO_BDESC, "echo buffer descriptor (spc-2)"},
+{ "en_ex",  MODE_EN_EX_ECHO,
+  "enable expander communications protocol and echo buffer (spc-3)"},
+{ "err_hist",   MODE_ERR_HISTORY, "error history (spc-4)"},
+};
+
+#define NUM_MODES   ((int)(sizeof(modes)/sizeof(modes[0])))
+
+static void
+print_modes(void)
+{
+int k;
+
+fprintf(stderr, "The modes parameter argument can be numeric "
+"(hex or decimal)\nor symbolic:\n");
+for (k = 0; k < NUM_MODES; k++) {
+fprintf(stderr, " %2d (0x%02x)  %-16s%s\n", modes[k].mode,
+modes[k].mode, modes[k].mode_string, modes[k].comment);
+}
+}
+
+static void
+dStrRaw(const char* str, int len)
+{
+int k;
+
+for (k = 0 ; k < len; ++k)
+printf("%c", str[k]);
+}
+
+int
+main(int argc, char * argv[])
+{
+int sg_fd, res, c, len, k;
+int do_help = 0;
+int do_hex = 0;
+int rb_id = 0;

[f2fs-dev] [PATCH] f2fs-tools: introduce sg_read_buffer

2022-10-26 Thread Randall Huang via Linux-f2fs-devel
Support UFS error history dumping

Signed-off-by: Randall Huang 
---
 tools/sg_write_buffer/Android.bp   |  19 ++
 tools/sg_write_buffer/sg_read_buffer.c | 334 +
 2 files changed, 353 insertions(+)
 create mode 100644 tools/sg_write_buffer/sg_read_buffer.c

diff --git a/tools/sg_write_buffer/Android.bp b/tools/sg_write_buffer/Android.bp
index 5222a59..f488aea 100644
--- a/tools/sg_write_buffer/Android.bp
+++ b/tools/sg_write_buffer/Android.bp
@@ -25,3 +25,22 @@ cc_binary {
 "sg_pt_linux_nvme.c",
 ],
 }
+
+cc_binary {
+name: "sg_read_buffer",
+defaults: [ "sg3-utils-defaults" ],
+srcs: [
+"sg_read_buffer.c",
+"sg_cmds_basic.c",
+"sg_cmds_basic2.c",
+"sg_cmds_extra.c",
+"sg_cmds_mmc.c",
+"sg_io_linux.c",
+"sg_lib.c",
+"sg_lib_data.c",
+"sg_pt_common.c",
+"sg_pt_linux.c",
+"sg_pt_linux_nvme.c",
+],
+system_ext_specific: true,
+}
diff --git a/tools/sg_write_buffer/sg_read_buffer.c 
b/tools/sg_write_buffer/sg_read_buffer.c
new file mode 100644
index 000..1924c7d
--- /dev/null
+++ b/tools/sg_write_buffer/sg_read_buffer.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2006-2013 Luben Tuikov and Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+#include "sg_pt.h"  /* needed for scsi_pt_win32_direct() */
+
+/*
+ * This utility issues the SCSI READ BUFFER command to the given device.
+ */
+
+static const char * version_str = "1.09 20130507";
+
+
+static struct option long_options[] = {
+{"help", 0, 0, 'h'},
+{"hex", 0, 0, 'H'},
+{"id", 1, 0, 'i'},
+{"length", 1, 0, 'l'},
+{"mode", 1, 0, 'm'},
+{"offset", 1, 0, 'o'},
+{"raw", 0, 0, 'r'},
+{"verbose", 0, 0, 'v'},
+{"version", 0, 0, 'V'},
+{0, 0, 0, 0},
+};
+
+
+static void
+usage()
+{
+fprintf(stderr, "Usage: "
+  "sg_read_buffer [--help] [--hex] [--id=ID] [--length=LEN] "
+  "[--mode=MO]\n"
+  "  [--offset=OFF] [--raw] [--verbose] "
+  "[--version] DEVICE\n"
+  "  where:\n"
+  "--help|-h   print out usage message\n"
+  "--hex|-Hprint output in hex\n"
+  "--id=ID|-i ID   buffer identifier (0 (default) to 255)\n"
+  "--length=LEN|-l LENlength in bytes to read (def: 4)\n"
+  "--mode=MO|-m MO read buffer mode, MO is number or "
+  "acronym (def: 0)\n"
+  "--off=OFF|-o OFFbuffer offset (unit: bytes, def: 0)\n"
+  "--raw|-routput response to stdout\n"
+  "--verbose|-vincrease verbosity\n"
+  "--version|-Vprint version string and exit\n\n"
+  "  Numbers given in options are decimal unless they have a "
+  "hex indicator\n"
+  "Performs a SCSI READ BUFFER command\n"
+  );
+
+}
+
+#define MODE_HEADER_DATA0
+#define MODE_VENDOR 1
+#define MODE_DATA   2
+#define MODE_DESCRIPTOR 3
+#define MODE_ECHO_BUFFER0x0A
+#define MODE_ECHO_BDESC 0x0B
+#define MODE_EN_EX_ECHO 0x1A
+#define MODE_ERR_HISTORY0x1C
+
+static struct mode_s {
+const char *mode_string;
+int   mode;
+const char *comment;
+} modes[] = {
+{ "hd", MODE_HEADER_DATA, "combined header and data"},
+{ "vendor", MODE_VENDOR,"vendor specific"},
+{ "data",   MODE_DATA,  "data"},
+{ "desc",   MODE_DESCRIPTOR, "descriptor"},
+{ "echo",   MODE_ECHO_BUFFER, "read data from echo buffer "
+  "(spc-2)"},
+{ "echo_desc",  MODE_ECHO_BDESC, "echo buffer descriptor (spc-2)"},
+{ "en_ex",  MODE_EN_EX_ECHO,
+  "enable expander communications protocol and echo buffer (spc-3)"},
+{ "err_hist",   MODE_ERR_HISTORY, "error history (spc-4)"},
+};
+
+#define NUM_MODES   ((int)(sizeof(modes)/sizeof(modes[0])))
+
+static void
+print_modes(void)
+{
+int k;
+
+fprintf(stderr, "The modes parameter argument can be numeric "
+"(hex or decimal)\nor symbolic:\n");
+for (k = 0; k < NUM_MODES; k++) {
+fprintf(stderr, " %2d (0x%02x)  %-16s%s\n", modes[k].mode,
+modes[k].mode, modes[k].mode_string, modes[k].comment);
+}
+}
+
+static void
+dStrRaw(const char* str, int len)
+{
+int k;
+
+for (k = 0 ; k < len; ++k)
+printf("%c", str[k]);
+}
+
+int
+main(int argc, char * argv[])
+{
+int sg_fd, res, c, len, k;
+int do_help = 0;
+int do_hex = 0;
+int rb_id = 0;

[f2fs-dev] [PATCH] f2fs: fix to avoid accessing xattr across the boundary

2019-04-08 Thread Randall Huang via Linux-f2fs-devel
When we traverse xattr entries via __find_xattr(),
if the raw filesystem content is faked or any hardware failure occurs,
out-of-bound error can be detected by KASAN.
Fix the issue by introducing boundary check.

[   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
f2fs_getxattr+0x518/0x68c
[   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
[   38.402935] c7   1827 Call trace:
[   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
[   38.402966] c7   1827 [] show_stack+0x20/0x2c
[   38.402981] c7   1827 [] dump_stack+0xfc/0x140
[   38.402995] c7   1827 [] 
print_address_description+0x80/0x2d8
[   38.403009] c7   1827 [] kasan_report_error+0x198/0x1fc
[   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
[   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
[   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
[   38.403066] c7   1827 [] f2fs_xattr_generic_get+0xb0/0xd0
[   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
[   38.403096] c7   1827 [] 
inode_doinit_with_dentry+0x360/0x938
[   38.403109] c7   1827 [] selinux_d_instantiate+0x2c/0x38
[   38.403123] c7   1827 [] security_d_instantiate+0x68/0x98
[   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
[   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
[   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
[   38.403177] c7   1827 [] walk_component+0x160/0x520
[   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
[   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
[   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
[   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
[   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38

Bug: 126558260

Signed-off-by: Randall Huang 
---
 fs/f2fs/xattr.c | 22 --
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 848a785abe25..0531c1e38275 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -202,12 +202,17 @@ static inline const struct xattr_handler 
*f2fs_xattr_handler(int index)
return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-   size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+   int base_addr_limit, int index,
+   size_t len, const char *name)
 {
struct f2fs_xattr_entry *entry;
+   void *max_addr = base_addr + ENTRY_SIZE(XATTR_ENTRY(base_addr)) +
+   base_addr_limit - 1;
 
list_for_each_xattr(entry, base_addr) {
+   if ((void *)entry + sizeof(__u32) > max_addr)
+   return NULL;
if (entry->e_name_index != index)
continue;
if (entry->e_name_len != len)
@@ -337,9 +342,9 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
else
cur_addr = txattr_addr;
 
-   *xe = __find_xattr(cur_addr, index, len, name);
+   *xe = __find_xattr(cur_addr, XATTR_PADDING_SIZE, index, len, name);
 check:
-   if (IS_XATTR_LAST_ENTRY(*xe)) {
+   if (!*xe || IS_XATTR_LAST_ENTRY(*xe)) {
err = -ENODATA;
goto out;
}
@@ -606,9 +611,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,
return error;
 
/* find entry with wanted name. */
-   here = __find_xattr(base_addr, index, len, name);
+   here = __find_xattr(base_addr, inline_xattr_size(inode) +
+   VALID_XATTR_BLOCK_SIZE + XATTR_PADDING_SIZE,
+   index, len, name);
 
-   found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
+   if (!here)
+   found = 0;
+   else
+   found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
 
if (found) {
if ((flags & XATTR_CREATE)) {
-- 
2.21.0.392.gf8f6787159e-goog



___
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [PATCH] f2fs: fix to avoid accessing xattr across the boundary

2019-04-09 Thread Randall Huang via Linux-f2fs-devel
On Mon, Apr 08, 2019 at 08:14:43PM +0800, Chao Yu wrote:
> On 2019/4/8 20:03, Chao Yu wrote:
> > Hi Randall,
> > 
> > On 2019/4/8 16:50, Randall Huang wrote:
> >> When we traverse xattr entries via __find_xattr(),
> >> if the raw filesystem content is faked or any hardware failure occurs,
> >> out-of-bound error can be detected by KASAN.
> >> Fix the issue by introducing boundary check.
> >>
> >> [   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
> >> f2fs_getxattr+0x518/0x68c
> >> [   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
> >> [   38.402935] c7   1827 Call trace:
> >> [   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
> >> [   38.402966] c7   1827 [] show_stack+0x20/0x2c
> >> [   38.402981] c7   1827 [] dump_stack+0xfc/0x140
> >> [   38.402995] c7   1827 [] 
> >> print_address_description+0x80/0x2d8
> >> [   38.403009] c7   1827 [] 
> >> kasan_report_error+0x198/0x1fc
> >> [   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
> >> [   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
> >> [   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
> >> [   38.403066] c7   1827 [] 
> >> f2fs_xattr_generic_get+0xb0/0xd0
> >> [   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
> >> [   38.403096] c7   1827 [] 
> >> inode_doinit_with_dentry+0x360/0x938
> >> [   38.403109] c7   1827 [] 
> >> selinux_d_instantiate+0x2c/0x38
> >> [   38.403123] c7   1827 [] 
> >> security_d_instantiate+0x68/0x98
> >> [   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
> >> [   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
> >> [   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
> >> [   38.403177] c7   1827 [] walk_component+0x160/0x520
> >> [   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
> >> [   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
> >> [   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
> >> [   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
> >> [   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38
> >>
> >> Bug: 126558260
> >>
> >> Signed-off-by: Randall Huang 
> >> ---
> >>  fs/f2fs/xattr.c | 22 --
> >>  1 file changed, 16 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
> >> index 848a785abe25..0531c1e38275 100644
> >> --- a/fs/f2fs/xattr.c
> >> +++ b/fs/f2fs/xattr.c
> >> @@ -202,12 +202,17 @@ static inline const struct xattr_handler 
> >> *f2fs_xattr_handler(int index)
> >>return handler;
> >>  }
> >>  
> >> -static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
> >> -  size_t len, const char *name)
> >> +static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
> >> +  int base_addr_limit, int index,
> > 
> > unsigned int max_size,
> > 
> >> +  size_t len, const char *name)
> >>  {
> >>struct f2fs_xattr_entry *entry;
> >> +  void *max_addr = base_addr + ENTRY_SIZE(XATTR_ENTRY(base_addr)) +
> >> +  base_addr_limit - 1;
> > 
> > If I'm not missing something, shouldn't it be?
> > 
> > void *max_addr = base_addr + max_size;
> > 
Hi Chao,
Let me show the buggy example of xattr entries.

Here is the buggy xattr entries.
The address 0x1201f24 - 0x1201fcb is correct content.
(Each entry occupies 4 + 9 + 10 + 1 bytes, 24 bytes)
Hacker append a faked entry at 0x1201fcc - 0x1201fe5
(entry length = 4 + 9 + 12 + 1 bytes)

01201f00  00 00 00 00 00 00 00 00  00 00 00 00 11 20 f5 f2  |. ..|
01201f10  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ||
01201f20  00 00 00 00 01 09 0a 00  61 74 74 72 6e 61 6d 65  |attrname|
01201f30  31 61 74 74 72 76 61 6c  75 65 31 00 01 09 0a 00  |1attrvalue1.|
01201f40  61 74 74 72 6e 61 6d 65  32 61 74 74 72 76 61 6c  |attrname2attrval|
01201f50  75 65 31 00 01 09 0a 00  61 74 74 72 6e 61 6d 65  |ue1.attrname|
01201f60  33 61 74 74 72 76 61 6c  75 65 31 00 01 09 0a 00  |3attrvalue1.|
01201f70  61 74 74 72 6e 61 6d 65  34 61 74 74 72 76 61 6c  |attrname4attrval|
01201f80  75 65 31 00 01 09 0a 00  61 74 74 72 6e 61 6d 65  |ue1.attrname|
01201f90  35 61 74 74 72 76 61 6c  75 65 31 00 01 09 0a 00  |5attrvalue1.|
01201fa0  61 74 74 72 6e 61 6d 65  36 61 74 74 72 76 61 6c  |attrname6attrval|
01201fb0  75 65 31 00 01 09 0a 00  61 74 74 72 6e 61 6d 65  |ue1.attrname|
01201fc0  37 61 74 74 72 76 61 6c  75 65 31 00 01 09 0c 00  |7attrvalue1.|
01201fd0  61 74 74 72 6e 61 6d 65  38 61 74 74 72 76 61 6c  |attrname8attrval|
01201fe0  75 65 31 31 31 00 00 00  07 00 00 00 07 00 00 00  |ue111...|

After lookup_all_xattrs() traveses all inline+xnid entries, the
base_addr becomes the starting pointer of the last xattr entry.

if (last_addr)
cur_addr = XATTR_HDR(last_addr) - 1;
else
cur_addr = txattr_addr;

For example,
before OOB error occurs, the lookup_all_xattrs() calls __find_xattr()
with base_addr = ffc05fe98228, max_size = 4 (= XATTR_PADDING_SIZE).

[f2fs-dev] [PATCH v3] f2fs: fix to avoid accessing xattr across the boundary

2019-04-09 Thread Randall Huang via Linux-f2fs-devel
When we traverse xattr entries via __find_xattr(),
if the raw filesystem content is faked or any hardware failure occurs,
out-of-bound error can be detected by KASAN.
Fix the issue by introducing boundary check.

[   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
f2fs_getxattr+0x518/0x68c
[   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
[   38.402935] c7   1827 Call trace:
[   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
[   38.402966] c7   1827 [] show_stack+0x20/0x2c
[   38.402981] c7   1827 [] dump_stack+0xfc/0x140
[   38.402995] c7   1827 [] 
print_address_description+0x80/0x2d8
[   38.403009] c7   1827 [] kasan_report_error+0x198/0x1fc
[   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
[   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
[   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
[   38.403066] c7   1827 [] f2fs_xattr_generic_get+0xb0/0xd0
[   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
[   38.403096] c7   1827 [] 
inode_doinit_with_dentry+0x360/0x938
[   38.403109] c7   1827 [] selinux_d_instantiate+0x2c/0x38
[   38.403123] c7   1827 [] security_d_instantiate+0x68/0x98
[   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
[   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
[   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
[   38.403177] c7   1827 [] walk_component+0x160/0x520
[   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
[   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
[   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
[   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
[   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38

Bug: 126558260

Signed-off-by: Randall Huang 
---
v2:
* return EFAULT if OOB error is detected

v3:
* fix typo in setxattr()
---
 fs/f2fs/xattr.c | 31 +++
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 848a785abe25..381f14b02a78 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -202,12 +202,17 @@ static inline const struct xattr_handler 
*f2fs_xattr_handler(int index)
return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-   size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+   unsigned int max_size, int index,
+   size_t len, const char *name)
 {
struct f2fs_xattr_entry *entry;
+   void *max_addr = base_addr + ENTRY_SIZE(XATTR_ENTRY(base_addr)) +
+   max_size - 1;
 
list_for_each_xattr(entry, base_addr) {
+   if ((void *)entry + sizeof(__u32) > max_addr)
+   return NULL;
if (entry->e_name_index != index)
continue;
if (entry->e_name_len != len)
@@ -301,6 +306,7 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
unsigned int inline_size = inline_xattr_size(inode);
+   unsigned int max_size = inline_size + size + XATTR_PADDING_SIZE;
int err = 0;
 
if (!size && !inline_size)
@@ -323,6 +329,7 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
*base_size = inline_size;
goto check;
}
+   max_size -= inline_size;
}
 
/* read from xattr node block */
@@ -330,6 +337,8 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
err = read_xattr_block(inode, txattr_addr);
if (err)
goto out;
+
+   max_size -= size;
}
 
if (last_addr)
@@ -337,7 +346,12 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
else
cur_addr = txattr_addr;
 
-   *xe = __find_xattr(cur_addr, index, len, name);
+   *xe = __find_xattr(cur_addr, max_size, index, len, name);
+   if (!*xe) {
+   err = -EFAULT;
+   goto out;
+   }
+
 check:
if (IS_XATTR_LAST_ENTRY(*xe)) {
err = -ENODATA;
@@ -585,6 +599,11 @@ static int __f2fs_setxattr(struct inode *inode, int index,
int found, newsize;
size_t len;
__u32 new_hsize;
+   nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+   unsigned int xattr_nid_size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
+   unsigned int inline_size = inline_xattr_size(inode);
+   unsigned int max_size = inline_size + xattr_nid_size +
+XATTR_PADDING_SIZE;
int error = 0;
 
if (name == NULL)
@@ -606,7 +625,11 @@ static int __f2fs_setxattr(struct inode *inode, int index,
return error;
 
/* find entry with wanted name. */
-   here = __find_xattr(base_a

[f2fs-dev] [PATCH v2] f2fs: fix to avoid accessing xattr across the boundary

2019-04-09 Thread Randall Huang via Linux-f2fs-devel
When we traverse xattr entries via __find_xattr(),
if the raw filesystem content is faked or any hardware failure occurs,
out-of-bound error can be detected by KASAN.
Fix the issue by introducing boundary check.

[   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
f2fs_getxattr+0x518/0x68c
[   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
[   38.402935] c7   1827 Call trace:
[   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
[   38.402966] c7   1827 [] show_stack+0x20/0x2c
[   38.402981] c7   1827 [] dump_stack+0xfc/0x140
[   38.402995] c7   1827 [] 
print_address_description+0x80/0x2d8
[   38.403009] c7   1827 [] kasan_report_error+0x198/0x1fc
[   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
[   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
[   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
[   38.403066] c7   1827 [] f2fs_xattr_generic_get+0xb0/0xd0
[   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
[   38.403096] c7   1827 [] 
inode_doinit_with_dentry+0x360/0x938
[   38.403109] c7   1827 [] selinux_d_instantiate+0x2c/0x38
[   38.403123] c7   1827 [] security_d_instantiate+0x68/0x98
[   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
[   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
[   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
[   38.403177] c7   1827 [] walk_component+0x160/0x520
[   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
[   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
[   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
[   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
[   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38

Bug: 126558260

Signed-off-by: Randall Huang 
---
v2:
* return EFAULT if OOB error is detected
---
 fs/f2fs/xattr.c | 30 ++
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 848a785abe25..f60e40d95bbf 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -202,12 +202,17 @@ static inline const struct xattr_handler 
*f2fs_xattr_handler(int index)
return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-   size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+   unsigned int max_size, int index,
+   size_t len, const char *name)
 {
struct f2fs_xattr_entry *entry;
+   void *max_addr = base_addr + ENTRY_SIZE(XATTR_ENTRY(base_addr)) +
+   max_size - 1;
 
list_for_each_xattr(entry, base_addr) {
+   if ((void *)entry + sizeof(__u32) > max_addr)
+   return NULL;
if (entry->e_name_index != index)
continue;
if (entry->e_name_len != len)
@@ -301,6 +306,7 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
unsigned int inline_size = inline_xattr_size(inode);
+   unsigned int max_size = inline_size + size + XATTR_PADDING_SIZE;
int err = 0;
 
if (!size && !inline_size)
@@ -323,6 +329,7 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
*base_size = inline_size;
goto check;
}
+   max_size -= inline_size;
}
 
/* read from xattr node block */
@@ -330,6 +337,8 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
err = read_xattr_block(inode, txattr_addr);
if (err)
goto out;
+
+   max_size -= size;
}
 
if (last_addr)
@@ -337,7 +346,12 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
else
cur_addr = txattr_addr;
 
-   *xe = __find_xattr(cur_addr, index, len, name);
+   *xe = __find_xattr(cur_addr, max_size, index, len, name);
+   if (!*xe) {
+   err = -EFAULT;
+   goto out;
+   }
+
 check:
if (IS_XATTR_LAST_ENTRY(*xe)) {
err = -ENODATA;
@@ -585,6 +599,10 @@ static int __f2fs_setxattr(struct inode *inode, int index,
int found, newsize;
size_t len;
__u32 new_hsize;
+   nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+   unsigned int xattr_nid_size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
+   unsigned int inline_size = inline_xattr_size(inode);
+   unsigned int max_size = inline_size + size + XATTR_PADDING_SIZE;
int error = 0;
 
if (name == NULL)
@@ -606,7 +624,11 @@ static int __f2fs_setxattr(struct inode *inode, int index,
return error;
 
/* find entry with wanted name. */
-   here = __find_xattr(base_addr, index, len, name);
+   here = __find_xattr(base_addr, max_size, i

[f2fs-dev] [PATCH v4] f2fs: fix to avoid accessing xattr across the boundary

2019-04-10 Thread Randall Huang via Linux-f2fs-devel
When we traverse xattr entries via __find_xattr(),
if the raw filesystem content is faked or any hardware failure occurs,
out-of-bound error can be detected by KASAN.
Fix the issue by introducing boundary check.

[   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
f2fs_getxattr+0x518/0x68c
[   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
[   38.402935] c7   1827 Call trace:
[   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
[   38.402966] c7   1827 [] show_stack+0x20/0x2c
[   38.402981] c7   1827 [] dump_stack+0xfc/0x140
[   38.402995] c7   1827 [] 
print_address_description+0x80/0x2d8
[   38.403009] c7   1827 [] kasan_report_error+0x198/0x1fc
[   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
[   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
[   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
[   38.403066] c7   1827 [] f2fs_xattr_generic_get+0xb0/0xd0
[   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
[   38.403096] c7   1827 [] 
inode_doinit_with_dentry+0x360/0x938
[   38.403109] c7   1827 [] selinux_d_instantiate+0x2c/0x38
[   38.403123] c7   1827 [] security_d_instantiate+0x68/0x98
[   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
[   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
[   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
[   38.403177] c7   1827 [] walk_component+0x160/0x520
[   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
[   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
[   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
[   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
[   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38

Bug: 126558260

Signed-off-by: Randall Huang 
---
v2:
* return EFAULT if OOB error is detected

v3:
* fix typo in setxattr()

v4:
* change boundry definition
---
 fs/f2fs/xattr.c | 34 +-
 1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 848a785abe25..a1cf53c727b2 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -202,12 +202,18 @@ static inline const struct xattr_handler 
*f2fs_xattr_handler(int index)
return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-   size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+   void *last_base_addr, int index,
+   size_t len, const char *name)
 {
struct f2fs_xattr_entry *entry;
 
list_for_each_xattr(entry, base_addr) {
+   if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
+   (void *)XATTR_NEXT_ENTRY(entry) +
+   sizeof(__u32) > last_base_addr)
+   return NULL;
+
if (entry->e_name_index != index)
continue;
if (entry->e_name_len != len)
@@ -298,6 +304,7 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
void **base_addr, int *base_size)
 {
void *cur_addr, *txattr_addr, *last_addr = NULL;
+   void *last_txattr_addr = NULL;
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
unsigned int inline_size = inline_xattr_size(inode);
@@ -311,6 +318,9 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
if (!txattr_addr)
return -ENOMEM;
 
+   last_txattr_addr = (void *)txattr_addr + inline_size + size +
+   XATTR_PADDING_SIZE - 1;
+
/* read from inline xattr */
if (inline_size) {
err = read_inline_xattr(inode, ipage, txattr_addr);
@@ -337,7 +347,11 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
else
cur_addr = txattr_addr;
 
-   *xe = __find_xattr(cur_addr, index, len, name);
+   *xe = __find_xattr(cur_addr, last_txattr_addr, index, len, name);
+   if (!*xe) {
+   err = -EFAULT;
+   goto out;
+   }
 check:
if (IS_XATTR_LAST_ENTRY(*xe)) {
err = -ENODATA;
@@ -581,10 +595,15 @@ static int __f2fs_setxattr(struct inode *inode, int index,
struct page *ipage, int flags)
 {
struct f2fs_xattr_entry *here, *last;
-   void *base_addr;
+   void *base_addr, *last_base_addr = NULL;
int found, newsize;
size_t len;
__u32 new_hsize;
+   nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+   unsigned int xattr_nid_size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
+   unsigned int inline_size = inline_xattr_size(inode);
+   unsigned int max_size = inline_size + xattr_nid_size +
+XATTR_PADDING_SIZE;
int error = 0;
 
if (name == NULL)
@@ -604,9 +623,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,

Re: [f2fs-dev] [PATCH v3] f2fs: fix to avoid accessing xattr across the boundary

2019-04-10 Thread Randall Huang via Linux-f2fs-devel
On Tue, Apr 09, 2019 at 06:22:55PM +0800, Chao Yu wrote:
> On 2019/4/9 16:53, Randall Huang wrote:
> > When we traverse xattr entries via __find_xattr(),
> > if the raw filesystem content is faked or any hardware failure occurs,
> > out-of-bound error can be detected by KASAN.
> > Fix the issue by introducing boundary check.
> > 
> > [   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
> > f2fs_getxattr+0x518/0x68c
> > [   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
> > [   38.402935] c7   1827 Call trace:
> > [   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
> > [   38.402966] c7   1827 [] show_stack+0x20/0x2c
> > [   38.402981] c7   1827 [] dump_stack+0xfc/0x140
> > [   38.402995] c7   1827 [] 
> > print_address_description+0x80/0x2d8
> > [   38.403009] c7   1827 [] kasan_report_error+0x198/0x1fc
> > [   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
> > [   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
> > [   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
> > [   38.403066] c7   1827 [] 
> > f2fs_xattr_generic_get+0xb0/0xd0
> > [   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
> > [   38.403096] c7   1827 [] 
> > inode_doinit_with_dentry+0x360/0x938
> > [   38.403109] c7   1827 [] 
> > selinux_d_instantiate+0x2c/0x38
> > [   38.403123] c7   1827 [] 
> > security_d_instantiate+0x68/0x98
> > [   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
> > [   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
> > [   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
> > [   38.403177] c7   1827 [] walk_component+0x160/0x520
> > [   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
> > [   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
> > [   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
> > [   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
> > [   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38
> > 
> > Bug: 126558260
> > 
> > Signed-off-by: Randall Huang 
> > ---
> > v2:
> > * return EFAULT if OOB error is detected
> > 
> > v3:
> > * fix typo in setxattr()
> > ---
> >  fs/f2fs/xattr.c | 31 +++
> >  1 file changed, 27 insertions(+), 4 deletions(-)
> > 
> > diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
> > index 848a785abe25..381f14b02a78 100644
> > --- a/fs/f2fs/xattr.c
> > +++ b/fs/f2fs/xattr.c
> > @@ -202,12 +202,17 @@ static inline const struct xattr_handler 
> > *f2fs_xattr_handler(int index)
> > return handler;
> >  }
> >  
> > -static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
> > -   size_t len, const char *name)
> > +static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
> > +   unsigned int max_size, int index,
> > +   size_t len, const char *name)
> >  {
> > struct f2fs_xattr_entry *entry;
> > +   void *max_addr = base_addr + ENTRY_SIZE(XATTR_ENTRY(base_addr)) +
> > +   max_size - 1;
> 
> Hi Randall,
> 
> I think this is not right, I enable noinline_xattr mount option, and add
> printk to see the status here, it shows
> 
> __find_xattr, base_addr:8e709ba92000, max_addr:8e709baa131f, 
> max_size:4
> 
> 8e709baa131f - 8e709ba92000 = F31F
> 
I would like to try another way.
The key is the pointer of entry should never run over the boundary of txattr
allocated in lookup_all_xattrs().

I will send v4.

> >  
> > list_for_each_xattr(entry, base_addr) {
> > +   if ((void *)entry + sizeof(__u32) > max_addr)
> > +   return NULL;
> > if (entry->e_name_index != index)
> > continue;
> > if (entry->e_name_len != len)
> > @@ -301,6 +306,7 @@ static int lookup_all_xattrs(struct inode *inode, 
> > struct page *ipage,
> > nid_t xnid = F2FS_I(inode)->i_xattr_nid;
> > unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
> > unsigned int inline_size = inline_xattr_size(inode);
> > +   unsigned int max_size = inline_size + size + XATTR_PADDING_SIZE;
> > int err = 0;
> >  
> > if (!size && !inline_size)
> > @@ -323,6 +329,7 @@ static int lookup_all_xattrs(struct inode *inode, 
> > struct page *ipage,
> > *base_size = inline_size;
> > goto check;
> > }
> > +   max_size -= inline_size;
> 
> The cur_addr pointer may point to middle of inline xattr space due to below 
> code? we
> should consider such case here.
> 
> if (last_addr)
>   cur_addr = XATTR_HDR(last_addr) - 1;
> 
> > }
> >  
> > /* read from xattr node block */
> > @@ -330,6 +337,8 @@ static int lookup_all_xattrs(struct inode *inode, 
> > struct page *ipage,
> > err = read_xattr_block(inode, txattr_addr);
> > if (err)
> > goto out;
> > +
> > +   max_size -= size;
> 
> We should not shrink max_size after loading xattr block's data.
> 
> Thanks,
> 
> > }
> >  
> > if (last_addr)
> > @@ -337,7 +346,12 

[f2fs-dev] [PATCH v5] f2fs: fix to avoid accessing xattr across the boundary

2019-04-11 Thread Randall Huang via Linux-f2fs-devel
When we traverse xattr entries via __find_xattr(),
if the raw filesystem content is faked or any hardware failure occurs,
out-of-bound error can be detected by KASAN.
Fix the issue by introducing boundary check.

[   38.402878] c7   1827 BUG: KASAN: slab-out-of-bounds in 
f2fs_getxattr+0x518/0x68c
[   38.402891] c7   1827 Read of size 4 at addr ffc0b6fb35dc by task
[   38.402935] c7   1827 Call trace:
[   38.402952] c7   1827 [] dump_backtrace+0x0/0x6bc
[   38.402966] c7   1827 [] show_stack+0x20/0x2c
[   38.402981] c7   1827 [] dump_stack+0xfc/0x140
[   38.402995] c7   1827 [] 
print_address_description+0x80/0x2d8
[   38.403009] c7   1827 [] kasan_report_error+0x198/0x1fc
[   38.403022] c7   1827 [] kasan_report_error+0x0/0x1fc
[   38.403037] c7   1827 [] __asan_load4+0x1b0/0x1b8
[   38.403051] c7   1827 [] f2fs_getxattr+0x518/0x68c
[   38.403066] c7   1827 [] f2fs_xattr_generic_get+0xb0/0xd0
[   38.403080] c7   1827 [] __vfs_getxattr+0x1f4/0x1fc
[   38.403096] c7   1827 [] 
inode_doinit_with_dentry+0x360/0x938
[   38.403109] c7   1827 [] selinux_d_instantiate+0x2c/0x38
[   38.403123] c7   1827 [] security_d_instantiate+0x68/0x98
[   38.403136] c7   1827 [] d_splice_alias+0x58/0x348
[   38.403149] c7   1827 [] f2fs_lookup+0x608/0x774
[   38.403163] c7   1827 [] lookup_slow+0x1e0/0x2cc
[   38.403177] c7   1827 [] walk_component+0x160/0x520
[   38.403190] c7   1827 [] path_lookupat+0x110/0x2b4
[   38.403203] c7   1827 [] filename_lookup+0x1d8/0x3a8
[   38.403216] c7   1827 [] user_path_at_empty+0x54/0x68
[   38.403229] c7   1827 [] SyS_getxattr+0xb4/0x18c
[   38.403241] c7   1827 [] el0_svc_naked+0x34/0x38

Bug: 126558260

Signed-off-by: Randall Huang 
---
v2:
* return EFAULT if OOB error is detected

v3:
* fix typo in setxattr()

v4:
* change boundry definition

v5:
* revise boundry definition
---
 fs/f2fs/xattr.c | 32 +++-
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 848a785abe25..587429e29a69 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -202,12 +202,18 @@ static inline const struct xattr_handler 
*f2fs_xattr_handler(int index)
return handler;
 }
 
-static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
-   size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
+   void *last_base_addr, int index,
+   size_t len, const char *name)
 {
struct f2fs_xattr_entry *entry;
 
list_for_each_xattr(entry, base_addr) {
+   if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
+   (void *)XATTR_NEXT_ENTRY(entry) +
+   sizeof(__u32) > last_base_addr)
+   return NULL;
+
if (entry->e_name_index != index)
continue;
if (entry->e_name_len != len)
@@ -298,6 +304,7 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
void **base_addr, int *base_size)
 {
void *cur_addr, *txattr_addr, *last_addr = NULL;
+   void *last_txattr_addr = NULL;
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
unsigned int inline_size = inline_xattr_size(inode);
@@ -311,6 +318,8 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
if (!txattr_addr)
return -ENOMEM;
 
+   last_txattr_addr = (void *)txattr_addr + inline_size + size;
+
/* read from inline xattr */
if (inline_size) {
err = read_inline_xattr(inode, ipage, txattr_addr);
@@ -337,7 +346,11 @@ static int lookup_all_xattrs(struct inode *inode, struct 
page *ipage,
else
cur_addr = txattr_addr;
 
-   *xe = __find_xattr(cur_addr, index, len, name);
+   *xe = __find_xattr(cur_addr, last_txattr_addr, index, len, name);
+   if (!*xe) {
+   err = -EFAULT;
+   goto out;
+   }
 check:
if (IS_XATTR_LAST_ENTRY(*xe)) {
err = -ENODATA;
@@ -581,10 +594,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,
struct page *ipage, int flags)
 {
struct f2fs_xattr_entry *here, *last;
-   void *base_addr;
+   void *base_addr, *last_base_addr = NULL;
int found, newsize;
size_t len;
__u32 new_hsize;
+   nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+   unsigned int xattr_nid_size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
+   unsigned int inline_size = inline_xattr_size(inode);
+
int error = 0;
 
if (name == NULL)
@@ -604,9 +621,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,
error = read_all_xattrs(inode, ipage, &base_addr);
if (error)
return error;
+   last_base_addr = (void *)base_ad