]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
can: raw: convert to getsockopt_iter
authorBreno Leitao <leitao@debian.org>
Wed, 8 Apr 2026 10:30:32 +0000 (03:30 -0700)
committerJakub Kicinski <kuba@kernel.org>
Mon, 13 Apr 2026 21:56:29 +0000 (14:56 -0700)
Convert CAN raw socket's getsockopt implementation to use the new
getsockopt_iter callback with sockopt_t.

Key changes:
- Replace (char __user *optval, int __user *optlen) with sockopt_t *opt
- Use opt->optlen for buffer length (input) and returned size (output)
- Use copy_to_iter() instead of copy_to_user()
- For CAN_RAW_FILTER and CAN_RAW_XL_VCID_OPTS: on -ERANGE, set
  opt->optlen to the required buffer size. The wrapper writes this
  back to userspace even on error, preserving the existing API that
  lets userspace discover the needed allocation size.

Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260408-getsockopt-v3-4-061bb9cb355d@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/can/raw.c

index 56c95c768778accaec42cb998c7d679a42c85894..a0c0f5e946d8bb067878d9ad351951792a33adae 100644 (file)
@@ -761,7 +761,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
 }
 
 static int raw_getsockopt(struct socket *sock, int level, int optname,
-                         char __user *optval, int __user *optlen)
+                         sockopt_t *opt)
 {
        struct sock *sk = sock->sk;
        struct raw_sock *ro = raw_sk(sk);
@@ -771,8 +771,7 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
 
        if (level != SOL_CAN_RAW)
                return -EINVAL;
-       if (get_user(len, optlen))
-               return -EFAULT;
+       len = opt->optlen;
        if (len < 0)
                return -EINVAL;
 
@@ -788,12 +787,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
                        if (len < fsize) {
                                /* return -ERANGE and needed space in optlen */
                                err = -ERANGE;
-                               if (put_user(fsize, optlen))
-                                       err = -EFAULT;
+                               opt->optlen = fsize;
                        } else {
                                if (len > fsize)
                                        len = fsize;
-                               if (copy_to_user(optval, ro->filter, len))
+                               if (copy_to_iter(ro->filter, len,
+                                                &opt->iter_out) != len)
                                        err = -EFAULT;
                        }
                } else {
@@ -802,7 +801,7 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
                release_sock(sk);
 
                if (!err)
-                       err = put_user(len, optlen);
+                       opt->optlen = len;
                return err;
        }
        case CAN_RAW_ERR_FILTER:
@@ -846,16 +845,16 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
                if (len < sizeof(ro->raw_vcid_opts)) {
                        /* return -ERANGE and needed space in optlen */
                        err = -ERANGE;
-                       if (put_user(sizeof(ro->raw_vcid_opts), optlen))
-                               err = -EFAULT;
+                       opt->optlen = sizeof(ro->raw_vcid_opts);
                } else {
                        if (len > sizeof(ro->raw_vcid_opts))
                                len = sizeof(ro->raw_vcid_opts);
-                       if (copy_to_user(optval, &ro->raw_vcid_opts, len))
+                       if (copy_to_iter(&ro->raw_vcid_opts, len,
+                                        &opt->iter_out) != len)
                                err = -EFAULT;
                }
                if (!err)
-                       err = put_user(len, optlen);
+                       opt->optlen = len;
                return err;
        }
        case CAN_RAW_JOIN_FILTERS:
@@ -869,9 +868,8 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
                return -ENOPROTOOPT;
        }
 
-       if (put_user(len, optlen))
-               return -EFAULT;
-       if (copy_to_user(optval, val, len))
+       opt->optlen = len;
+       if (copy_to_iter(val, len, &opt->iter_out) != len)
                return -EFAULT;
        return 0;
 }
@@ -1078,7 +1076,7 @@ static const struct proto_ops raw_ops = {
        .listen        = sock_no_listen,
        .shutdown      = sock_no_shutdown,
        .setsockopt    = raw_setsockopt,
-       .getsockopt    = raw_getsockopt,
+       .getsockopt_iter = raw_getsockopt,
        .sendmsg       = raw_sendmsg,
        .recvmsg       = raw_recvmsg,
        .mmap          = sock_no_mmap,