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