summaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2022-10-10 12:31:21 -0400
committerPaul Moore <paul@paul-moore.com>2022-11-04 23:25:30 -0400
commitb10b9c342f7571f287fd422be5d5c0beb26ba974 (patch)
treee2afb492a670ba89d761a4f94d875cf0a171b17e /security/selinux
parent610b17b05c5c682fbb8fefedae1aacaab412eac3 (diff)
downloadlinux-b10b9c342f7571f287fd422be5d5c0beb26ba974.tar.bz2
lsm: make security_socket_getpeersec_stream() sockptr_t safe
Commit 4ff09db1b79b ("bpf: net: Change sk_getsockopt() to take the sockptr_t argument") made it possible to call sk_getsockopt() with both user and kernel address space buffers through the use of the sockptr_t type. Unfortunately at the time of conversion the security_socket_getpeersec_stream() LSM hook was written to only accept userspace buffers, and in a desire to avoid having to change the LSM hook the commit author simply passed the sockptr_t's userspace buffer pointer. Since the only sk_getsockopt() callers at the time of conversion which used kernel sockptr_t buffers did not allow SO_PEERSEC, and hence the security_socket_getpeersec_stream() hook, this was acceptable but also very fragile as future changes presented the possibility of silently passing kernel space pointers to the LSM hook. There are several ways to protect against this, including careful code review of future commits, but since relying on code review to catch bugs is a recipe for disaster and the upstream eBPF maintainer is "strongly against defensive programming", this patch updates the LSM hook, and all of the implementations to support sockptr_t and safely handle both user and kernel space buffers. Acked-by: Casey Schaufler <casey@schaufler-ca.com> Acked-by: John Johansen <john.johansen@canonical.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/hooks.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f553c370397e..0bdddeba90a6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5119,11 +5119,12 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return err;
}
-static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
- int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec_stream(struct socket *sock,
+ sockptr_t optval, sockptr_t optlen,
+ unsigned int len)
{
int err = 0;
- char *scontext;
+ char *scontext = NULL;
u32 scontext_len;
struct sk_security_struct *sksec = sock->sk->sk_security;
u32 peer_sid = SECSID_NULL;
@@ -5139,17 +5140,15 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
&scontext_len);
if (err)
return err;
-
if (scontext_len > len) {
err = -ERANGE;
goto out_len;
}
- if (copy_to_user(optval, scontext, scontext_len))
+ if (copy_to_sockptr(optval, scontext, scontext_len))
err = -EFAULT;
-
out_len:
- if (put_user(scontext_len, optlen))
+ if (copy_to_sockptr(optlen, &scontext_len, sizeof(scontext_len)))
err = -EFAULT;
kfree(scontext);
return err;