From: Hangyu Hua hbh25y@gmail.com
stable inclusion from stable-v4.19.285 commit 59a27414bb00e48c4153a8b794fb4e69910a6a1b category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I7E6ML CVE: CVE-2023-35788
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 4d56304e5827c8cc8cc18c75343d283af7c4825c ]
If we send two TCA_FLOWER_KEY_ENC_OPTS_GENEVE packets and their total size is 252 bytes(key->enc_opts.len = 252) then key->enc_opts.len = opt->length = data_len / 4 = 0 when the third TCA_FLOWER_KEY_ENC_OPTS_GENEVE packet enters fl_set_geneve_opt. This bypasses the next bounds check and results in an out-of-bounds.
Fixes: 0a6e77784f49 ("net/sched: allow flower to match tunnel options") Signed-off-by: Hangyu Hua hbh25y@gmail.com Reviewed-by: Simon Horman simon.horman@corigine.com Reviewed-by: Pieter Jansen van Vuuren pieter.jansen-van-vuuren@amd.com Link: https://lore.kernel.org/r/20230531102805.27090-1-hbh25y@gmail.com Signed-off-by: Paolo Abeni pabeni@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Zhengchao Shao shaozhengchao@huawei.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- net/sched/cls_flower.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index bd27251ba953..fff54fa798d5 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -634,6 +634,9 @@ static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key, if (option_len > sizeof(struct geneve_opt)) data_len = option_len - sizeof(struct geneve_opt);
+ if (key->enc_opts.len > FLOW_DIS_TUN_OPTS_MAX - 4) + return -ERANGE; + opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len]; memset(opt, 0xff, option_len); opt->length = data_len / 4;
From: Pengcheng Yang yangpc@wangsu.com
stable inclusion from stable-v4.19.283 commit 2a6c63d04d89227ee45d0234c8059e2bccc15d73 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I7E5C1 CVE: CVE-2023-3268
----------------------------------------
[ Upstream commit 341a7213e5c1ce274cc0f02270054905800ea660 ]
When reading, read_pos should start with bytes_consumed, not file->f_pos. Because when there is more than one reader, the read_pos corresponding to file->f_pos may have been consumed, which will cause the data that has been consumed to be read and the bytes_consumed update error.
Signed-off-by: Pengcheng Yang yangpc@wangsu.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Reviewed-by: Jens Axboe axboe@kernel.dk Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Jann Horn jannh@google.com Cc: Al Viro viro@zeniv.linux.org.uke Link: http://lkml.kernel.org/r/1579691175-28949-1-git-send-email-yangpc@wangsu.com Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Stable-dep-of: 43ec16f1450f ("relayfs: fix out-of-bounds access in relay_file_read") Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: GONG, Ruiqi gongruiqi1@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- kernel/relay.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/kernel/relay.c b/kernel/relay.c index 5ad6cd2483ae..b8a535171961 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -996,14 +996,14 @@ static void relay_file_read_consume(struct rchan_buf *buf, /* * relay_file_read_avail - boolean, are there unconsumed bytes available? */ -static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos) +static int relay_file_read_avail(struct rchan_buf *buf) { size_t subbuf_size = buf->chan->subbuf_size; size_t n_subbufs = buf->chan->n_subbufs; size_t produced = buf->subbufs_produced; size_t consumed = buf->subbufs_consumed;
- relay_file_read_consume(buf, read_pos, 0); + relay_file_read_consume(buf, 0, 0);
consumed = buf->subbufs_consumed;
@@ -1064,23 +1064,20 @@ static size_t relay_file_read_subbuf_avail(size_t read_pos,
/** * relay_file_read_start_pos - find the first available byte to read - * @read_pos: file read position * @buf: relay channel buffer * - * If the @read_pos is in the middle of padding, return the + * If the read_pos is in the middle of padding, return the * position of the first actually available byte, otherwise * return the original value. */ -static size_t relay_file_read_start_pos(size_t read_pos, - struct rchan_buf *buf) +static size_t relay_file_read_start_pos(struct rchan_buf *buf) { size_t read_subbuf, padding, padding_start, padding_end; size_t subbuf_size = buf->chan->subbuf_size; size_t n_subbufs = buf->chan->n_subbufs; size_t consumed = buf->subbufs_consumed % n_subbufs; + size_t read_pos = consumed * subbuf_size + buf->bytes_consumed;
- if (!read_pos) - read_pos = consumed * subbuf_size + buf->bytes_consumed; read_subbuf = read_pos / subbuf_size; padding = buf->padding[read_subbuf]; padding_start = (read_subbuf + 1) * subbuf_size - padding; @@ -1136,10 +1133,10 @@ static ssize_t relay_file_read(struct file *filp, do { void *from;
- if (!relay_file_read_avail(buf, *ppos)) + if (!relay_file_read_avail(buf)) break;
- read_start = relay_file_read_start_pos(*ppos, buf); + read_start = relay_file_read_start_pos(buf); avail = relay_file_read_subbuf_avail(read_start, buf); if (!avail) break;
From: Zhang Zhengming zhang.zhengming@h3c.com
stable inclusion from stable-v4.19.283 commit ed32488417669568308b65ba5d45799418f9ed49 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I7E5C1 CVE: CVE-2023-3268
----------------------------------------
[ Upstream commit 43ec16f1450f4936025a9bdf1a273affdb9732c1 ]
There is a crash in relay_file_read, as the var from point to the end of last subbuf.
The oops looks something like: pc : __arch_copy_to_user+0x180/0x310 lr : relay_file_read+0x20c/0x2c8 Call trace: __arch_copy_to_user+0x180/0x310 full_proxy_read+0x68/0x98 vfs_read+0xb0/0x1d0 ksys_read+0x6c/0xf0 __arm64_sys_read+0x20/0x28 el0_svc_common.constprop.3+0x84/0x108 do_el0_svc+0x74/0x90 el0_svc+0x1c/0x28 el0_sync_handler+0x88/0xb0 el0_sync+0x148/0x180
We get the condition by analyzing the vmcore:
1). The last produced byte and last consumed byte both at the end of the last subbuf
2). A softirq calls function(e.g __blk_add_trace) to write relay buffer occurs when an program is calling relay_file_read_avail().
relay_file_read relay_file_read_avail relay_file_read_consume(buf, 0, 0); //interrupted by softirq who will write subbuf .... return 1; //read_start point to the end of the last subbuf read_start = relay_file_read_start_pos //avail is equal to subsize avail = relay_file_read_subbuf_avail //from points to an invalid memory address from = buf->start + read_start //system is crashed copy_to_user(buffer, from, avail)
Link: https://lkml.kernel.org/r/20230419040203.37676-1-zhang.zhengming@h3c.com Fixes: 8d62fdebdaf9 ("relay file read: start-pos fix") Signed-off-by: Zhang Zhengming zhang.zhengming@h3c.com Reviewed-by: Zhao Lei zhao_lei1@hoperun.com Reviewed-by: Zhou Kete zhou.kete@h3c.com Reviewed-by: Pengcheng Yang yangpc@wangsu.com Cc: Jens Axboe axboe@kernel.dk Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: GONG, Ruiqi gongruiqi1@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- kernel/relay.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/relay.c b/kernel/relay.c index b8a535171961..8ad762ab0c6b 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -1076,7 +1076,8 @@ static size_t relay_file_read_start_pos(struct rchan_buf *buf) size_t subbuf_size = buf->chan->subbuf_size; size_t n_subbufs = buf->chan->n_subbufs; size_t consumed = buf->subbufs_consumed % n_subbufs; - size_t read_pos = consumed * subbuf_size + buf->bytes_consumed; + size_t read_pos = (consumed * subbuf_size + buf->bytes_consumed) + % (n_subbufs * subbuf_size);
read_subbuf = read_pos / subbuf_size; padding = buf->padding[read_subbuf];