Commit 5b75e7d6 authored by Breno Leitao's avatar Breno Leitao Committed by Jakub Kicinski
Browse files

can: raw: convert to getsockopt_iter



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: default avatarBreno Leitao <leitao@debian.org>
Acked-by: default avatarStanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20260408-getsockopt-v3-4-061bb9cb355d@debian.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 9c99d627
Loading
Loading
Loading
Loading
+13 −15
Original line number Diff line number Diff line
@@ -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,