[PATCH 1/1] 9p: fix caches_show() out-of-bounds write
Ren Wei <[email protected]> Sat, 20 Jun 2026 23:53:03 +0800
| Newsgroups | dev.linux.lists.v9fs |
|---|---|
| Message-ID | <abfb65f4800634dafb08238bba20cb48797e796f.1781908090.git.zzhan461@ucr.edu> |
From: Zhao Zhang <[email protected]> The sysfs show handler for /sys/fs/9p/caches appends cache tags with snprintf(buf + count, limit, ...) and then advances count and limit by the return value. This is incorrect for truncation because snprintf() returns the full would-have-been length, not the number of bytes stored. Once the accumulated output exceeds PAGE_SIZE, count can advance past the sysfs buffer and limit can become negative. A later iteration then passes an out-of-bounds destination pointer and an oversized size_t into snprintf(), leading to an out-of-bounds write. Use sysfs_emit_at() for the append instead. It follows the sysfs buffer contract and returns the number of bytes actually stored, so the offset remains bounded even when the output is truncated. Fixes: 86db0c32f16c ("9p: fix /sys/fs/9p/caches overwriting itself") Cc: [email protected] Reported-by: Yuan Tan <[email protected]> Reported-by: Zhengchuan Liang <[email protected]> Reported-by: Xin Liu <[email protected]> Assisted-by: Codex:GPT-5.4 Signed-off-by: Zhao Zhang <[email protected]> Signed-off-by: Ren Wei <[email protected]> --- fs/9p/v9fs.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index acda42499ca9..0668bad681bf 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -17,6 +17,7 @@ #include <linux/fs_context.h> #include <linux/slab.h> #include <linux/seq_file.h> +#include <linux/sysfs.h> #include <net/9p/9p.h> #include <net/9p/client.h> #include <net/9p/transport.h> @@ -592,21 +593,14 @@ static ssize_t caches_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - ssize_t n = 0, count = 0, limit = PAGE_SIZE; + ssize_t count = 0; struct v9fs_session_info *v9ses; spin_lock(&v9fs_sessionlist_lock); list_for_each_entry(v9ses, &v9fs_sessionlist, slist) { - if (v9ses->cachetag) { - n = snprintf(buf + count, limit, "%s\n", v9ses->cachetag); - if (n < 0) { - count = n; - break; - } - - count += n; - limit -= n; - } + if (v9ses->cachetag) + count += sysfs_emit_at(buf, count, "%s\n", + v9ses->cachetag); } spin_unlock(&v9fs_sessionlist_lock); -- 2.47.3