lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Sun, 25 May 2014 22:36:24 -0700 From: ebiederm@...ssion.com (Eric W. Biederman) To: Linus Torvalds <torvalds@...ux-foundation.org> Cc: Andy Lutomirski <luto@...capital.net>, "Jorge Boncompte \[DTI2\]" <jorge@...2.net>, Jiri Benc <jbenc@...hat.com>, David Miller <davem@...emloft.net>, Vivek Goyal <vgoyal@...hat.com>, Simo Sorce <ssorce@...hat.com>, "security\@kernel.org" <security@...nel.org>, Network Development <netdev@...r.kernel.org>, "Serge E. Hallyn" <serge@...lyn.com>, Michael Kerrisk-manpages <mtk.manpages@...il.com> Subject: [RFC][PATCH 2/1] netlink: Use the credential at the time the destination address was set. When sending a message over a netlink socket and then checking to see if the person is authorized to send the message it is important that we verify both the sender of the message and the whoever it is that set the destination of the message both have permission. Otherwise it becomes possible for an unpriivleged user to set the message destination and trick an suid process to write to the socket and change the network connection. For netlink sockets socket() sets the default destination address to 0 (the kernel) so we need to remember the credentials when a socket is created. For netlink sockets connect() changes the default destination address so we need to remember the credentials of the last changer of the default destination with connect. This results is there always being a valid remembered credential on the socket and so that credential is unconditionally freed in netlink_release(). This change makes the semantics of the permission checks of netlink sockets make sense,and removes the possibility of an unprivileged user getting access to a root own socket and changing the destination address with connect. Signed-off-by: "Eric W. Biederman" <ebiederm@...ssion.com> --- This winds up continuig to grab credentials when socket() is called because we actually set the destination address in socket() for netlink sockets, but now we update those credentials when connect() is called. include/linux/netlink.h | 2 +- net/netlink/af_netlink.c | 27 ++++++++++++++++++++++++--- net/netlink/af_netlink.h | 1 + 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index f289d085f87f..4f4607c0a1a1 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -19,7 +19,7 @@ enum netlink_skb_flags { NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */ NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */ NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */ - NETLINK_SKB_DST = 0x8, /* Packet not socket destination */ + NETLINK_SKB_DST = 0x8, /* Dst set in sendto or sendmsg */ }; struct netlink_skb_parms { diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 15c731f03fa6..5b886ed6a648 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1191,6 +1191,7 @@ static int __netlink_create(struct net *net, struct socket *sock, mutex_init(nlk->cb_mutex); } init_waitqueue_head(&nlk->wait); + nlk->cred = get_current_cred(); #ifdef CONFIG_NETLINK_MMAP mutex_init(&nlk->pg_vec_lock); #endif @@ -1291,6 +1292,7 @@ static int netlink_release(struct socket *sock) NETLINK_URELEASE, &n); } + put_cred(nlk->cred); module_put(nlk->module); netlink_table_grab(); @@ -1377,9 +1379,17 @@ retry: bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, struct user_namespace *user_ns, int cap) { - return ((nsp->flags & NETLINK_SKB_DST) || - file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) && - ns_capable(user_ns, cap); + const struct cred *cred; + bool capable; + + rcu_read_lock(); + cred = nlk_sk(nsp->sk)->cred; + capable = ((nsp->flags & NETLINK_SKB_DST) || + security_capable(cred, user_ns, cap)) && + ns_capable(user_ns, cap); + rcu_read_unlock(); + + return capable; } EXPORT_SYMBOL(__netlink_ns_capable); @@ -1569,14 +1579,20 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; + const struct cred *old_cred; if (alen < sizeof(addr->sa_family)) return -EINVAL; if (addr->sa_family == AF_UNSPEC) { + lock_sock(sk); sk->sk_state = NETLINK_UNCONNECTED; nlk->dst_portid = 0; nlk->dst_group = 0; + old_cred = nlk->cred; + nlk->cred = get_current_cred(); + put_cred(old_cred); + release_sock(sk); return 0; } if (addr->sa_family != AF_NETLINK) @@ -1590,9 +1606,14 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, err = netlink_autobind(sock); if (err == 0) { + lock_sock(sk); sk->sk_state = NETLINK_CONNECTED; nlk->dst_portid = nladdr->nl_pid; nlk->dst_group = ffs(nladdr->nl_groups); + old_cred = nlk->cred; + nlk->cred = get_current_cred(); + put_cred(old_cred); + release_sock(sk); } return err; diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 0b59d441f5b6..d3c9d319e9e6 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h @@ -40,6 +40,7 @@ struct netlink_sock { void (*netlink_rcv)(struct sk_buff *skb); int (*netlink_bind)(int group); void (*netlink_unbind)(int group); + const struct cred *cred; struct module *module; #ifdef CONFIG_NETLINK_MMAP struct mutex pg_vec_lock; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists