mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 10:00:03 -04:00
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: 1da177e4c3 ("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>
This commit is contained in:
committed by
Jakub Kicinski
parent
b1896543ce
commit
d0c80dbb97
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user