[f2fs-dev] [PATCH] Introduce sg_read_buffer
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
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
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
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
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
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
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
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
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
