Netdev List
 help / color / mirror / Atom feed
* [PATCH 14/21] userns: nfnetlink_log: Report socket uids in the log sockets user namespace
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

At logging instance creation capture the peer netlink socket's user
namespace. Use the captured peer user namespace when reporting socket
uids to the peer.

The peer socket's user namespace is guaranateed to be valid until the user
closes the netlink socket.  nfnetlink_log removes instances during the final
close of a socket.  __build_packet_message does not get called after an
instance is destroyed.   Therefore it is safe to let the peer netlink socket
take care of the user namespace reference counting for us.

Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 init/Kconfig                  |    1 -
 net/netfilter/nfnetlink_log.c |   14 ++++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 07435e0..2660b31 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -947,7 +947,6 @@ config UIDGID_CONVERTED
 	depends on NETFILTER_XT_MATCH_OWNER = n
 	depends on NETFILTER_XT_MATCH_RECENT = n
 	depends on NETFILTER_XT_TARGET_LOG = n
-	depends on NETFILTER_NETLINK_LOG = n
 	depends on AF_RXRPC = n
 	depends on NET_KEY = n
 	depends on DNS_RESOLVER = n
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 169ab59..4142aac 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -55,6 +55,7 @@ struct nfulnl_instance {
 	unsigned int qlen;		/* number of nlmsgs in skb */
 	struct sk_buff *skb;		/* pre-allocatd skb */
 	struct timer_list timer;
+	struct user_namespace *peer_user_ns;	/* User namespace of the peer process */
 	int peer_pid;			/* PID of the peer process */
 
 	/* configurable parameters */
@@ -132,7 +133,7 @@ instance_put(struct nfulnl_instance *inst)
 static void nfulnl_timer(unsigned long data);
 
 static struct nfulnl_instance *
-instance_create(u_int16_t group_num, int pid)
+instance_create(u_int16_t group_num, int pid, struct user_namespace *user_ns)
 {
 	struct nfulnl_instance *inst;
 	int err;
@@ -162,6 +163,7 @@ instance_create(u_int16_t group_num, int pid)
 
 	setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);
 
+	inst->peer_user_ns = user_ns;
 	inst->peer_pid = pid;
 	inst->group_num = group_num;
 
@@ -503,8 +505,11 @@ __build_packet_message(struct nfulnl_instance *inst,
 		read_lock_bh(&skb->sk->sk_callback_lock);
 		if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
 			struct file *file = skb->sk->sk_socket->file;
-			__be32 uid = htonl(file->f_cred->fsuid);
-			__be32 gid = htonl(file->f_cred->fsgid);
+			__be32 uid = htonl(from_kuid_munged(inst->peer_user_ns,
+							    file->f_cred->fsuid));
+			__be32 gid = htonl(from_kgid_munged(inst->peer_user_ns,
+							    file->f_cred->fsgid));
+			/* need to unlock here since NLA_PUT may goto */
 			read_unlock_bh(&skb->sk->sk_callback_lock);
 			if (nla_put_be32(inst->skb, NFULA_UID, uid) ||
 			    nla_put_be32(inst->skb, NFULA_GID, gid))
@@ -783,7 +788,8 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
 			}
 
 			inst = instance_create(group_num,
-					       NETLINK_CB(skb).pid);
+					       NETLINK_CB(skb).pid,
+					       sk_user_ns(NETLINK_CB(skb).ssk));
 			if (IS_ERR(inst)) {
 				ret = PTR_ERR(inst);
 				goto out;
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 13/21] userns: Teach inet_diag to work with user namespaces
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Andrew Vagin, Pavel Emelyanov,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Eric W. Biederman,
	David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Compute the user namespace of the socket that we are replying to
and translate the kuids of reported sockets into that user namespace.

Cc: Andrew Vagin <avagin-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org>
Cc: Pavel Emelyanov <xemul-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/linux/inet_diag.h |    1 +
 init/Kconfig              |    1 -
 net/ipv4/inet_diag.c      |   21 +++++++++++++++------
 net/ipv4/udp_diag.c       |    5 ++++-
 4 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index f1362b5..e788c18 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -159,6 +159,7 @@ struct inet_diag_handler {
 struct inet_connection_sock;
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
 			      struct sk_buff *skb, struct inet_diag_req_v2 *req,
+			      struct user_namespace *user_ns,
 			      u32 pid, u32 seq, u16 nlmsg_flags,
 			      const struct nlmsghdr *unlh);
 void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb,
diff --git a/init/Kconfig b/init/Kconfig
index 8447e0c..07435e0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -950,7 +950,6 @@ config UIDGID_CONVERTED
 	depends on NETFILTER_NETLINK_LOG = n
 	depends on AF_RXRPC = n
 	depends on NET_KEY = n
-	depends on INET_DIAG = n
 	depends on DNS_RESOLVER = n
 
 	# Filesystems
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 570e61f..8bc005b 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -69,6 +69,7 @@ static inline void inet_diag_unlock_handler(
 
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
 			      struct sk_buff *skb, struct inet_diag_req_v2 *req,
+			      struct user_namespace *user_ns,		      	
 			      u32 pid, u32 seq, u16 nlmsg_flags,
 			      const struct nlmsghdr *unlh)
 {
@@ -124,7 +125,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
 	}
 #endif
 
-	r->idiag_uid = sock_i_uid(sk);
+	r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
 	r->idiag_inode = sock_i_ino(sk);
 
 	if (ext & (1 << (INET_DIAG_MEMINFO - 1))) {
@@ -199,11 +200,12 @@ EXPORT_SYMBOL_GPL(inet_sk_diag_fill);
 
 static int inet_csk_diag_fill(struct sock *sk,
 			      struct sk_buff *skb, struct inet_diag_req_v2 *req,
+			      struct user_namespace *user_ns,
 			      u32 pid, u32 seq, u16 nlmsg_flags,
 			      const struct nlmsghdr *unlh)
 {
 	return inet_sk_diag_fill(sk, inet_csk(sk),
-			skb, req, pid, seq, nlmsg_flags, unlh);
+			skb, req, user_ns, pid, seq, nlmsg_flags, unlh);
 }
 
 static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
@@ -256,14 +258,16 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
 }
 
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
-			struct inet_diag_req_v2 *r, u32 pid, u32 seq, u16 nlmsg_flags,
+			struct inet_diag_req_v2 *r,
+			struct user_namespace *user_ns,
+			u32 pid, u32 seq, u16 nlmsg_flags,
 			const struct nlmsghdr *unlh)
 {
 	if (sk->sk_state == TCP_TIME_WAIT)
 		return inet_twsk_diag_fill((struct inet_timewait_sock *)sk,
 					   skb, r, pid, seq, nlmsg_flags,
 					   unlh);
-	return inet_csk_diag_fill(sk, skb, r, pid, seq, nlmsg_flags, unlh);
+	return inet_csk_diag_fill(sk, skb, r, user_ns, pid, seq, nlmsg_flags, unlh);
 }
 
 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb,
@@ -311,6 +315,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
 	}
 
 	err = sk_diag_fill(sk, rep, req,
+			   sk_user_ns(NETLINK_CB(in_skb).ssk),
 			   NETLINK_CB(in_skb).pid,
 			   nlh->nlmsg_seq, 0, nlh);
 	if (err < 0) {
@@ -551,6 +556,7 @@ static int inet_csk_diag_dump(struct sock *sk,
 		return 0;
 
 	return inet_csk_diag_fill(sk, skb, r,
+				  sk_user_ns(NETLINK_CB(cb->skb).ssk),
 				  NETLINK_CB(cb->skb).pid,
 				  cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
 }
@@ -591,7 +597,9 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 }
 
 static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
-			      struct request_sock *req, u32 pid, u32 seq,
+			      struct request_sock *req,
+			      struct user_namespace *user_ns,
+			      u32 pid, u32 seq,
 			      const struct nlmsghdr *unlh)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
@@ -625,7 +633,7 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
 	r->idiag_expires = jiffies_to_msecs(tmo);
 	r->idiag_rqueue = 0;
 	r->idiag_wqueue = 0;
-	r->idiag_uid = sock_i_uid(sk);
+	r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
 	r->idiag_inode = 0;
 #if IS_ENABLED(CONFIG_IPV6)
 	if (r->idiag_family == AF_INET6) {
@@ -702,6 +710,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
 			}
 
 			err = inet_diag_fill_req(skb, sk, req,
+					       sk_user_ns(NETLINK_CB(cb->skb).ssk),
 					       NETLINK_CB(cb->skb).pid,
 					       cb->nlh->nlmsg_seq, cb->nlh);
 			if (err < 0) {
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 16d0960..d2f336e 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -24,7 +24,9 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
 	if (!inet_diag_bc_sk(bc, sk))
 		return 0;
 
-	return inet_sk_diag_fill(sk, NULL, skb, req, NETLINK_CB(cb->skb).pid,
+	return inet_sk_diag_fill(sk, NULL, skb, req,
+			sk_user_ns(NETLINK_CB(cb->skb).ssk),
+			NETLINK_CB(cb->skb).pid,
 			cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
 }
 
@@ -69,6 +71,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
 		goto out;
 
 	err = inet_sk_diag_fill(sk, NULL, rep, req,
+			   sk_user_ns(NETLINK_CB(in_skb).ssk),
 			   NETLINK_CB(in_skb).pid,
 			   nlh->nlmsg_seq, 0, nlh);
 	if (err < 0) {
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 12/21] userns: Implement sk_user_ns
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Add a helper sk_user_ns to make it easy to find the user namespace
of the process that opened a socket.

Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/net/sock.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 65c3d62..9d43736 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -604,6 +604,15 @@ static inline void sk_add_bind_node(struct sock *sk,
 #define sk_for_each_bound(__sk, node, list) \
 	hlist_for_each_entry(__sk, node, list, sk_bind_node)
 
+static inline struct user_namespace *sk_user_ns(struct sock *sk)
+{
+	/* Careful only use this in a context where these parameters
+	 * can not change and must all be valid, such as recvmsg from
+	 * userspace.
+	 */
+	return sk->sk_socket->file->f_cred->user_ns;
+}
+
 /* Sock flags */
 enum sock_flags {
 	SOCK_DEAD,
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 11/21] netlink: Make the sending netlink socket availabe in NETLINK_CB
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

The sending socket of an skb is already available by it's port id
in the NETLINK_CB.  If you want to know more like to examine the
credentials on the sending socket you have to look up the sending
socket by it's port id and all of the needed functions and data
structures are static inside of af_netlink.c.  So do the simple
thing and pass the sending socket to the receivers in the NETLINK_CB.

I intend to use this to get the user namespace of the sending socket
in inet_diag so that I can report uids in the context of the process
who opened the socket, the same way I report uids in the contect
of the process who opens files.

Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/linux/netlink.h  |    1 +
 net/netlink/af_netlink.c |    6 ++++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index f74dd13..c9fdde2 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -165,6 +165,7 @@ struct netlink_skb_parms {
 	struct ucred		creds;		/* Skb credentials	*/
 	__u32			pid;
 	__u32			dst_group;
+	struct sock		*ssk;
 };
 
 #define NETLINK_CB(skb)		(*(struct netlink_skb_parms*)&((skb)->cb))
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 5463969..7cb7867 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -912,7 +912,8 @@ static void netlink_rcv_wake(struct sock *sk)
 		wake_up_interruptible(&nlk->wait);
 }
 
-static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb)
+static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
+				  struct sock *ssk)
 {
 	int ret;
 	struct netlink_sock *nlk = nlk_sk(sk);
@@ -921,6 +922,7 @@ static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb)
 	if (nlk->netlink_rcv != NULL) {
 		ret = skb->len;
 		skb_set_owner_r(skb, sk);
+		NETLINK_CB(skb).ssk = ssk;
 		nlk->netlink_rcv(skb);
 		consume_skb(skb);
 	} else {
@@ -947,7 +949,7 @@ retry:
 		return PTR_ERR(sk);
 	}
 	if (netlink_is_kernel(sk))
-		return netlink_unicast_kernel(sk, skb);
+		return netlink_unicast_kernel(sk, skb, ssk);
 
 	if (sk_filter(sk, skb)) {
 		err = skb->len;
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 09/21] pidns: Export free_pid_ns
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

There is a least one modular user so export free_pid_ns so modules can
capture and use the pid namespace on the very rare occasion when it
makes sense.

Signed-off-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 kernel/pid_namespace.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index b3c7fd5..baa528d 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/reboot.h>
+#include <linux/export.h>
 
 #define BITS_PER_PAGE		(PAGE_SIZE*8)
 
@@ -144,6 +145,7 @@ void free_pid_ns(struct kref *kref)
 	if (parent != NULL)
 		put_pid_ns(parent);
 }
+EXPORT_SYMBOL_GPL(free_pid_ns);
 
 void zap_pid_ns_processes(struct pid_namespace *pid_ns)
 {
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 08/21] net ip6 flowlabel: Make owner a union of struct pid * and kuid_t
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Correct a long standing omission and use struct pid in the owner
field of struct ip6_flowlabel when the share type is IPV6_FL_S_PROCESS.
This guarantees we don't have issues when pid wraparound occurs.

Use a kuid_t in the owner field of struct ip6_flowlabel when the
share type is IPV6_FL_S_USER to add user namespace support.

In /proc/net/ip6_flowlabel capture the current pid namespace when
opening the file and release the pid namespace when the file is
closed ensuring we print the pid owner value that is meaning to
the reader of the file.  Similarly use from_kuid_munged to print
uid values that are meaningful to the reader of the file.

This requires exporting pid_nr_ns so that ipv6 can continue to built
as a module.  Yoiks what silliness

Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/net/ipv6.h       |    5 +++-
 init/Kconfig             |    1 -
 kernel/pid.c             |    1 +
 net/ipv6/ip6_flowlabel.c |   50 +++++++++++++++++++++++++++++++++++++++------
 4 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 01c34b3..c8a2024 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -222,7 +222,10 @@ struct ip6_flowlabel {
 	struct ipv6_txoptions	*opt;
 	unsigned long		linger;
 	u8			share;
-	u32			owner;
+	union {
+		struct pid *pid;
+		kuid_t uid;
+	} owner;
 	unsigned long		lastuse;
 	unsigned long		expires;
 	struct net		*fl_net;
diff --git a/init/Kconfig b/init/Kconfig
index f857f97..64ff9ce 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -948,7 +948,6 @@ config UIDGID_CONVERTED
 	depends on NETFILTER_XT_MATCH_RECENT = n
 	depends on NETFILTER_XT_TARGET_LOG = n
 	depends on NETFILTER_NETLINK_LOG = n
-	depends on IPV6 = n
 	depends on AF_RXRPC = n
 	depends on NET_KEY = n
 	depends on INET_DIAG = n
diff --git a/kernel/pid.c b/kernel/pid.c
index e86b291a..aebd4f5 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -479,6 +479,7 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)
 	}
 	return nr;
 }
+EXPORT_SYMBOL_GPL(pid_nr_ns);
 
 pid_t pid_vnr(struct pid *pid)
 {
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 9772fbd..c836a6a 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -22,6 +22,7 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/pid_namespace.h>
 
 #include <net/net_namespace.h>
 #include <net/sock.h>
@@ -90,6 +91,11 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
 
 static void fl_free(struct ip6_flowlabel *fl)
 {
+	switch (fl->share) {
+	case IPV6_FL_S_PROCESS:
+		put_pid(fl->owner.pid);
+		break;
+	}
 	if (fl) {
 		release_net(fl->fl_net);
 		kfree(fl->opt);
@@ -394,10 +400,10 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
 	case IPV6_FL_S_ANY:
 		break;
 	case IPV6_FL_S_PROCESS:
-		fl->owner = current->pid;
+		fl->owner.pid = get_task_pid(current, PIDTYPE_PID);
 		break;
 	case IPV6_FL_S_USER:
-		fl->owner = current_euid();
+		fl->owner.uid = current_euid();
 		break;
 	default:
 		err = -EINVAL;
@@ -561,7 +567,10 @@ recheck:
 				err = -EPERM;
 				if (fl1->share == IPV6_FL_S_EXCL ||
 				    fl1->share != fl->share ||
-				    fl1->owner != fl->owner)
+				    ((fl1->share == IPV6_FL_S_PROCESS) &&
+				     (fl1->owner.pid == fl->owner.pid)) ||
+				    ((fl1->share == IPV6_FL_S_USER) &&
+				     uid_eq(fl1->owner.uid, fl->owner.uid)))
 					goto release;
 
 				err = -EINVAL;
@@ -621,6 +630,7 @@ done:
 
 struct ip6fl_iter_state {
 	struct seq_net_private p;
+	struct pid_namespace *pid_ns;
 	int bucket;
 };
 
@@ -699,6 +709,7 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v)
 
 static int ip6fl_seq_show(struct seq_file *seq, void *v)
 {
+	struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
 	if (v == SEQ_START_TOKEN)
 		seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n",
 			   "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
@@ -708,7 +719,11 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v)
 			   "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n",
 			   (unsigned int)ntohl(fl->label),
 			   fl->share,
-			   (int)fl->owner,
+			   ((fl->share == IPV6_FL_S_PROCESS) ?
+			    pid_nr_ns(fl->owner.pid, state->pid_ns) :
+			    ((fl->share == IPV6_FL_S_USER) ?
+			     from_kuid_munged(seq_user_ns(seq), fl->owner.uid) :
+			     0)),
 			   atomic_read(&fl->users),
 			   fl->linger/HZ,
 			   (long)(fl->expires - jiffies)/HZ,
@@ -727,8 +742,29 @@ static const struct seq_operations ip6fl_seq_ops = {
 
 static int ip6fl_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_net(inode, file, &ip6fl_seq_ops,
-			    sizeof(struct ip6fl_iter_state));
+	struct seq_file *seq;
+	struct ip6fl_iter_state *state;
+	int err;
+
+	err = seq_open_net(inode, file, &ip6fl_seq_ops,
+			   sizeof(struct ip6fl_iter_state));
+
+	if (!err) {
+		seq = file->private_data;
+		state = ip6fl_seq_private(seq);
+		rcu_read_lock();
+		state->pid_ns = get_pid_ns(task_active_pid_ns(current));
+		rcu_read_unlock();
+	}
+	return err;
+}
+
+static int ip6fl_seq_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
+	put_pid_ns(state->pid_ns);
+	return seq_release_net(inode, file);
 }
 
 static const struct file_operations ip6fl_seq_fops = {
@@ -736,7 +772,7 @@ static const struct file_operations ip6fl_seq_fops = {
 	.open		=	ip6fl_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_net,
+	.release	=	ip6fl_seq_release,
 };
 
 static int __net_init ip6_flowlabel_proc_init(struct net *net)
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 07/21] userns: Use kgids for sysctl_ping_group_range
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller,
	Eric W. Biederman, Vasiliy Kulikov
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

- Store sysctl_ping_group_range as a paire of kgid_t values
  instead of a pair of gid_t values.
- Move the kgid conversion work from ping_init_sock into ipv4_ping_group_range
- For invalid cases reset to the default disabled state.

With the kgid_t conversion made part of the original value sanitation
from userspace understand how the code will react becomes clearer
and it becomes possible to set the sysctl ping group range from
something other than the initial user namespace.

Cc: Vasiliy Kulikov <segoon-cxoSlKxDwOJWk0Htik3J/w@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/net/netns/ipv4.h   |    3 ++-
 init/Kconfig               |    1 -
 net/ipv4/ping.c            |   18 ++++++------------
 net/ipv4/sysctl_net_ipv4.c |   42 +++++++++++++++++++++++++++---------------
 4 files changed, 35 insertions(+), 29 deletions(-)

diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 1474dd6..3516dc0 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -5,6 +5,7 @@
 #ifndef __NETNS_IPV4_H__
 #define __NETNS_IPV4_H__
 
+#include <linux/uidgid.h>
 #include <net/inet_frag.h>
 
 struct tcpm_hash_bucket;
@@ -62,7 +63,7 @@ struct netns_ipv4 {
 	int sysctl_icmp_ratemask;
 	int sysctl_icmp_errors_use_inbound_ifaddr;
 
-	unsigned int sysctl_ping_group_range[2];
+	kgid_t sysctl_ping_group_range[2];
 	long sysctl_tcp_mem[3];
 
 	atomic_t rt_genid;
diff --git a/init/Kconfig b/init/Kconfig
index 25a6ebb..f857f97 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -948,7 +948,6 @@ config UIDGID_CONVERTED
 	depends on NETFILTER_XT_MATCH_RECENT = n
 	depends on NETFILTER_XT_TARGET_LOG = n
 	depends on NETFILTER_NETLINK_LOG = n
-	depends on INET = n
 	depends on IPV6 = n
 	depends on AF_RXRPC = n
 	depends on NET_KEY = n
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index bee5eeb..8f3d054 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -185,10 +185,10 @@ exit:
 	return sk;
 }
 
-static void inet_get_ping_group_range_net(struct net *net, gid_t *low,
-					  gid_t *high)
+static void inet_get_ping_group_range_net(struct net *net, kgid_t *low,
+					  kgid_t *high)
 {
-	gid_t *data = net->ipv4.sysctl_ping_group_range;
+	kgid_t *data = net->ipv4.sysctl_ping_group_range;
 	unsigned int seq;
 
 	do {
@@ -203,19 +203,13 @@ static void inet_get_ping_group_range_net(struct net *net, gid_t *low,
 static int ping_init_sock(struct sock *sk)
 {
 	struct net *net = sock_net(sk);
-	gid_t group = current_egid();
-	gid_t range[2];
+	kgid_t group = current_egid();
 	struct group_info *group_info = get_current_groups();
 	int i, j, count = group_info->ngroups;
 	kgid_t low, high;
 
-	inet_get_ping_group_range_net(net, range, range+1);
-	low = make_kgid(&init_user_ns, range[0]);
-	high = make_kgid(&init_user_ns, range[1]);
-	if (!gid_valid(low) || !gid_valid(high) || gid_lt(high, low))
-		return -EACCES;
-
-	if (range[0] <= group && group <= range[1])
+	inet_get_ping_group_range_net(net, &low, &high);
+	if (gid_lte(low, group) && gid_lte(group, high))
 		return 0;
 
 	for (i = 0; i < group_info->nblocks; i++) {
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1b5ce96..3e78c79 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -76,9 +76,9 @@ static int ipv4_local_port_range(ctl_table *table, int write,
 }
 
 
-static void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high)
+static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high)
 {
-	gid_t *data = table->data;
+	kgid_t *data = table->data;
 	unsigned int seq;
 	do {
 		seq = read_seqbegin(&sysctl_local_ports.lock);
@@ -89,12 +89,12 @@ static void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low,
 }
 
 /* Update system visible IP port range */
-static void set_ping_group_range(struct ctl_table *table, gid_t range[2])
+static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t high)
 {
-	gid_t *data = table->data;
+	kgid_t *data = table->data;
 	write_seqlock(&sysctl_local_ports.lock);
-	data[0] = range[0];
-	data[1] = range[1];
+	data[0] = low;
+	data[1] = high;
 	write_sequnlock(&sysctl_local_ports.lock);
 }
 
@@ -103,21 +103,33 @@ static int ipv4_ping_group_range(ctl_table *table, int write,
 				 void __user *buffer,
 				 size_t *lenp, loff_t *ppos)
 {
+	struct user_namespace *user_ns = current_user_ns();
 	int ret;
-	gid_t range[2];
+	gid_t urange[2];
+	kgid_t low, high;
 	ctl_table tmp = {
-		.data = &range,
-		.maxlen = sizeof(range),
+		.data = &urange,
+		.maxlen = sizeof(urange),
 		.mode = table->mode,
 		.extra1 = &ip_ping_group_range_min,
 		.extra2 = &ip_ping_group_range_max,
 	};
 
-	inet_get_ping_group_range_table(table, range, range + 1);
+	inet_get_ping_group_range_table(table, &low, &high);
+	urange[0] = from_kgid_munged(user_ns, low);
+	urange[1] = from_kgid_munged(user_ns, high);
 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
 
-	if (write && ret == 0)
-		set_ping_group_range(table, range);
+	if (write && ret == 0) {
+		low = make_kgid(user_ns, urange[0]);
+		high = make_kgid(user_ns, urange[1]);
+		if (!gid_valid(low) || !gid_valid(high) ||
+		    (urange[1] < urange[0]) || gid_lt(high, low)) {
+			low = make_kgid(&init_user_ns, 1);
+			high = make_kgid(&init_user_ns, 0);
+		}
+		set_ping_group_range(table, low, high);
+	}
 
 	return ret;
 }
@@ -786,7 +798,7 @@ static struct ctl_table ipv4_net_table[] = {
 	{
 		.procname	= "ping_group_range",
 		.data		= &init_net.ipv4.sysctl_ping_group_range,
-		.maxlen		= sizeof(init_net.ipv4.sysctl_ping_group_range),
+		.maxlen		= sizeof(gid_t)*2,
 		.mode		= 0644,
 		.proc_handler	= ipv4_ping_group_range,
 	},
@@ -830,8 +842,8 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
 	 * Sane defaults - nobody may create ping sockets.
 	 * Boot scripts should set this to distro-specific group.
 	 */
-	net->ipv4.sysctl_ping_group_range[0] = 1;
-	net->ipv4.sysctl_ping_group_range[1] = 0;
+	net->ipv4.sysctl_ping_group_range[0] = make_kgid(&init_user_ns, 1);
+	net->ipv4.sysctl_ping_group_range[1] = make_kgid(&init_user_ns, 0);
 
 	tcp_init_mem(net);
 
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 06/21] userns: Print out socket uids in a user namespace aware fashion.
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Patrick McHardy, Hideaki YOSHIFUJI,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Vlad Yasevich,
	Eric W. Biederman, Arnaldo Carvalho de Melo, Remi Denis-Courmont,
	Alexey Kuznetsov, Sridhar Samudrala, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Cc: David Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Alexey Kuznetsov <kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
Cc: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
Cc: Hideaki YOSHIFUJI <yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
Cc: Patrick McHardy <kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
Cc: Remi Denis-Courmont <courmisch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Arnaldo Carvalho de Melo <acme-f8uhVLnGfZaxAyOMLChx1axOck334EZe@public.gmane.org>
Cc: Vlad Yasevich <vyasevich-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Sridhar Samudrala <sri-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/net/tcp.h          |    3 ++-
 init/Kconfig               |    6 ------
 net/appletalk/atalk_proc.c |    3 ++-
 net/ipv4/ping.c            |    4 +++-
 net/ipv4/raw.c             |    4 +++-
 net/ipv4/tcp_ipv4.c        |    6 +++---
 net/ipv4/udp.c             |    4 +++-
 net/ipv6/raw.c             |    3 ++-
 net/ipv6/tcp_ipv6.c        |    6 +++---
 net/ipv6/udp.c             |    3 ++-
 net/ipx/ipx_proc.c         |    3 ++-
 net/key/af_key.c           |    2 +-
 net/llc/llc_proc.c         |    2 +-
 net/packet/af_packet.c     |    2 +-
 net/phonet/socket.c        |    6 ++++--
 net/sctp/proc.c            |    6 ++++--
 16 files changed, 36 insertions(+), 27 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index e19124b..91e7467 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1509,7 +1509,8 @@ struct tcp_iter_state {
 	sa_family_t		family;
 	enum tcp_seq_states	state;
 	struct sock		*syn_wait_sk;
-	int			bucket, offset, sbucket, num, uid;
+	int			bucket, offset, sbucket, num;
+	kuid_t			uid;
 	loff_t			last_pos;
 };
 
diff --git a/init/Kconfig b/init/Kconfig
index 80fae19..25a6ebb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -942,10 +942,7 @@ config UIDGID_CONVERTED
 	depends on PROC_EVENTS = n
 
 	# Networking
-	depends on PACKET = n
 	depends on NET_9P = n
-	depends on IPX = n
-	depends on PHONET = n
 	depends on NET_CLS_FLOW = n
 	depends on NETFILTER_XT_MATCH_OWNER = n
 	depends on NETFILTER_XT_MATCH_RECENT = n
@@ -953,14 +950,11 @@ config UIDGID_CONVERTED
 	depends on NETFILTER_NETLINK_LOG = n
 	depends on INET = n
 	depends on IPV6 = n
-	depends on IP_SCTP = n
 	depends on AF_RXRPC = n
-	depends on LLC2 = n
 	depends on NET_KEY = n
 	depends on INET_DIAG = n
 	depends on DNS_RESOLVER = n
 	depends on AX25 = n
-	depends on ATALK = n
 
 	# Filesystems
 	depends on USB_GADGETFS = n
diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
index b5b1a22..c30f3a0 100644
--- a/net/appletalk/atalk_proc.c
+++ b/net/appletalk/atalk_proc.c
@@ -183,7 +183,8 @@ static int atalk_seq_socket_show(struct seq_file *seq, void *v)
 		   ntohs(at->dest_net), at->dest_node, at->dest_port,
 		   sk_wmem_alloc_get(s),
 		   sk_rmem_alloc_get(s),
-		   s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
+		   s->sk_state,
+		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(s)));
 out:
 	return 0;
 }
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 6232d47..bee5eeb 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -845,7 +845,9 @@ static void ping_format_sock(struct sock *sp, struct seq_file *f,
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
-		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
+		0, 0L, 0,
+		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
+		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
 		atomic_read(&sp->sk_drops), len);
 }
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index ff0f071..f242578 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -992,7 +992,9 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
 		i, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
-		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
+		0, 0L, 0,
+		from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
+		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
 }
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 42b2a6a..642be8a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2382,7 +2382,7 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 EXPORT_SYMBOL(tcp_proc_unregister);
 
 static void get_openreq4(const struct sock *sk, const struct request_sock *req,
-			 struct seq_file *f, int i, int uid, int *len)
+			 struct seq_file *f, int i, kuid_t uid, int *len)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	int ttd = req->expires - jiffies;
@@ -2399,7 +2399,7 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
 		1,    /* timers active (only the expire timer) */
 		jiffies_to_clock_t(ttd),
 		req->retrans,
-		uid,
+		from_kuid_munged(seq_user_ns(f), uid),
 		0,  /* non standard timer */
 		0, /* open_requests have no inode */
 		atomic_read(&sk->sk_refcnt),
@@ -2450,7 +2450,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		timer_active,
 		jiffies_to_clock_t(timer_expires - jiffies),
 		icsk->icsk_retransmits,
-		sock_i_uid(sk),
+		from_kuid_munged(seq_user_ns(f), sock_i_uid(sk)),
 		icsk->icsk_probes_out,
 		sock_i_ino(sk),
 		atomic_read(&sk->sk_refcnt), sk,
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index b4c3582..53b8981 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2110,7 +2110,9 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
-		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
+		0, 0L, 0,
+		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
+		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
 		atomic_read(&sp->sk_drops), len);
 }
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index ef0579d..7af88ef 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -1251,7 +1251,8 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
 		   sk_wmem_alloc_get(sp),
 		   sk_rmem_alloc_get(sp),
 		   0, 0L, 0,
-		   sock_i_uid(sp), 0,
+		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
+		   0,
 		   sock_i_ino(sp),
 		   atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
 }
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c66b90f..4b5b335 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1803,7 +1803,7 @@ static void tcp_v6_destroy_sock(struct sock *sk)
 #ifdef CONFIG_PROC_FS
 /* Proc filesystem TCPv6 sock list dumping. */
 static void get_openreq6(struct seq_file *seq,
-			 const struct sock *sk, struct request_sock *req, int i, int uid)
+			 const struct sock *sk, struct request_sock *req, int i, kuid_t uid)
 {
 	int ttd = req->expires - jiffies;
 	const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
@@ -1827,7 +1827,7 @@ static void get_openreq6(struct seq_file *seq,
 		   1,   /* timers active (only the expire timer) */
 		   jiffies_to_clock_t(ttd),
 		   req->retrans,
-		   uid,
+		   from_kuid_munged(seq_user_ns(seq), uid),
 		   0,  /* non standard timer */
 		   0, /* open_requests have no inode */
 		   0, req);
@@ -1877,7 +1877,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
 		   timer_active,
 		   jiffies_to_clock_t(timer_expires - jiffies),
 		   icsk->icsk_retransmits,
-		   sock_i_uid(sp),
+		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
 		   icsk->icsk_probes_out,
 		   sock_i_ino(sp),
 		   atomic_read(&sp->sk_refcnt), sp,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 99d0077..bbdff07 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1458,7 +1458,8 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
 		   sk_wmem_alloc_get(sp),
 		   sk_rmem_alloc_get(sp),
 		   0, 0L, 0,
-		   sock_i_uid(sp), 0,
+		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
+		   0,
 		   sock_i_ino(sp),
 		   atomic_read(&sp->sk_refcnt), sp,
 		   atomic_read(&sp->sk_drops));
diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
index f8ba30d..02ff7f2 100644
--- a/net/ipx/ipx_proc.c
+++ b/net/ipx/ipx_proc.c
@@ -217,7 +217,8 @@ static int ipx_seq_socket_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "%08X  %08X  %02X     %03d\n",
 		   sk_wmem_alloc_get(s),
 		   sk_rmem_alloc_get(s),
-		   s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
+		   s->sk_state,
+		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(s)));
 out:
 	return 0;
 }
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 34e4185..0481d4b 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3661,7 +3661,7 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
 			       atomic_read(&s->sk_refcnt),
 			       sk_rmem_alloc_get(s),
 			       sk_wmem_alloc_get(s),
-			       sock_i_uid(s),
+			       from_kuid_munged(seq_user_ns(f), sock_i_uid(s)),
 			       sock_i_ino(s)
 			       );
 	return 0;
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index a1839c0..7b4799c 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -151,7 +151,7 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v)
 		   sk_wmem_alloc_get(sk),
 		   sk_rmem_alloc_get(sk) - llc->copied_seq,
 		   sk->sk_state,
-		   sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1,
+		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 		   llc->link);
 out:
 	return 0;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ceaca7c..d147317 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3846,7 +3846,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
 			   po->ifindex,
 			   po->running,
 			   atomic_read(&s->sk_rmem_alloc),
-			   sock_i_uid(s),
+			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(s)),
 			   sock_i_ino(s));
 	}
 
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 0acc943..b7e9827 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -612,7 +612,8 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
 			sk->sk_protocol, pn->sobject, pn->dobject,
 			pn->resource, sk->sk_state,
 			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
-			sock_i_uid(sk), sock_i_ino(sk),
+			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
+			sock_i_ino(sk),
 			atomic_read(&sk->sk_refcnt), sk,
 			atomic_read(&sk->sk_drops), &len);
 	}
@@ -796,7 +797,8 @@ static int pn_res_seq_show(struct seq_file *seq, void *v)
 		struct sock *sk = *psk;
 
 		seq_printf(seq, "%02X %5d %lu%n",
-			   (int) (psk - pnres.sk), sock_i_uid(sk),
+			   (int) (psk - pnres.sk),
+			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 			   sock_i_ino(sk), &len);
 	}
 	seq_printf(seq, "%*s\n", 63 - len, "");
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 1e2eee8..dc12feb 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -216,7 +216,8 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
 		seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
 			   sctp_sk(sk)->type, sk->sk_state, hash,
 			   epb->bind_addr.port,
-			   sock_i_uid(sk), sock_i_ino(sk));
+			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
+			   sock_i_ino(sk));
 
 		sctp_seq_dump_local_addrs(seq, epb);
 		seq_printf(seq, "\n");
@@ -324,7 +325,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
 			   assoc->assoc_id,
 			   assoc->sndbuf_used,
 			   atomic_read(&assoc->rmem_alloc),
-			   sock_i_uid(sk), sock_i_ino(sk),
+			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
+			   sock_i_ino(sk),
 			   epb->bind_addr.port,
 			   assoc->peer.port);
 		seq_printf(seq, " ");
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 05/21] userns: Make seq_file's user namespace accessible
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric Dumazet,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Al Viro, Alexey Dobriyan,
	Eric W. Biederman, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

struct file already has a user namespace associated with it
in file->f_cred->user_ns, unfortunately because struct
seq_file has no struct file backpointer associated with
it, it is difficult to get at the user namespace in seq_file
context.  Therefore add a helper function seq_user_ns to return
the associated user namespace and a user_ns field to struct
seq_file to be used in implementing seq_user_ns.

Cc: Al Viro <viro-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.org>
Cc: Eric Dumazet <eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Cc: Alexey Dobriyan <adobriyan-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 fs/seq_file.c            |    4 ++++
 include/linux/seq_file.h |   14 ++++++++++++++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/fs/seq_file.c b/fs/seq_file.c
index 14cf9de..99dffab 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -9,6 +9,7 @@
 #include <linux/export.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/cred.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -56,6 +57,9 @@ int seq_open(struct file *file, const struct seq_operations *op)
 	memset(p, 0, sizeof(*p));
 	mutex_init(&p->lock);
 	p->op = op;
+#ifdef CONFIG_USER_NS
+	p->user_ns = file->f_cred->user_ns;
+#endif
 
 	/*
 	 * Wrappers around seq_open(e.g. swaps_open) need to be
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 83c44ee..68a04a3 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -13,6 +13,7 @@ struct file;
 struct path;
 struct inode;
 struct dentry;
+struct user_namespace;
 
 struct seq_file {
 	char *buf;
@@ -25,6 +26,9 @@ struct seq_file {
 	struct mutex lock;
 	const struct seq_operations *op;
 	int poll_event;
+#ifdef CONFIG_USER_NS
+	struct user_namespace *user_ns;
+#endif
 	void *private;
 };
 
@@ -128,6 +132,16 @@ int seq_put_decimal_ull(struct seq_file *m, char delimiter,
 int seq_put_decimal_ll(struct seq_file *m, char delimiter,
 			long long num);
 
+static inline struct user_namespace *seq_user_ns(struct seq_file *seq)
+{
+#ifdef CONFIG_USER_NS
+	return seq->user_ns;
+#else
+	extern struct user_namespace init_user_ns;
+	return &init_user_ns;
+#endif
+}
+
 #define SEQ_START_TOKEN ((void *)1)
 /*
  * Helpers for iteration over list_head-s in seq_files
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 04/21] userns: Allow USER_NS and NET simultaneously in Kconfig
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Now that the networking core is user namespace safe allow
networking and user namespaces to be built at the same time.

Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 init/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 364b38d..80fae19 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -942,7 +942,7 @@ config UIDGID_CONVERTED
 	depends on PROC_EVENTS = n
 
 	# Networking
-	depends on NET = n
+	depends on PACKET = n
 	depends on NET_9P = n
 	depends on IPX = n
 	depends on PHONET = n
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 03/21] userns: Convert sock_i_uid to return a kuid_t
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric W. Biederman,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 include/net/sock.h |    2 +-
 net/core/sock.c    |    6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index b373023..65c3d62 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1668,7 +1668,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
 	write_unlock_bh(&sk->sk_callback_lock);
 }
 
-extern int sock_i_uid(struct sock *sk);
+extern kuid_t sock_i_uid(struct sock *sk);
 extern unsigned long sock_i_ino(struct sock *sk);
 
 static inline struct dst_entry *
diff --git a/net/core/sock.c b/net/core/sock.c
index 9c7fe4f..5c6a435 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1526,12 +1526,12 @@ void sock_edemux(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_edemux);
 
-int sock_i_uid(struct sock *sk)
+kuid_t sock_i_uid(struct sock *sk)
 {
-	int uid;
+	kuid_t uid;
 
 	read_lock_bh(&sk->sk_callback_lock);
-	uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0;
+	uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : GLOBAL_ROOT_UID;
 	read_unlock_bh(&sk->sk_callback_lock);
 	return uid;
 }
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 02/21] userns: Convert __dev_set_promiscuity to use kuids in audit logs
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Klaus Heinrich Kiwi,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Eric Paris,
	Eric W. Biederman, David Miller
In-Reply-To: <1344889115-21610-1-git-send-email-ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Cc: Klaus Heinrich Kiwi <klausk-xuelUoVDAHHQT0dZR+AlfA@public.gmane.org>
Cc: Eric Paris <eparis-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 net/core/dev.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 0cb3fe8..026bb4a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4492,8 +4492,8 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
 static int __dev_set_promiscuity(struct net_device *dev, int inc)
 {
 	unsigned int old_flags = dev->flags;
-	uid_t uid;
-	gid_t gid;
+	kuid_t uid;
+	kgid_t gid;
 
 	ASSERT_RTNL();
 
@@ -4525,7 +4525,8 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
 				dev->name, (dev->flags & IFF_PROMISC),
 				(old_flags & IFF_PROMISC),
 				audit_get_loginuid(current),
-				uid, gid,
+				from_kuid(&init_user_ns, uid),
+				from_kgid(&init_user_ns, gid),
 				audit_get_sessionid(current));
 		}
 
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 01/21] userns: Convert net/core/scm.c to use kuids and kgids
From: Eric W. Biederman @ 2012-08-13 20:18 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: Eric Dumazet,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Eric W. Biederman,
	David Miller
In-Reply-To: <87ehnav9n5.fsf-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

From: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

With the existence of kuid_t and kgid_t we can take this further
and remove the usage of struct cred altogether, ensuring we
don't get cache line misses from reference counts.   For now
however start simply and do a straight forward conversion
I can be certain is correct.

In cred_to_ucred use from_kuid_munged and from_kgid_munged
as these values are going directly to userspace and we want to use
the userspace safe values not -1 when reporting a value that does not
map.  The earlier conversion that used from_kuid was buggy in that
respect.  Oops.

Cc: Eric Dumazet <eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Signed-off-by: Eric W. Biederman <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
---
 net/core/scm.c  |   31 +++++++++++++++++++++++--------
 net/core/sock.c |    4 ++--
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/net/core/scm.c b/net/core/scm.c
index 8f6ccfd..5472ae7 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -45,12 +45,17 @@
 static __inline__ int scm_check_creds(struct ucred *creds)
 {
 	const struct cred *cred = current_cred();
+	kuid_t uid = make_kuid(cred->user_ns, creds->uid);
+	kgid_t gid = make_kgid(cred->user_ns, creds->gid);
+
+	if (!uid_valid(uid) || !gid_valid(gid))
+		return -EINVAL;
 
 	if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
-	    ((creds->uid == cred->uid   || creds->uid == cred->euid ||
-	      creds->uid == cred->suid) || capable(CAP_SETUID)) &&
-	    ((creds->gid == cred->gid   || creds->gid == cred->egid ||
-	      creds->gid == cred->sgid) || capable(CAP_SETGID))) {
+	    ((uid_eq(uid, cred->uid)   || uid_eq(uid, cred->euid) ||
+	      uid_eq(uid, cred->suid)) || capable(CAP_SETUID)) &&
+	    ((gid_eq(gid, cred->gid)   || gid_eq(gid, cred->egid) ||
+	      gid_eq(gid, cred->sgid)) || capable(CAP_SETGID))) {
 	       return 0;
 	}
 	return -EPERM;
@@ -149,6 +154,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
 				goto error;
 			break;
 		case SCM_CREDENTIALS:
+		{
+			kuid_t uid;
+			kgid_t gid;
 			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
 				goto error;
 			memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred));
@@ -166,22 +174,29 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
 				p->pid = pid;
 			}
 
+			err = -EINVAL;
+			uid = make_kuid(current_user_ns(), p->creds.uid);
+			gid = make_kgid(current_user_ns(), p->creds.gid);
+			if (!uid_valid(uid) || !gid_valid(gid))
+				goto error;
+
 			if (!p->cred ||
-			    (p->cred->euid != p->creds.uid) ||
-			    (p->cred->egid != p->creds.gid)) {
+			    !uid_eq(p->cred->euid, uid) ||
+			    !gid_eq(p->cred->egid, gid)) {
 				struct cred *cred;
 				err = -ENOMEM;
 				cred = prepare_creds();
 				if (!cred)
 					goto error;
 
-				cred->uid = cred->euid = p->creds.uid;
-				cred->gid = cred->egid = p->creds.gid;
+				cred->uid = cred->euid = uid;
+				cred->gid = cred->egid = gid;
 				if (p->cred)
 					put_cred(p->cred);
 				p->cred = cred;
 			}
 			break;
+		}
 		default:
 			goto error;
 		}
diff --git a/net/core/sock.c b/net/core/sock.c
index 6b654b3..9c7fe4f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -868,8 +868,8 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred,
 	if (cred) {
 		struct user_namespace *current_ns = current_user_ns();
 
-		ucred->uid = from_kuid(current_ns, cred->euid);
-		ucred->gid = from_kgid(current_ns, cred->egid);
+		ucred->uid = from_kuid_munged(current_ns, cred->euid);
+		ucred->gid = from_kgid_munged(current_ns, cred->egid);
 	}
 }
 EXPORT_SYMBOL_GPL(cred_to_ucred);
-- 
1.7.5.4

^ permalink raw reply related

* [REVIEW][PATCH 0/21] User namespace changes to the networking stack.
From: Eric W. Biederman @ 2012-08-13 20:07 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: Linux Containers, David Miller


This is a modest set of changes against the current networking stack to
enable basic user namespace support.  Allowing the code to compile with
user namespaces enabled and removing the assumption that there is only
the initial user namespace.

Work to relax the privilege checks in the networking stack from
"capable(CAP_NET_ADMIN)" or "capable(CAP_NET_RAW)" to
"ns_capable(net->user_ns, CAP_NET_ADMIN)" or 
"ns_capable(net->user_ns, CAP_NET_RAW)" allowing root in a user
namespace to control a network namespace will come later.

David there are just enough interdependencies between the user namespace
bits that I intend to merge them all through my user namespace tree.
After the review is complete I will add these patches to my for-next
branch of my user-namespace.git tree where I do not intend to rebase.
If it make sense to pull these into net-next to avoid or reduce
conflicts that should not be a problem.

A current snapshot of my development tree for people who are interested
in seeing the entire picture is at:

git.kernel.org:/pub/scm/linux/kernel/git/ebiederm/user-namespace.git userns-always-map-user-v46

Eric W. Biederman (21):
      userns: Convert net/core/scm.c to use kuids and kgids
      userns: Convert __dev_set_promiscuity to use kuids in audit logs
      userns: Convert sock_i_uid to return a kuid_t
      userns: Allow USER_NS and NET simultaneously in Kconfig
      userns: Make seq_file's user namespace accessible
      userns: Print out socket uids in a user namespace aware fashion.
      userns: Use kgids for sysctl_ping_group_range
      net ip6 flowlabel: Make owner a union of struct pid * and kuid_t
      pidns: Export free_pid_ns
      userns: Convert net/ax25 to use kuid_t where appropriate
      netlink: Make the sending netlink socket availabe in NETLINK_CB
      userns: Implement sk_user_ns
      userns: Teach inet_diag to work with user namespaces
      userns: nfnetlink_log: Report socket uids in the log sockets user namespace
      net sched: Pass the skb into change so it can access NETLINK_CB
      userns: Convert cls_flow to work with user namespaces enabled
      userns: Convert xt_LOG to print socket kuids and kgids as uids and gids
      userns xt_recent: Specify the owner/group of ip_list_perms in the initial user namespace
      userns: xt_owner: Add basic user namespace support.
      userns: Make the airo wireless driver use kuids for proc uids and gids
      userns: Convert tun/tap to use kuid and kgid where appropriate

 drivers/net/tun.c             |   46 ++++++++++++++++++++++++++-----------
 drivers/net/wireless/airo.c   |   48 +++++++++++++++++++++++----------------
 fs/seq_file.c                 |    4 +++
 include/linux/inet_diag.h     |    1 +
 include/linux/netlink.h       |    1 +
 include/linux/seq_file.h      |   14 +++++++++++
 include/net/ax25.h            |    4 +-
 include/net/ipv6.h            |    5 +++-
 include/net/netns/ipv4.h      |    3 +-
 include/net/sch_generic.h     |    3 +-
 include/net/sock.h            |   11 ++++++++-
 include/net/tcp.h             |    3 +-
 init/Kconfig                  |   18 --------------
 kernel/pid.c                  |    1 +
 kernel/pid_namespace.c        |    2 +
 net/appletalk/atalk_proc.c    |    3 +-
 net/ax25/ax25_uid.c           |   21 +++++++++++-----
 net/core/dev.c                |    7 +++--
 net/core/scm.c                |   31 ++++++++++++++++++------
 net/core/sock.c               |   10 ++++----
 net/ipv4/inet_diag.c          |   21 ++++++++++++-----
 net/ipv4/ping.c               |   22 +++++++----------
 net/ipv4/raw.c                |    4 ++-
 net/ipv4/sysctl_net_ipv4.c    |   42 ++++++++++++++++++++++------------
 net/ipv4/tcp_ipv4.c           |    6 ++--
 net/ipv4/udp.c                |    4 ++-
 net/ipv4/udp_diag.c           |    5 +++-
 net/ipv6/ip6_flowlabel.c      |   50 +++++++++++++++++++++++++++++++++++-----
 net/ipv6/raw.c                |    3 +-
 net/ipv6/tcp_ipv6.c           |    6 ++--
 net/ipv6/udp.c                |    3 +-
 net/ipx/ipx_proc.c            |    3 +-
 net/key/af_key.c              |    2 +-
 net/llc/llc_proc.c            |    2 +-
 net/netfilter/nfnetlink_log.c |   14 ++++++++---
 net/netfilter/xt_LOG.c        |   16 ++++++++-----
 net/netfilter/xt_owner.c      |   30 +++++++++++++++++++-----
 net/netfilter/xt_recent.c     |   13 +++++++++-
 net/netlink/af_netlink.c      |    6 +++-
 net/packet/af_packet.c        |    2 +-
 net/phonet/socket.c           |    6 +++-
 net/sched/cls_api.c           |    2 +-
 net/sched/cls_basic.c         |    3 +-
 net/sched/cls_cgroup.c        |    3 +-
 net/sched/cls_flow.c          |   19 +++++++++++----
 net/sched/cls_fw.c            |    3 +-
 net/sched/cls_route.c         |    3 +-
 net/sched/cls_rsvp.h          |    3 +-
 net/sched/cls_tcindex.c       |    3 +-
 net/sched/cls_u32.c           |    3 +-
 net/sctp/proc.c               |    6 +++-
 51 files changed, 368 insertions(+), 176 deletions(-)

Eric

^ permalink raw reply

* Re: [patch net-next 03/16] vlan: add link to upper device
From: Flavio Leitner @ 2012-08-13 19:04 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, davem, edumazet, faisal.latif, roland, sean.hefty,
	hal.rosenstock, fubar, andy, divy, jitendra.kalsaria, sony.chacko,
	linux-driver, kaber, ursula.braun, blaschka, linux390, shemminger,
	bhutchings, therbert, xiyou.wangcong, joe, gregory.v.rose,
	john.r.fastabend, linux-rdma, linux-kernel, linux-s390, bridge
In-Reply-To: <1344871635-1052-4-git-send-email-jiri@resnulli.us>

On Mon, 13 Aug 2012 17:27:02 +0200
Jiri Pirko <jiri@resnulli.us> wrote:

> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> ---
>  net/8021q/vlan.c |   10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
> index 9096bcb..739665e 100644
> --- a/net/8021q/vlan.c
> +++ b/net/8021q/vlan.c
> @@ -105,6 +105,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
>  	 */
>  	unregister_netdevice_queue(dev, head);
>  
> +	netdev_upper_dev_unlink(real_dev, dev);
> +
>  	if (grp->nr_vlan_devs == 0)
>  		vlan_gvrp_uninit_applicant(real_dev);
>  
> @@ -162,9 +164,13 @@ int register_vlan_dev(struct net_device *dev)
>  	if (err < 0)
>  		goto out_uninit_applicant;
>  
> +	err = netdev_upper_dev_link(real_dev, dev);
> +	if (err)
> +		goto out_uninit_applicant;
> +
>  	err = register_netdevice(dev);
>  	if (err < 0)
> -		goto out_uninit_applicant;
> +		goto out_upper_dev_unlink;
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
see below:

>  
>  	/* Account for reference in struct vlan_dev_priv */
>  	dev_hold(real_dev);
> @@ -180,6 +186,8 @@ int register_vlan_dev(struct net_device *dev)
>  
>  	return 0;
>  
> +upper_dev_unlink:
^^^^^^^^^^^^^^^^^^^
should be out_upper_dev_unlink:

fbl

> +	netdev_upper_dev_unlink(real_dev, dev);
>  out_uninit_applicant:
>  	if (grp->nr_vlan_devs == 0)
>  		vlan_gvrp_uninit_applicant(real_dev);

^ permalink raw reply

* Re: [PATCH] netvm: check for page == NULL when propogating the skb->pfmemalloc flag
From: Jeremy Fitzhardinge @ 2012-08-13 18:56 UTC (permalink / raw)
  To: Mel Gorman
  Cc: linux-mm, linux-kernel, netdev, xen-devel, konrad, Ian.Campbell,
	David Miller, akpm
In-Reply-To: <20120813104745.GE4177@suse.de>

On 08/13/2012 03:47 AM, Mel Gorman wrote:
> Resending to correct Jeremy's address.
>
> On Wed, Aug 08, 2012 at 03:50:46PM -0700, David Miller wrote:
>> From: Mel Gorman <mgorman@suse.de>
>> Date: Tue, 7 Aug 2012 09:55:55 +0100
>>
>>> Commit [c48a11c7: netvm: propagate page->pfmemalloc to skb] is responsible
>>> for the following bug triggered by a xen network driver
>>  ...
>>> The problem is that the xenfront driver is passing a NULL page to
>>> __skb_fill_page_desc() which was unexpected. This patch checks that
>>> there is a page before dereferencing.
>>>
>>> Reported-and-Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
>>> Signed-off-by: Mel Gorman <mgorman@suse.de>
>> That call to __skb_fill_page_desc() in xen-netfront.c looks completely bogus.
>> It's the only driver passing NULL here.
>>
>> That whole song and dance figuring out what to do with the head
>> fragment page, depending upon whether the length is greater than the
>> RX_COPY_THRESHOLD, is completely unnecessary.
>>
>> Just use something like a call to __pskb_pull_tail(skb, len) and all
>> that other crap around that area can simply be deleted.
> I looked at this for a while but I did not see how __pskb_pull_tail()
> could be used sensibly but I'm simily not familiar with writing network
> device drivers or Xen.
>
> This messing with RX_COPY_THRESHOLD seems to be related to how the frontend
> and backend communicate (maybe some fixed limitation of the xenbus). The
> existing code looks like it is trying to take the fragments received and
> pass them straight to the backend without copying by passing the fragments
> to the backend without copying. I worry that if I try converting this to
> __pskb_pull_tail() that it would either hit the limitation of xenbus or
> introduce copying where it is not wanted.
>
> I'm going to have to punt this to Jeremy and the other Xen folk as I'm not
> sure what the original intention was and I don't have a Xen setup anywhere
> to test any patch. Jeremy, xen folk? 

It's been a while since I've looked at that stuff, but as I remember,
the issue is that since the packet ring memory is shared with another
domain which may be untrustworthy, we want to make copies of the headers
before making any decisions based on them so that the other domain can't
change them after header processing but before they're actually sent. 
(The packet payload is considered less important, but of course the same
issue applies if you're using some kind of content-aware packet filter.)

So that's the rationale for always copying RX_COPY_THRESHOLD, even if
the packet is larger than that amount.  As far as I know, changing this
behaviour wouldn't break the ring protocol, but it does introduce a
potential security issue.

    J

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [RFC PATCH 0/2] net: connect to UNIX sockets from specified root
From: J. Bruce Fields @ 2012-08-13 18:24 UTC (permalink / raw)
  To: Stanislav Kinsbursky
  Cc: Pavel Emelianov, H. Peter Anvin, Alan Cox,
	Trond.Myklebust@netapp.com, davem@davemloft.net,
	linux-nfs@vger.kernel.org, eric.dumazet@gmail.com,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	viro@zeniv.linux.org.uk, tim.c.chen@linux.intel.com,
	devel@openvz.org
In-Reply-To: <50293BE9.3010408@parallels.com>

On Mon, Aug 13, 2012 at 09:39:53PM +0400, Stanislav Kinsbursky wrote:
> 13.08.2012 20:47, J. Bruce Fields пишет:
> >On Sat, Aug 11, 2012 at 03:15:24PM +0400, Stanislav Kinsbursky wrote:
> >>11.08.2012 10:23, Pavel Emelyanov пишет:
> >>>On 08/11/2012 03:09 AM, H. Peter Anvin wrote:
> >>>>On 08/10/2012 12:28 PM, Alan Cox wrote:
> >>>>>Explicitly for Linux yes - this is not generally true of the AF_UNIX
> >>>>>socket domain and even the permissions aspect isn't guaranteed to be
> >>>>>supported on some BSD environments !
> >>>>Yes, but let's worry about what the Linux behavior should be.
> >>>>
> >>>>>The name is however just a proxy for the socket itself. You don't even
> >>>>>get a device node in the usual sense or the same inode in the file system
> >>>>>space.
> >>>>No, but it is looked up the same way any other inode is (the difference
> >>>>between FIFOs and sockets is that sockets have separate connections,
> >>>>which is also why open() on sockets would be nice.)
> >>>>
> >>>>However, there is a fundamental difference between AF_UNIX sockets and
> >>>>open(), and that is how the pathname is delivered.  It thus would make
> >>>>more sense to provide the openat()-like information in struct
> >>>>sockaddr_un, but that may be very hard to do in a sensible way.  In that
> >>>>sense it perhaps would be cleaner to be able to do an open[at]() on the
> >>>>socket node with O_PATH (perhaps there should be an O_SOCKET option,
> >>>>even?) and pass the resulting file descriptor to bind() or connect().
> >>>I vote for this (openat + O_WHATEVER on a unix socket) as well. It will
> >>>help us in checkpoint-restore, making handling of overmounted/unlinked
> >>>sockets much cleaner.
> >>I have to notice, that it's not enough and doesn't solve the issue.
> >>There should be some way how to connect/bind already existent unix
> >>socket (from kernel, at least), because socket can be created in
> >>user space.
> >>And this way (sock operation or whatever) have to provide an ability
> >>to lookup UNIX socket starting from specified root to support
> >>containers.
> >I don't understand--the rpcbind sockets are created by the kernel.  What
> >am I missing?
> 
> Kernel preform connect to rpcbind socket (i.e. user-space binds it),
> doesn't it?

I'm confused, possibly because there are three "sockets" here: the
client-side socket that's connected, the server-side socket that's
bound, and the common object that exists in the filesystem namespace.

Userland creates the server-side socket and binds to it.  All of that is
done in the context of the rpcbind process, so is created in rpcbind's
namespace.  That should be OK, right?

The client side socket is created and connected in
xs_local_setup_socket().

Making sure they both end up with the same thing is a matter of making
sure they lookup the same path in the same namespace.  The difficult
part of that is the in-kernel client-side socket connect, where we don't
have the right process context any more.

We currently set that up with __sock_create followed by
kernel_connect.

The proposal seems to be to instead do an openat followed by a
kernel_connect, and pass the path in the openat instead of the connect.

(Though in the kernel we won't be able to call openat, so we'll end up
doing something like nfsd does (calling lookup_one_len() and
dentry_open() by hand).)

Have I got all that right?

I don't know if that's better just calling into the unix socket code at
connect time as your patch does.  Maybe the answer depends on whether
it's a priority to make this functionality available to userspace.

--b.

^ permalink raw reply

* Re: [patch net-next 01/16] net: introduce upper device lists
From: Flavio Leitner @ 2012-08-13 17:52 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, davem, edumazet, faisal.latif, roland, sean.hefty,
	hal.rosenstock, fubar, andy, divy, jitendra.kalsaria, sony.chacko,
	linux-driver, kaber, ursula.braun, blaschka, linux390, shemminger,
	bhutchings, therbert, xiyou.wangcong, joe, gregory.v.rose,
	john.r.fastabend, linux-rdma, linux-kernel, linux-s390, bridge
In-Reply-To: <1344871635-1052-2-git-send-email-jiri@resnulli.us>

On Mon, 13 Aug 2012 17:27:00 +0200
Jiri Pirko <jiri@resnulli.us> wrote:

> This lists are supposed to serve for storing pointers to all upper devices.
> Eventually it will replace dev->master pointer which is used for
> bonding, bridge, team but it cannot be used for vlan, macvlan where
> there might be multiple "masters" present.
> 
> New upper device list resolves this limitation. Also, the information
> stored in lists is used for preventing looping setups like
> "bond->somethingelse->samebond"
> 
> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> ---
>  include/linux/netdevice.h |   14 +++
>  net/core/dev.c            |  232 ++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 244 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index a9db4f3..e7a07f8 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1173,6 +1173,8 @@ struct net_device {
>  					  * which this device is member of.
>  					  */
>  
> +	struct list_head	upper_dev_list; /* List of upper devices */
> +
>  	/* Interface address info used in eth_type_trans() */
>  	unsigned char		*dev_addr;	/* hw address, (before bcast
>  						   because most packets are
> @@ -2611,6 +2613,18 @@ extern int		netdev_max_backlog;
>  extern int		netdev_tstamp_prequeue;
>  extern int		weight_p;
>  extern int		bpf_jit_enable;
> +
> +extern bool netdev_has_upper_dev(struct net_device *dev,
> +				 struct net_device *upper_dev);
> +extern bool netdev_has_any_upper_dev(struct net_device *dev);
> +extern struct net_device *netdev_unique_upper_dev_get(struct net_device *dev);
> +extern struct net_device *netdev_unique_upper_dev_get_rcu(struct net_device *dev);
> +extern int netdev_upper_dev_link(struct net_device *dev,
> +				 struct net_device *upper_dev);
> +extern int netdev_unique_upper_dev_link(struct net_device *dev,
> +					struct net_device *upper_dev);
> +extern void netdev_upper_dev_unlink(struct net_device *dev,
> +				    struct net_device *upper_dev);
>  extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
>  extern int netdev_set_bond_master(struct net_device *dev,
>  				  struct net_device *master);
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 1f06df8..68db1ac 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -4425,6 +4425,229 @@ static int __init dev_proc_init(void)
>  #endif	/* CONFIG_PROC_FS */
>  
>  
> +struct netdev_upper {
> +	struct net_device *dev;
> +	bool unique;

unique is quite confusing here. I see that it is possible to have 
one unique and many non-unique linked in the list, so maybe rename
to 'main_dev', 'master' or 'principal'...


> +	struct list_head list;
> +	struct rcu_head rcu;
> +};
> +
> +static bool __netdev_has_upper_dev(struct net_device *dev,
> +				   struct net_device *upper_dev,
> +				   bool deep)
> +{
> +	struct netdev_upper *upper;
> +
> +	list_for_each_entry(upper, &dev->upper_dev_list, list) {
> +		if (upper->dev == upper_dev)
> +			return true;
> +		if (deep && __netdev_has_upper_dev(upper->dev, upper_dev, deep))
> +			return true;
> +	}
> +	return false;
> +}
> +
> +static struct netdev_upper *__netdev_find_upper(struct net_device *dev,
> +						struct net_device *upper_dev)
> +{
> +	struct netdev_upper *upper;
> +
> +	list_for_each_entry(upper, &dev->upper_dev_list, list) {
> +		if (upper->dev == upper_dev)
> +			return upper;
> +	}
> +	return NULL;
> +}
> +
> +/**
> + * netdev_has_upper_dev - Check if device is linked to an upper device
> + * @dev: device
> + * @upper_dev: upper device to check
> + *
> + * Find out if a device is linked to specified upper device and return true
> + * in case it is. The caller must hold the RTNL semaphore.
> + */
> +bool netdev_has_upper_dev(struct net_device *dev,
> +			  struct net_device *upper_dev)
> +{
> +	ASSERT_RTNL();
> +
> +	return __netdev_has_upper_dev(dev, upper_dev, false);
> +}
> +EXPORT_SYMBOL(netdev_has_upper_dev);
> +
> +/**
> + * netdev_has_any_upper_dev - Check if device is linked to some device
> + * @dev: device
> + *
> + * Find out if a device is linked to an upper device and return true in case
> + * it is. The caller must hold the RTNL semaphore.
> + */
> +bool netdev_has_any_upper_dev(struct net_device *dev)
> +{
> +	ASSERT_RTNL();
> +
> +	return !list_empty(&dev->upper_dev_list);
> +}
> +EXPORT_SYMBOL(netdev_has_any_upper_dev);
> +
> +/**
> + * netdev_unique_upper_dev_get - Get unique upper device
> + * @dev: device
> + *
> + * Find a unique upper device and return pointer to it or NULL in case
> + * it's not there. The caller must hold the RTNL semaphore.
> + */
> +struct net_device *netdev_unique_upper_dev_get(struct net_device *dev)
> +{
> +	struct netdev_upper *upper;
> +
> +	ASSERT_RTNL();
> +
> +	if (list_empty(&dev->upper_dev_list))
> +		return NULL;
> +
> +	upper = list_first_entry(&dev->upper_dev_list,
> +				 struct netdev_upper, list);
> +	if (likely(upper->unique))
> +		return upper->dev;
> +	return NULL;
> +}
> +EXPORT_SYMBOL(netdev_unique_upper_dev_get);
> +
> +/**
> + * netdev_unique_upper_dev_get_rcu - Get unique upper device
> + * @dev: device
> + *
> + * Find a unique upper device and return pointer to it or NULL in case
> + * it's not there. The caller must hold the RCU read lock.
> + */
> +struct net_device *netdev_unique_upper_dev_get_rcu(struct net_device *dev)
> +{
> +	struct netdev_upper *upper;
> +
> +	upper = list_first_or_null_rcu(&dev->upper_dev_list,
> +				       struct netdev_upper, list);
> +	if (likely(upper->unique))

It will oopses here if 'upper' is NULL (i.e. no upper devices).


> +		return upper->dev;
> +	return NULL;
> +}
> +EXPORT_SYMBOL(netdev_unique_upper_dev_get_rcu);
> +
> +static int __netdev_upper_dev_link(struct net_device *dev,
> +				   struct net_device *upper_dev, bool unique)
> +{
> +	struct netdev_upper *upper;
> +
> +	ASSERT_RTNL();
> +
> +	if (dev == upper_dev)
> +		return -EBUSY;
> +	/*
> +	 * To prevent loops, check if dev is not upper device to upper_dev.
> +	 */
> +	if (__netdev_has_upper_dev(upper_dev, dev, true))
> +		return -EBUSY;
> +
> +	if (__netdev_find_upper(dev, upper_dev))
> +		return -EEXIST;

__netdev_has_upper_dev() can go all the way up finding the device and
the __netdev_find_upper() just check the first level.

I think it would be better to use:
__netdev_find_upper_dev(,,deep=true/false)
__netdev_has_upper(,)

thanks,
fbl

> +	if (unique && netdev_unique_upper_dev_get(dev))
> +		return -EBUSY;
> +
> +	upper = kmalloc(sizeof(*upper), GFP_KERNEL);
> +	if (!upper)
> +		return -ENOMEM;
> +
> +	upper->dev = upper_dev;
> +	upper->unique = unique;
> +
> +	/*
> +	 * Ensure that unique upper link is always the first item in the list.
> +	 */
> +	if (unique)
> +		list_add_rcu(&upper->list, &dev->upper_dev_list);
> +	else
> +		list_add_tail_rcu(&upper->list, &dev->upper_dev_list);
> +	dev_hold(upper_dev);
> +
> +	return 0;
> +}
> +/**
> + * netdev_upper_dev_link - Add a link to the upper device
> + * @dev: device
> + * @upper_dev: new upper device
> + *
> + * Adds a link to device which is upper to this one. The caller must hold
> + * the RTNL semaphore. On a failure a negative errno code is returned.
> + * On success the reference counts are adjusted and the function
> + * returns zero.
> + */
> +int netdev_upper_dev_link(struct net_device *dev,
> +			  struct net_device *upper_dev)
> +{
> +	return __netdev_upper_dev_link(dev, upper_dev, false);
> +}
> +EXPORT_SYMBOL(netdev_upper_dev_link);
> +
> +/**
> + * netdev_unique_upper_dev_link - Add a unique link to the upper device
> + * @dev: device
> + * @upper_dev: new upper device
> + *
> + * Adds a link to device which is upper to this one. In this case, only
> + * one unique upper device can be linked, although other non-unique devices
> + * might be linked as well. The caller must hold the RTNL semaphore.
> + * On a failure a negative errno code is returned. On success the reference
> + * counts are adjusted and the function returns zero.
> + */
> +int netdev_unique_upper_dev_link(struct net_device *dev,
> +				 struct net_device *upper_dev)
> +{
> +	return __netdev_upper_dev_link(dev, upper_dev, true);
> +}
> +EXPORT_SYMBOL(netdev_unique_upper_dev_link);
> +
> +/**
> + * netdev_upper_free_rcu - Frees a upper device list item via the RCU pointer
> + * @entry: the entry's RCU field
> + *
> + * This function is designed to be used as a callback to the call_rcu()
> + * function so that the memory allocated to the netdev upper device list item
> + * can be released safely.
> + */
> +static void netdev_upper_free_rcu(struct rcu_head *entry)
> +{
> +	struct netdev_upper *upper;
> +
> +	upper = container_of(entry, struct netdev_upper, rcu);
> +	kfree(upper);
> +}
> +
> +/**
> + * netdev_upper_dev_unlink - Removes a link to upper device
> + * @dev: device
> + * @upper_dev: new upper device
> + *
> + * Removes a link to device which is upper to this one. The caller must hold
> + * the RTNL semaphore.
> + */
> +void netdev_upper_dev_unlink(struct net_device *dev,
> +			     struct net_device *upper_dev)
> +{
> +	struct netdev_upper *upper;
> +
> +	ASSERT_RTNL();
> +
> +	upper = __netdev_find_upper(dev, upper_dev);
> +	if (!upper)
> +		return;
> +	list_del_rcu(&upper->list);
> +	dev_put(upper_dev);
> +	call_rcu(&upper->rcu, netdev_upper_free_rcu);
> +}
> +EXPORT_SYMBOL(netdev_upper_dev_unlink);
> +
>  /**
>   *	netdev_set_master	-	set up master pointer
>   *	@slave: slave device
> @@ -4438,19 +4661,23 @@ static int __init dev_proc_init(void)
>  int netdev_set_master(struct net_device *slave, struct net_device *master)
>  {
>  	struct net_device *old = slave->master;
> +	int err;
>  
>  	ASSERT_RTNL();
>  
>  	if (master) {
>  		if (old)
>  			return -EBUSY;
> -		dev_hold(master);
> +		err = netdev_unique_upper_dev_link(slave, master);
> +		if (err)
> +			return err;
>  	}
>  
>  	slave->master = master;
>  
>  	if (old)
> -		dev_put(old);
> +		netdev_upper_dev_unlink(slave, master);
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(netdev_set_master);
> @@ -5999,6 +6226,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
>  	INIT_LIST_HEAD(&dev->napi_list);
>  	INIT_LIST_HEAD(&dev->unreg_list);
>  	INIT_LIST_HEAD(&dev->link_watch_list);
> +	INIT_LIST_HEAD(&dev->upper_dev_list);
>  	dev->priv_flags = IFF_XMIT_DST_RELEASE;
>  	setup(dev);
>  

^ permalink raw reply

* Re: [RFC PATCH 0/2] net: connect to UNIX sockets from specified root
From: Stanislav Kinsbursky @ 2012-08-13 17:39 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Pavel Emelianov, H. Peter Anvin, Alan Cox,
	Trond.Myklebust@netapp.com, davem@davemloft.net,
	linux-nfs@vger.kernel.org, eric.dumazet@gmail.com,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	viro@zeniv.linux.org.uk, tim.c.chen@linux.intel.com,
	devel@openvz.org
In-Reply-To: <20120813164730.GB2497@fieldses.org>

13.08.2012 20:47, J. Bruce Fields пишет:
> On Sat, Aug 11, 2012 at 03:15:24PM +0400, Stanislav Kinsbursky wrote:
>> 11.08.2012 10:23, Pavel Emelyanov пишет:
>>> On 08/11/2012 03:09 AM, H. Peter Anvin wrote:
>>>> On 08/10/2012 12:28 PM, Alan Cox wrote:
>>>>> Explicitly for Linux yes - this is not generally true of the AF_UNIX
>>>>> socket domain and even the permissions aspect isn't guaranteed to be
>>>>> supported on some BSD environments !
>>>> Yes, but let's worry about what the Linux behavior should be.
>>>>
>>>>> The name is however just a proxy for the socket itself. You don't even
>>>>> get a device node in the usual sense or the same inode in the file system
>>>>> space.
>>>> No, but it is looked up the same way any other inode is (the difference
>>>> between FIFOs and sockets is that sockets have separate connections,
>>>> which is also why open() on sockets would be nice.)
>>>>
>>>> However, there is a fundamental difference between AF_UNIX sockets and
>>>> open(), and that is how the pathname is delivered.  It thus would make
>>>> more sense to provide the openat()-like information in struct
>>>> sockaddr_un, but that may be very hard to do in a sensible way.  In that
>>>> sense it perhaps would be cleaner to be able to do an open[at]() on the
>>>> socket node with O_PATH (perhaps there should be an O_SOCKET option,
>>>> even?) and pass the resulting file descriptor to bind() or connect().
>>> I vote for this (openat + O_WHATEVER on a unix socket) as well. It will
>>> help us in checkpoint-restore, making handling of overmounted/unlinked
>>> sockets much cleaner.
>> I have to notice, that it's not enough and doesn't solve the issue.
>> There should be some way how to connect/bind already existent unix
>> socket (from kernel, at least), because socket can be created in
>> user space.
>> And this way (sock operation or whatever) have to provide an ability
>> to lookup UNIX socket starting from specified root to support
>> containers.
> I don't understand--the rpcbind sockets are created by the kernel.  What
> am I missing?

Kernel preform connect to rpcbind socket (i.e. user-space binds it), 
doesn't it?

>
> --b.

^ permalink raw reply

* Re: [patch net-next 15/16] net: remove usage of dev->master
From: Jiri Pirko @ 2012-08-13 17:31 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	edumazet-hpIqsD4AKlfQT0dZR+AlfA,
	faisal.latif-ral2JQCrhuEAvxtiuMwx3w,
	roland-DgEjT+Ai2ygdnm+yROfE0A, sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
	hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
	fubar-r/Jw6+rmf7HQT0dZR+AlfA, andy-QlMahl40kYEqcZcGjlUOXw,
	divy-ut6Up61K2wZBDgjK7y7TUQ,
	jitendra.kalsaria-h88ZbnxC6KDQT0dZR+AlfA,
	sony.chacko-h88ZbnxC6KDQT0dZR+AlfA,
	linux-driver-h88ZbnxC6KDQT0dZR+AlfA, kaber-dcUjhNyLwpNeoWH0uzbU5w,
	ursula.braun-tA70FqPdS9bQT0dZR+AlfA,
	blaschka-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
	linux390-tA70FqPdS9bQT0dZR+AlfA,
	shemminger-ZtmgI6mnKB3QT0dZR+AlfA,
	therbert-hpIqsD4AKlfQT0dZR+AlfA,
	xiyou.wangcong-Re5JQEeQqe8AvxtiuMwx3w, joe-6d6DIl74uiNBDgjK7y7TUQ,
	gregory.v.rose-ral2JQCrhuEAvxtiuMwx3w,
	john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-s390-u79uwXL29TY76Z2rM5mHXA,
	bridge-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	fbl-H+wXaHxf7aLQT0dZR+AlfA
In-Reply-To: <1344878131.2733.28.camel-/LGg1Z1CJKReKY3V0RtoKmatzQS1i7+A3tAM5lWOD0I@public.gmane.org>

Mon, Aug 13, 2012 at 07:15:31PM CEST, bhutchings-s/n/eUQHGBpZroRs9YW3xA@public.gmane.org wrote:
>On Mon, 2012-08-13 at 17:27 +0200, Jiri Pirko wrote:
>> Signed-off-by: Jiri Pirko <jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>
>> ---
>>  net/core/dev.c |    4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>> 
>> diff --git a/net/core/dev.c b/net/core/dev.c
>> index c0f9adb..8977404 100644
>> --- a/net/core/dev.c
>> +++ b/net/core/dev.c
>> @@ -5461,8 +5461,8 @@ static void rollback_registered_many(struct list_head *head)
>>  		if (dev->netdev_ops->ndo_uninit)
>>  			dev->netdev_ops->ndo_uninit(dev);
>>  
>> -		/* Notifier chain MUST detach us from master device. */
>> -		WARN_ON(dev->master);
>> +		/* Notifier chain MUST detach us all upper devices. */
>> +		WARN_ON(netdev_has_any_upper_dev(dev));
>>  
>>  		/* Remove entries from kobject tree */
>>  		netdev_unregister_kobject(dev);
>
>I think this should be folded into patch 1, since that already ensures
>that any master device is included in the upper device list.

Right, I will squash it into patch 1

>
>Ben.
>
>-- 
>Ben Hutchings, Staff Engineer, Solarflare
>Not speaking for my employer; that's the marketing department's job.
>They asked us to note that Solarflare product names are trademarked.
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [flame^Wreview] net: netprio_cgroup: rework update socket logic
From: John Fastabend @ 2012-08-13 17:31 UTC (permalink / raw)
  To: Al Viro; +Cc: netdev, David Miller, Neil Horman, linux-kernel
In-Reply-To: <20120813170109.GD23464@ZenIV.linux.org.uk>

On 8/13/2012 10:01 AM, Al Viro wrote:
> On Mon, Aug 13, 2012 at 09:58:12AM -0700, John Fastabend wrote:
>> [...]
>>
>>> HOWEVER, it still doesn't address more fundamental problem - somebody
>>> creating a socket and passing it to you in SCM_RIGHTS datagram will
>>> leave you with a socket you can do IO on, still tagged according to who
>>> had created it.
>>>
>>> AFAICS, the whole point of that exercise was to allow third-party changing
>>> the priorities of traffic on sockets already created by a process we now
>>> move to a different cgroup.  Consider e.g. this:
>>
>> Correct that is the point of the exercise.
>>
>> To fix this specific case we could add a call to sock_update_netprioidx
>> in scm_recv to set the sk_cgrp_prioidx value.
>
> On every received descriptor, that is?  Eeek...
>

We are already iterating through the files in scm_detach_fds called from
scm_recv(). This would be an extra (file->f_op == &socket_file_ops)
check here and then the sock update.

^ permalink raw reply

* Re: [patch net-next 01/16] net: introduce upper device lists
From: Jiri Pirko @ 2012-08-13 17:31 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: netdev, davem, edumazet, faisal.latif, roland, sean.hefty,
	hal.rosenstock, fubar, andy, divy, jitendra.kalsaria, sony.chacko,
	linux-driver, kaber, ursula.braun, blaschka, linux390, shemminger,
	therbert, xiyou.wangcong, joe, gregory.v.rose, john.r.fastabend,
	linux-rdma, linux-kernel, linux-s390, bridge, fbl
In-Reply-To: <1344877451.2733.26.camel@bwh-desktop.uk.solarflarecom.com>

Mon, Aug 13, 2012 at 07:04:11PM CEST, bhutchings@solarflare.com wrote:
>On Mon, 2012-08-13 at 17:27 +0200, Jiri Pirko wrote:
>> This lists are supposed to serve for storing pointers to all upper devices.
>> Eventually it will replace dev->master pointer which is used for
>> bonding, bridge, team but it cannot be used for vlan, macvlan where
>> there might be multiple "masters" present.
>> 
>> New upper device list resolves this limitation. Also, the information
>> stored in lists is used for preventing looping setups like
>> "bond->somethingelse->samebond"
>> 
>> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
>[...]
>> --- a/net/core/dev.c
>> +++ b/net/core/dev.c
>> @@ -4425,6 +4425,229 @@ static int __init dev_proc_init(void)
>>  #endif	/* CONFIG_PROC_FS */
>>  
>> 
>> +struct netdev_upper {
>> +	struct net_device *dev;
>> +	bool unique;
>
>This needs a better name.  It doesn't really have anything to do with
>uniqueness and doesn't ensure exclusivity.  I think that it would be
>fine to keep the 'master' term.

Hmm. I admit that "unique" I do not like too much as well. But "master"
I like even less.

This flag should ensure exclusivity. Only one upper device with this
flag can be present at a time.

>
>> +	struct list_head list;
>> +	struct rcu_head rcu;
>> +};
>[...]
>> +static int __netdev_upper_dev_link(struct net_device *dev,
>> +				   struct net_device *upper_dev, bool unique)
>> +{
>> +	struct netdev_upper *upper;
>> +
>> +	ASSERT_RTNL();
>> +
>> +	if (dev == upper_dev)
>> +		return -EBUSY;
>> +	/*
>> +	 * To prevent loops, check if dev is not upper device to upper_dev.
>> +	 */
>> +	if (__netdev_has_upper_dev(upper_dev, dev, true))
>> +		return -EBUSY;
>> +
>> +	if (__netdev_find_upper(dev, upper_dev))
>> +		return -EEXIST;
>> +
>> +	if (unique && netdev_unique_upper_dev_get(dev))
>> +		return -EBUSY;
>> +
>> +	upper = kmalloc(sizeof(*upper), GFP_KERNEL);
>> +	if (!upper)
>> +		return -ENOMEM;
>> +
>> +	upper->dev = upper_dev;
>> +	upper->unique = unique;
>> +
>> +	/*
>> +	 * Ensure that unique upper link is always the first item in the list.
>> +	 */
>> +	if (unique)
>> +		list_add_rcu(&upper->list, &dev->upper_dev_list);
>> +	else
>> +		list_add_tail_rcu(&upper->list, &dev->upper_dev_list);
>> +	dev_hold(upper_dev);
>
>This behaviour (calling dev_hold()) matches netdev_set_master().  But
>it's oddly asymmetric: generally the administrator can remove either the
>upper device or the lower device (rtnl_link_ops or unbinding a physical
>device) and the upper device driver must then unlink itself from the
>lower device (using a notifier to catch lower device removal).
>
>If the upper device driver fails to unlink when the upper device is
>unregistered, then this extra reference causes netdev_wait_allrefs() to
>hang... is that the intent?  Or should there be a more explicit counter
>and check on unregistration, e.g. WARN_ON(dev->num_lower_devs != 0)?
>

I'm not sure I understand you. I believe that upper device notifier
should take care of the unlink. This behaviour is unchanged by the
patch.



>If it fails to unlink when the lower device is removed, this warning in
>rollback_registered_many() may be triggered:
>
>		/* Notifier chain MUST detach us from master device. */
>		WARN_ON(dev->master);
>
>I think that needs to become WARN_ON(netdev_has_upper_dev(dev)).

Patch 15

>
>> +	return 0;
>> +}
>[...] 
>
>-- 
>Ben Hutchings, Staff Engineer, Solarflare
>Not speaking for my employer; that's the marketing department's job.
>They asked us to note that Solarflare product names are trademarked.
>

^ permalink raw reply

* Re: [patch net-next 15/16] net: remove usage of dev->master
From: Ben Hutchings @ 2012-08-13 17:15 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	edumazet-hpIqsD4AKlfQT0dZR+AlfA,
	faisal.latif-ral2JQCrhuEAvxtiuMwx3w,
	roland-DgEjT+Ai2ygdnm+yROfE0A, sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
	hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
	fubar-r/Jw6+rmf7HQT0dZR+AlfA, andy-QlMahl40kYEqcZcGjlUOXw,
	divy-ut6Up61K2wZBDgjK7y7TUQ,
	jitendra.kalsaria-h88ZbnxC6KDQT0dZR+AlfA,
	sony.chacko-h88ZbnxC6KDQT0dZR+AlfA,
	linux-driver-h88ZbnxC6KDQT0dZR+AlfA, kaber-dcUjhNyLwpNeoWH0uzbU5w,
	ursula.braun-tA70FqPdS9bQT0dZR+AlfA,
	blaschka-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
	linux390-tA70FqPdS9bQT0dZR+AlfA,
	shemminger-ZtmgI6mnKB3QT0dZR+AlfA,
	therbert-hpIqsD4AKlfQT0dZR+AlfA,
	xiyou.wangcong-Re5JQEeQqe8AvxtiuMwx3w, joe-6d6DIl74uiNBDgjK7y7TUQ,
	gregory.v.rose-ral2JQCrhuEAvxtiuMwx3w,
	john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-s390-u79uwXL29TY76Z2rM5mHXA,
	bridge-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	fbl-H+wXaHxf7aLQT0dZR+AlfA
In-Reply-To: <1344871635-1052-16-git-send-email-jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>

On Mon, 2012-08-13 at 17:27 +0200, Jiri Pirko wrote:
> Signed-off-by: Jiri Pirko <jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>
> ---
>  net/core/dev.c |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/core/dev.c b/net/core/dev.c
> index c0f9adb..8977404 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -5461,8 +5461,8 @@ static void rollback_registered_many(struct list_head *head)
>  		if (dev->netdev_ops->ndo_uninit)
>  			dev->netdev_ops->ndo_uninit(dev);
>  
> -		/* Notifier chain MUST detach us from master device. */
> -		WARN_ON(dev->master);
> +		/* Notifier chain MUST detach us all upper devices. */
> +		WARN_ON(netdev_has_any_upper_dev(dev));
>  
>  		/* Remove entries from kobject tree */
>  		netdev_unregister_kobject(dev);

I think this should be folded into patch 1, since that already ensures
that any master device is included in the upper device list.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [patch net-next 01/16] net: introduce upper device lists
From: Ben Hutchings @ 2012-08-13 17:04 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	edumazet-hpIqsD4AKlfQT0dZR+AlfA,
	faisal.latif-ral2JQCrhuEAvxtiuMwx3w,
	roland-DgEjT+Ai2ygdnm+yROfE0A, sean.hefty-ral2JQCrhuEAvxtiuMwx3w,
	hal.rosenstock-Re5JQEeQqe8AvxtiuMwx3w,
	fubar-r/Jw6+rmf7HQT0dZR+AlfA, andy-QlMahl40kYEqcZcGjlUOXw,
	divy-ut6Up61K2wZBDgjK7y7TUQ,
	jitendra.kalsaria-h88ZbnxC6KDQT0dZR+AlfA,
	sony.chacko-h88ZbnxC6KDQT0dZR+AlfA,
	linux-driver-h88ZbnxC6KDQT0dZR+AlfA, kaber-dcUjhNyLwpNeoWH0uzbU5w,
	ursula.braun-tA70FqPdS9bQT0dZR+AlfA,
	blaschka-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8,
	linux390-tA70FqPdS9bQT0dZR+AlfA,
	shemminger-ZtmgI6mnKB3QT0dZR+AlfA,
	therbert-hpIqsD4AKlfQT0dZR+AlfA,
	xiyou.wangcong-Re5JQEeQqe8AvxtiuMwx3w, joe-6d6DIl74uiNBDgjK7y7TUQ,
	gregory.v.rose-ral2JQCrhuEAvxtiuMwx3w,
	john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-s390-u79uwXL29TY76Z2rM5mHXA,
	bridge-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	fbl-H+wXaHxf7aLQT0dZR+AlfA
In-Reply-To: <1344871635-1052-2-git-send-email-jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>

On Mon, 2012-08-13 at 17:27 +0200, Jiri Pirko wrote:
> This lists are supposed to serve for storing pointers to all upper devices.
> Eventually it will replace dev->master pointer which is used for
> bonding, bridge, team but it cannot be used for vlan, macvlan where
> there might be multiple "masters" present.
> 
> New upper device list resolves this limitation. Also, the information
> stored in lists is used for preventing looping setups like
> "bond->somethingelse->samebond"
> 
> Signed-off-by: Jiri Pirko <jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>
[...]
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -4425,6 +4425,229 @@ static int __init dev_proc_init(void)
>  #endif	/* CONFIG_PROC_FS */
>  
> 
> +struct netdev_upper {
> +	struct net_device *dev;
> +	bool unique;

This needs a better name.  It doesn't really have anything to do with
uniqueness and doesn't ensure exclusivity.  I think that it would be
fine to keep the 'master' term.

> +	struct list_head list;
> +	struct rcu_head rcu;
> +};
[...]
> +static int __netdev_upper_dev_link(struct net_device *dev,
> +				   struct net_device *upper_dev, bool unique)
> +{
> +	struct netdev_upper *upper;
> +
> +	ASSERT_RTNL();
> +
> +	if (dev == upper_dev)
> +		return -EBUSY;
> +	/*
> +	 * To prevent loops, check if dev is not upper device to upper_dev.
> +	 */
> +	if (__netdev_has_upper_dev(upper_dev, dev, true))
> +		return -EBUSY;
> +
> +	if (__netdev_find_upper(dev, upper_dev))
> +		return -EEXIST;
> +
> +	if (unique && netdev_unique_upper_dev_get(dev))
> +		return -EBUSY;
> +
> +	upper = kmalloc(sizeof(*upper), GFP_KERNEL);
> +	if (!upper)
> +		return -ENOMEM;
> +
> +	upper->dev = upper_dev;
> +	upper->unique = unique;
> +
> +	/*
> +	 * Ensure that unique upper link is always the first item in the list.
> +	 */
> +	if (unique)
> +		list_add_rcu(&upper->list, &dev->upper_dev_list);
> +	else
> +		list_add_tail_rcu(&upper->list, &dev->upper_dev_list);
> +	dev_hold(upper_dev);

This behaviour (calling dev_hold()) matches netdev_set_master().  But
it's oddly asymmetric: generally the administrator can remove either the
upper device or the lower device (rtnl_link_ops or unbinding a physical
device) and the upper device driver must then unlink itself from the
lower device (using a notifier to catch lower device removal).

If the upper device driver fails to unlink when the upper device is
unregistered, then this extra reference causes netdev_wait_allrefs() to
hang... is that the intent?  Or should there be a more explicit counter
and check on unregistration, e.g. WARN_ON(dev->num_lower_devs != 0)?

If it fails to unlink when the lower device is removed, this warning in
rollback_registered_many() may be triggered:

		/* Notifier chain MUST detach us from master device. */
		WARN_ON(dev->master);

I think that needs to become WARN_ON(netdev_has_upper_dev(dev)).

> +	return 0;
> +}
[...] 

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [flame^Wreview] net: netprio_cgroup: rework update socket logic
From: Al Viro @ 2012-08-13 17:01 UTC (permalink / raw)
  To: John Fastabend; +Cc: netdev, David Miller, Neil Horman, linux-kernel
In-Reply-To: <50293224.90803@intel.com>

On Mon, Aug 13, 2012 at 09:58:12AM -0700, John Fastabend wrote:
> [...]
> 
> >HOWEVER, it still doesn't address more fundamental problem - somebody
> >creating a socket and passing it to you in SCM_RIGHTS datagram will
> >leave you with a socket you can do IO on, still tagged according to who
> >had created it.
> >
> >AFAICS, the whole point of that exercise was to allow third-party changing
> >the priorities of traffic on sockets already created by a process we now
> >move to a different cgroup.  Consider e.g. this:
> 
> Correct that is the point of the exercise.
> 
> To fix this specific case we could add a call to sock_update_netprioidx
> in scm_recv to set the sk_cgrp_prioidx value.

On every received descriptor, that is?  Eeek...

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox