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
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87ppj1qexz.fsf_-_@x220.int.ebiederm.org>
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ