]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net/iucv: fix locking in .getsockopt
authorBreno Leitao <leitao@debian.org>
Thu, 21 May 2026 14:11:45 +0000 (07:11 -0700)
committerJakub Kicinski <kuba@kernel.org>
Sat, 23 May 2026 00:40:32 +0000 (17:40 -0700)
Mirror iucv_sock_setsockopt() and wrap the whole switch in
lock_sock()/release_sock(). The pre-existing SO_MSGLIMIT-only lock
becomes redundant and is removed.

Any AF_IUCV HIPER user can potentially crash the kernel by racing
recvmsg() with getsockopt(SO_MSGSIZE): the SO_MSGSIZE arm dereferences
iucv->hs_dev->mtu after iucv_sock_close() (called from the racing
recvmsg()) has set hs_dev to NULL, producing a NULL pointer dereference
oops.

Suggested-by: Stanislav Fomichev <sdf.kernel@gmail.com>
Fixes: 51363b8751a6 ("af_iucv: allow retrieval of maximum message size")
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Tested-by: Alexandra Winter <wintera@linux.ibm.com>
Link: https://patch.msgid.link/20260521-af_iucv_fix2-v1-1-f16b1c510aa9@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/iucv/af_iucv.c

index 72dfccd4e3d58813e00ebfe38cdff492e2977197..c2dc3338670e83c2882534f9ac5a21bacfadb9c2 100644 (file)
@@ -1540,7 +1540,7 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname,
        struct sock *sk = sock->sk;
        struct iucv_sock *iucv = iucv_sk(sk);
        unsigned int val;
-       int len;
+       int len, rc;
 
        if (level != SOL_IUCV)
                return -ENOPROTOOPT;
@@ -1553,26 +1553,34 @@ static int iucv_sock_getsockopt(struct socket *sock, int level, int optname,
 
        len = min_t(unsigned int, len, sizeof(int));
 
+       rc = 0;
+
+       lock_sock(sk);
        switch (optname) {
        case SO_IPRMDATA_MSG:
                val = (iucv->flags & IUCV_IPRMDATA) ? 1 : 0;
                break;
        case SO_MSGLIMIT:
-               lock_sock(sk);
                val = (iucv->path != NULL) ? iucv->path->msglim /* connected */
                                           : iucv->msglimit;    /* default */
-               release_sock(sk);
                break;
        case SO_MSGSIZE:
-               if (sk->sk_state == IUCV_OPEN)
-                       return -EBADFD;
+               if (sk->sk_state == IUCV_OPEN) {
+                       rc = -EBADFD;
+                       break;
+               }
                val = (iucv->hs_dev) ? iucv->hs_dev->mtu -
                                sizeof(struct af_iucv_trans_hdr) - ETH_HLEN :
                                0x7fffffff;
                break;
        default:
-               return -ENOPROTOOPT;
+               rc = -ENOPROTOOPT;
+               break;
        }
+       release_sock(sk);
+
+       if (rc)
+               return rc;
 
        if (put_user(len, optlen))
                return -EFAULT;