Split __sys_getsockopt() into two functions by removing the core logic into a sub-function (do_sock_getsockopt()). This will avoid code duplication when executing the same operation in other callers, for instance. do_sock_getsockopt() will be called by io_uring getsockopt() command operation in the following patch. Suggested-by: Martin KaFai Lau <martin.lau@xxxxxxxxx> Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx> --- include/net/sock.h | 3 +++ net/socket.c | 51 ++++++++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index aa8fb54ad0af..fbd568a43d28 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1863,6 +1863,9 @@ int sock_setsockopt(struct socket *sock, int level, int op, sockptr_t optval, unsigned int optlen); int do_sock_setsockopt(struct socket *sock, bool compat, int level, int optname, char __user *user_optval, int optlen); +int do_sock_getsockopt(struct socket *sock, bool compat, int level, + int optname, char __user *user_optval, + int __user *user_optlen); int sk_getsockopt(struct sock *sk, int level, int optname, sockptr_t optval, sockptr_t optlen); diff --git a/net/socket.c b/net/socket.c index 360332e098d4..3ec779a56f79 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2333,28 +2333,17 @@ SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, INDIRECT_CALLABLE_DECLARE(bool tcp_bpf_bypass_getsockopt(int level, int optname)); -/* - * Get a socket option. Because we don't know the option lengths we have - * to pass a user mode parameter for the protocols to sort out. - */ -int __sys_getsockopt(int fd, int level, int optname, char __user *optval, - int __user *optlen) +int do_sock_getsockopt(struct socket *sock, bool compat, int level, + int optname, char __user *optval, + int __user *optlen) { int max_optlen __maybe_unused; const struct proto_ops *ops; - int err, fput_needed; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - return err; + int err; err = security_socket_getsockopt(sock, level, optname); if (err) - goto out_put; - - if (!in_compat_syscall()) - max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen); + return err; ops = READ_ONCE(sock->ops); if (level == SOL_SOCKET) @@ -2362,14 +2351,36 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval, else if (unlikely(!ops->getsockopt)) err = -EOPNOTSUPP; else - err = ops->getsockopt(sock, level, optname, optval, - optlen); + err = ops->getsockopt(sock, level, optname, optval, optlen); - if (!in_compat_syscall()) + if (!compat) { + max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen); err = BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname, optval, optlen, max_optlen, err); -out_put: + } + + return err; +} +EXPORT_SYMBOL(do_sock_getsockopt); + +/* Get a socket option. Because we don't know the option lengths we have + * to pass a user mode parameter for the protocols to sort out. + */ +int __sys_getsockopt(int fd, int level, int optname, char __user *optval, + int __user *optlen) +{ + int err, fput_needed; + bool compat = in_compat_syscall(); + struct socket *sock; + + sock = sockfd_lookup_light(fd, &err, &fput_needed); + if (!sock) + return err; + + err = do_sock_getsockopt(sock, compat, level, optname, optval, + optlen); + fput_light(sock->file, fput_needed); return err; } -- 2.34.1