Commit d0c80dbb9704 for kernel
commit d0c80dbb970439bd2eeb0e5effff8c16a5f4e1e3
Author: Eric Dumazet <edumazet@google.com>
Date: Wed Aug 5 13:15:08 2026 +0000
net/atm: fix slab-out-of-bounds read in vcc_setsockopt()
vcc_setsockopt() contained an ineffective optlen check:
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
return -EINVAL;
If __SO_LEVEL_MATCH(optname, level) evaluated to false (e.g. if the caller
passed a mismatched level), the length check optlen != __SO_SIZE(optname)
was short-circuited and bypassed. Execution then fell through to switch(optname),
calling copy_from_sockptr() assuming optval contained sufficient space.
Furthermore, even if level matched, a cgroup BPF setsockopt filter could shrink
optlen after entry. Because copy_from_sockptr() on kernel pointers uses memcpy(),
this leads to a KASAN slab-out-of-bounds read when optlen is smaller than the
expected structure size.
Fix this by using copy_safe_from_sockptr(), which unconditionally validates
that optlen is at least the expected size before copying. Also change the local
'value' variable type from 'unsigned long' to 'int' so that SO_SETCLP matches
its sizeof(int) ABI encoding on 64-bit systems.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+53ecc09fb81df10ef4de@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=53ecc09fb81df10ef4de
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260805131508.3227331-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
diff --git a/net/atm/common.c b/net/atm/common.c
index c7f92405daf0..81195727fa18 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -710,7 +710,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct atm_vcc *vcc;
- unsigned long value;
+ int value;
int error;
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
@@ -722,8 +722,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
{
struct atm_qos qos;
- if (copy_from_sockptr(&qos, optval, sizeof(qos)))
- return -EFAULT;
+ error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
+ optlen);
+ if (error)
+ return error;
error = check_qos(&qos);
if (error)
return error;
@@ -737,8 +739,10 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
return 0;
}
case SO_SETCLP:
- if (copy_from_sockptr(&value, optval, sizeof(value)))
- return -EFAULT;
+ error = copy_safe_from_sockptr(&value, sizeof(value), optval,
+ optlen);
+ if (error)
+ return error;
if (value)
vcc->atm_options |= ATM_ATMOPT_CLP;
else