2012-08-13 20:19:38

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 01/21] userns: Convert net/core/scm.c to use kuids and kgids

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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


2012-08-13 20:20:19

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 05/21] userns: Make seq_file's user namespace accessible

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: KAMEZAWA Hiroyuki <[email protected]>
Cc: Alexey Dobriyan <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:20:37

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 10/21] userns: Convert net/ax25 to use kuid_t where appropriate

From: "Eric W. Biederman" <[email protected]>

Cc: Ralf Baechle <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
include/net/ax25.h | 4 ++--
init/Kconfig | 1 -
net/ax25/ax25_uid.c | 21 ++++++++++++++-------
3 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/include/net/ax25.h b/include/net/ax25.h
index 5d23521..53539ac 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -157,7 +157,7 @@ enum {
typedef struct ax25_uid_assoc {
struct hlist_node uid_node;
atomic_t refcount;
- uid_t uid;
+ kuid_t uid;
ax25_address call;
} ax25_uid_assoc;

@@ -434,7 +434,7 @@ extern unsigned long ax25_display_timer(struct timer_list *);

/* ax25_uid.c */
extern int ax25_uid_policy;
-extern ax25_uid_assoc *ax25_findbyuid(uid_t);
+extern ax25_uid_assoc *ax25_findbyuid(kuid_t);
extern int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *);
extern const struct file_operations ax25_uid_fops;
extern void ax25_uid_free(void);
diff --git a/init/Kconfig b/init/Kconfig
index 64ff9ce..8447e0c 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -952,7 +952,6 @@ config UIDGID_CONVERTED
depends on NET_KEY = n
depends on INET_DIAG = n
depends on DNS_RESOLVER = n
- depends on AX25 = n

# Filesystems
depends on USB_GADGETFS = n
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index e3c579b..957999e 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -51,14 +51,14 @@ int ax25_uid_policy;

EXPORT_SYMBOL(ax25_uid_policy);

-ax25_uid_assoc *ax25_findbyuid(uid_t uid)
+ax25_uid_assoc *ax25_findbyuid(kuid_t uid)
{
ax25_uid_assoc *ax25_uid, *res = NULL;
struct hlist_node *node;

read_lock(&ax25_uid_lock);
ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
- if (ax25_uid->uid == uid) {
+ if (uid_eq(ax25_uid->uid, uid)) {
ax25_uid_hold(ax25_uid);
res = ax25_uid;
break;
@@ -84,7 +84,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
read_lock(&ax25_uid_lock);
ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
- res = ax25_uid->uid;
+ res = from_kuid_munged(current_user_ns(), ax25_uid->uid);
break;
}
}
@@ -93,9 +93,14 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return res;

case SIOCAX25ADDUID:
+ {
+ kuid_t sax25_kuid;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- user = ax25_findbyuid(sax->sax25_uid);
+ sax25_kuid = make_kuid(current_user_ns(), sax->sax25_uid);
+ if (!uid_valid(sax25_kuid))
+ return -EINVAL;
+ user = ax25_findbyuid(sax25_kuid);
if (user) {
ax25_uid_put(user);
return -EEXIST;
@@ -106,7 +111,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return -ENOMEM;

atomic_set(&ax25_uid->refcount, 1);
- ax25_uid->uid = sax->sax25_uid;
+ ax25_uid->uid = sax25_kuid;
ax25_uid->call = sax->sax25_call;

write_lock(&ax25_uid_lock);
@@ -114,7 +119,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
write_unlock(&ax25_uid_lock);

return 0;
-
+ }
case SIOCAX25DELUID:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -172,7 +177,9 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v)
struct ax25_uid_assoc *pt;

pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
- seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call));
+ seq_printf(seq, "%6d %s\n",
+ from_kuid_munged(seq_user_ns(seq), pt->uid),
+ ax2asc(buf, &pt->call));
}
return 0;
}
--
1.7.5.4

2012-08-13 20:24:27

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 16/21] userns: Convert cls_flow to work with user namespaces enabled

From: "Eric W. Biederman" <[email protected]>

The flow classifier can use uids and gids of the sockets that
are transmitting packets and do insert those uids and gids
into the packet classification calcuation. I don't fully
understand the details but it appears that we can depend
on specific uids and gids when making traffic classification
decisions.

To work with user namespaces enabled map from kuids and kgids
into uids and gids in the initial user namespace giving raw
integer values the code can play with and depend on.

To avoid issues of userspace depending on uids and gids in
packet classifiers installed from other user namespaces
and getting confused deny all packet classifiers that
use uids or gids that are not comming from a netlink socket
in the initial user namespace.

Cc: Patrick McHardy <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jamal Hadi Salim <[email protected]>
Cc: Changli Gao <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
init/Kconfig | 1 -
net/sched/cls_flow.c | 16 ++++++++++++----
2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 2660b31..b44c3a3 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -943,7 +943,6 @@ config UIDGID_CONVERTED

# Networking
depends on NET_9P = n
- depends on NET_CLS_FLOW = n
depends on NETFILTER_XT_MATCH_OWNER = n
depends on NETFILTER_XT_MATCH_RECENT = n
depends on NETFILTER_XT_TARGET_LOG = n
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index ae854f3..ce82d0c 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -193,15 +193,19 @@ static u32 flow_get_rtclassid(const struct sk_buff *skb)

static u32 flow_get_skuid(const struct sk_buff *skb)
{
- if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
- return skb->sk->sk_socket->file->f_cred->fsuid;
+ if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) {
+ kuid_t skuid = skb->sk->sk_socket->file->f_cred->fsuid;
+ return from_kuid(&init_user_ns, skuid);
+ }
return 0;
}

static u32 flow_get_skgid(const struct sk_buff *skb)
{
- if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file)
- return skb->sk->sk_socket->file->f_cred->fsgid;
+ if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) {
+ kgid_t skgid = skb->sk->sk_socket->file->f_cred->fsgid;
+ return from_kgid(&init_user_ns, skgid);
+ }
return 0;
}

@@ -387,6 +391,10 @@ static int flow_change(struct sk_buff *in_skb,

if (fls(keymask) - 1 > FLOW_KEY_MAX)
return -EOPNOTSUPP;
+
+ if ((keymask & (FLOW_KEY_SKUID|FLOW_KEY_SKGID)) &&
+ sk_user_ns(NETLINK_CB(in_skb).ssk) != &init_user_ns)
+ return -EOPNOTSUPP;
}

err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);
--
1.7.5.4

2012-08-13 20:24:37

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 17/21] userns: Convert xt_LOG to print socket kuids and kgids as uids and gids

From: "Eric W. Biederman" <[email protected]>

xt_LOG always writes messages via sb_add via printk. Therefore when
xt_LOG logs the uid and gid of a socket a packet came from the
values should be converted to be in the initial user namespace.

Thus making xt_LOG as user namespace safe as possible.

Cc: Pablo Neira Ayuso <[email protected]>
Cc: Patrick McHardy <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
init/Kconfig | 1 -
net/netfilter/xt_LOG.c | 16 ++++++++++------
2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index b44c3a3..c8911eb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -945,7 +945,6 @@ config UIDGID_CONVERTED
depends on NET_9P = n
depends on NETFILTER_XT_MATCH_OWNER = n
depends on NETFILTER_XT_MATCH_RECENT = n
- depends on NETFILTER_XT_TARGET_LOG = n
depends on AF_RXRPC = n
depends on NET_KEY = n
depends on DNS_RESOLVER = n
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c
index ff5f75f..02a2bf4 100644
--- a/net/netfilter/xt_LOG.c
+++ b/net/netfilter/xt_LOG.c
@@ -363,10 +363,12 @@ static void dump_ipv4_packet(struct sbuff *m,
/* Max length: 15 "UID=4294967295 " */
if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
- if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+ if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
+ const struct cred *cred = skb->sk->sk_socket->file->f_cred;
sb_add(m, "UID=%u GID=%u ",
- skb->sk->sk_socket->file->f_cred->fsuid,
- skb->sk->sk_socket->file->f_cred->fsgid);
+ from_kuid_munged(&init_user_ns, cred->fsuid),
+ from_kgid_munged(&init_user_ns, cred->fsgid));
+ }
read_unlock_bh(&skb->sk->sk_callback_lock);
}

@@ -719,10 +721,12 @@ static void dump_ipv6_packet(struct sbuff *m,
/* Max length: 15 "UID=4294967295 " */
if ((logflags & XT_LOG_UID) && recurse && skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
- if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+ if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
+ const struct cred *cred = skb->sk->sk_socket->file->f_cred;
sb_add(m, "UID=%u GID=%u ",
- skb->sk->sk_socket->file->f_cred->fsuid,
- skb->sk->sk_socket->file->f_cred->fsgid);
+ from_kuid_munged(&init_user_ns, cred->fsuid),
+ from_kgid_munged(&init_user_ns, cred->fsgid));
+ }
read_unlock_bh(&skb->sk->sk_callback_lock);
}

--
1.7.5.4

2012-08-13 20:26:40

by Rémi Denis-Courmont

[permalink] [raw]
Subject: Re: [PATCH 06/21] userns: Print out socket uids in a user namespace aware fashion.

Le lundi 13 ao?t 2012 23:18:20, vous avez ?crit :
> From: "Eric W. Biederman" <[email protected]>
>
> Cc: David Miller <[email protected]>
> Cc: Alexey Kuznetsov <[email protected]>
> Cc: James Morris <[email protected]>
> Cc: Hideaki YOSHIFUJI <[email protected]>
> Cc: Patrick McHardy <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: Vlad Yasevich <[email protected]>
> Cc: Sridhar Samudrala <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>
> Signed-off-by: Eric W. Biederman <[email protected]>

FWIW, ...

Acked-By: R?mi Denis-Courmont <[email protected]>

--
R?mi Denis-Courmont
C/C++ software engineer looking for a job
http://www.linkedin.com/in/remidenis

2012-08-13 20:24:34

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 19/21] userns: xt_owner: Add basic user namespace support.

From: "Eric W. Biederman" <[email protected]>

- Only allow adding matches from the initial user namespace
- Add the appropriate conversion functions to handle matches
against sockets in other user namespaces.

Cc: Jan Engelhardt <[email protected]>
Cc: Patrick McHardy <[email protected]>
Cc: Pablo Neira Ayuso <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
init/Kconfig | 1 -
net/netfilter/xt_owner.c | 30 ++++++++++++++++++++++++------
2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 40f5020..76ffca9 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -943,7 +943,6 @@ config UIDGID_CONVERTED

# Networking
depends on NET_9P = n
- depends on NETFILTER_XT_MATCH_OWNER = n
depends on AF_RXRPC = n
depends on NET_KEY = n
depends on DNS_RESOLVER = n
diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
index 772d738..ca2e577 100644
--- a/net/netfilter/xt_owner.c
+++ b/net/netfilter/xt_owner.c
@@ -17,6 +17,17 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_owner.h>

+static int owner_check(const struct xt_mtchk_param *par)
+{
+ struct xt_owner_match_info *info = par->matchinfo;
+
+ /* For now only allow adding matches from the initial user namespace */
+ if ((info->match & (XT_OWNER_UID|XT_OWNER_GID)) &&
+ (current_user_ns() != &init_user_ns))
+ return -EINVAL;
+ return 0;
+}
+
static bool
owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
@@ -37,17 +48,23 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
return ((info->match ^ info->invert) &
(XT_OWNER_UID | XT_OWNER_GID)) == 0;

- if (info->match & XT_OWNER_UID)
- if ((filp->f_cred->fsuid >= info->uid_min &&
- filp->f_cred->fsuid <= info->uid_max) ^
+ if (info->match & XT_OWNER_UID) {
+ kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min);
+ kuid_t uid_max = make_kuid(&init_user_ns, info->uid_max);
+ if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
+ uid_lte(filp->f_cred->fsuid, uid_max)) ^
!(info->invert & XT_OWNER_UID))
return false;
+ }

- if (info->match & XT_OWNER_GID)
- if ((filp->f_cred->fsgid >= info->gid_min &&
- filp->f_cred->fsgid <= info->gid_max) ^
+ if (info->match & XT_OWNER_GID) {
+ kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min);
+ kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max);
+ if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
+ gid_lte(filp->f_cred->fsgid, gid_max)) ^
!(info->invert & XT_OWNER_GID))
return false;
+ }

return true;
}
@@ -56,6 +73,7 @@ static struct xt_match owner_mt_reg __read_mostly = {
.name = "owner",
.revision = 1,
.family = NFPROTO_UNSPEC,
+ .checkentry = owner_check,
.match = owner_mt,
.matchsize = sizeof(struct xt_owner_match_info),
.hooks = (1 << NF_INET_LOCAL_OUT) |
--
1.7.5.4

2012-08-13 20:24:31

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 20/21] userns: Make the airo wireless driver use kuids for proc uids and gids

From: "Eric W. Biederman" <[email protected]>

Cc: Dan Carpenter <[email protected]>
Cc: Alexey Dobriyan <[email protected]>
Cc: John W. Linville <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
drivers/net/wireless/airo.c | 48 +++++++++++++++++++++++++-----------------
init/Kconfig | 2 -
2 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index f9f15bb..c586f78 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -232,8 +232,10 @@ static int adhoc;

static int probe = 1;

+static kuid_t proc_kuid;
static int proc_uid /* = 0 */;

+static kgid_t proc_kgid;
static int proc_gid /* = 0 */;

static int airo_perm = 0555;
@@ -4499,78 +4501,79 @@ struct proc_data {
static int setup_proc_entry( struct net_device *dev,
struct airo_info *apriv ) {
struct proc_dir_entry *entry;
+
/* First setup the device directory */
strcpy(apriv->proc_name,dev->name);
apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
airo_entry);
if (!apriv->proc_entry)
goto fail;
- apriv->proc_entry->uid = proc_uid;
- apriv->proc_entry->gid = proc_gid;
+ apriv->proc_entry->uid = proc_kuid;
+ apriv->proc_entry->gid = proc_kgid;

/* Setup the StatsDelta */
entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry)
goto fail_stats_delta;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the Stats */
entry = proc_create_data("Stats", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_stats_ops, dev);
if (!entry)
goto fail_stats;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the Status */
entry = proc_create_data("Status", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_status_ops, dev);
if (!entry)
goto fail_status;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the Config */
entry = proc_create_data("Config", proc_perm,
apriv->proc_entry, &proc_config_ops, dev);
if (!entry)
goto fail_config;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the SSID */
entry = proc_create_data("SSID", proc_perm,
apriv->proc_entry, &proc_SSID_ops, dev);
if (!entry)
goto fail_ssid;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the APList */
entry = proc_create_data("APList", proc_perm,
apriv->proc_entry, &proc_APList_ops, dev);
if (!entry)
goto fail_aplist;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the BSSList */
entry = proc_create_data("BSSList", proc_perm,
apriv->proc_entry, &proc_BSSList_ops, dev);
if (!entry)
goto fail_bsslist;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

/* Setup the WepKey */
entry = proc_create_data("WepKey", proc_perm,
apriv->proc_entry, &proc_wepkey_ops, dev);
if (!entry)
goto fail_wepkey;
- entry->uid = proc_uid;
- entry->gid = proc_gid;
+ entry->uid = proc_kuid;
+ entry->gid = proc_kgid;

return 0;

@@ -5697,11 +5700,16 @@ static int __init airo_init_module( void )
{
int i;

+ proc_kuid = make_kuid(&init_user_ns, proc_uid);
+ proc_kgid = make_kgid(&init_user_ns, proc_gid);
+ if (!uid_valid(proc_kuid) || !gid_valid(proc_kgid))
+ return -EINVAL;
+
airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);

if (airo_entry) {
- airo_entry->uid = proc_uid;
- airo_entry->gid = proc_gid;
+ airo_entry->uid = proc_kuid;
+ airo_entry->gid = proc_kgid;
}

for (i = 0; i < 4 && io[i] && irq[i]; i++) {
diff --git a/init/Kconfig b/init/Kconfig
index 76ffca9..eac23a6 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1003,8 +1003,6 @@ config UIDGID_CONVERTED
depends on !UML || HOSTFS = n

# The rare drivers that won't build
- depends on AIRO = n
- depends on AIRO_CS = n
depends on TUN = n
depends on INFINIBAND_QIB = n
depends on BLK_DEV_LOOP = n
--
1.7.5.4

2012-08-13 20:24:23

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 12/21] userns: Implement sk_user_ns

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:32:30

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 18/21] userns xt_recent: Specify the owner/group of ip_list_perms in the initial user namespace

From: "Eric W. Biederman" <[email protected]>

xt_recent creates a bunch of proc files and initializes their uid
and gids to the values of ip_list_uid and ip_list_gid. When
initialize those proc files convert those values to kuids so they
can continue to reside on the /proc inode.

Cc: Pablo Neira Ayuso <[email protected]>
Cc: Patrick McHardy <[email protected]>
Cc: Jan Engelhardt <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
init/Kconfig | 1 -
net/netfilter/xt_recent.c | 13 +++++++++++--
2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index c8911eb..40f5020 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -944,7 +944,6 @@ config UIDGID_CONVERTED
# Networking
depends on NET_9P = n
depends on NETFILTER_XT_MATCH_OWNER = n
- depends on NETFILTER_XT_MATCH_RECENT = n
depends on AF_RXRPC = n
depends on NET_KEY = n
depends on DNS_RESOLVER = n
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index ae2ad1e..4635c9b 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -317,6 +317,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
struct recent_table *t;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pde;
+ kuid_t uid;
+ kgid_t gid;
#endif
unsigned int i;
int ret = -EINVAL;
@@ -372,6 +374,13 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
for (i = 0; i < ip_list_hash_size; i++)
INIT_LIST_HEAD(&t->iphash[i]);
#ifdef CONFIG_PROC_FS
+ uid = make_kuid(&init_user_ns, ip_list_uid);
+ gid = make_kgid(&init_user_ns, ip_list_gid);
+ if (!uid_valid(uid) || !gid_valid(gid)) {
+ kfree(t);
+ ret = -EINVAL;
+ goto out;
+ }
pde = proc_create_data(t->name, ip_list_perms, recent_net->xt_recent,
&recent_mt_fops, t);
if (pde == NULL) {
@@ -379,8 +388,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
ret = -ENOMEM;
goto out;
}
- pde->uid = ip_list_uid;
- pde->gid = ip_list_gid;
+ pde->uid = uid;
+ pde->gid = gid;
#endif
spin_lock_bh(&recent_lock);
list_add_tail(&t->list, &recent_net->tables);
--
1.7.5.4

2012-08-13 20:32:28

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 11/21] netlink: Make the sending netlink socket availabe in NETLINK_CB

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:32:26

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 21/21] userns: Convert tun/tap to use kuid and kgid where appropriate

From: "Eric W. Biederman" <[email protected]>

Cc: Maxim Krasnyansky <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
drivers/net/tun.c | 46 ++++++++++++++++++++++++++++++++--------------
init/Kconfig | 1 -
2 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 926d4db..a9bd9f3 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -120,8 +120,8 @@ struct tun_sock;
struct tun_struct {
struct tun_file *tfile;
unsigned int flags;
- uid_t owner;
- gid_t group;
+ kuid_t owner;
+ kgid_t group;

struct net_device *dev;
netdev_features_t set_features;
@@ -1032,8 +1032,8 @@ static void tun_setup(struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);

- tun->owner = -1;
- tun->group = -1;
+ tun->owner = INVALID_UID;
+ tun->group = INVALID_GID;

dev->ethtool_ops = &tun_ethtool_ops;
dev->destructor = tun_free_netdev;
@@ -1156,14 +1156,20 @@ static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
- return sprintf(buf, "%d\n", tun->owner);
+ return uid_valid(tun->owner)?
+ sprintf(buf, "%u\n",
+ from_kuid_munged(current_user_ns(), tun->owner)):
+ sprintf(buf, "-1\n");
}

static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct tun_struct *tun = netdev_priv(to_net_dev(dev));
- return sprintf(buf, "%d\n", tun->group);
+ return gid_valid(tun->group) ?
+ sprintf(buf, "%u\n",
+ from_kgid_munged(current_user_ns(), tun->group)):
+ sprintf(buf, "-1\n");
}

static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL);
@@ -1190,8 +1196,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
else
return -EINVAL;

- if (((tun->owner != -1 && cred->euid != tun->owner) ||
- (tun->group != -1 && !in_egroup_p(tun->group))) &&
+ if (((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) ||
+ (gid_valid(tun->group) && !in_egroup_p(tun->group))) &&
!capable(CAP_NET_ADMIN))
return -EPERM;
err = security_tun_dev_attach(tun->socket.sk);
@@ -1375,6 +1381,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
void __user* argp = (void __user*)arg;
struct sock_fprog fprog;
struct ifreq ifr;
+ kuid_t owner;
+ kgid_t group;
int sndbuf;
int vnet_hdr_sz;
int ret;
@@ -1448,16 +1456,26 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,

case TUNSETOWNER:
/* Set owner of the device */
- tun->owner = (uid_t) arg;
-
- tun_debug(KERN_INFO, tun, "owner set to %d\n", tun->owner);
+ owner = make_kuid(current_user_ns(), arg);
+ if (!uid_valid(owner)) {
+ ret = -EINVAL;
+ break;
+ }
+ tun->owner = owner;
+ tun_debug(KERN_INFO, tun, "owner set to %d\n",
+ from_kuid(&init_user_ns, tun->owner));
break;

case TUNSETGROUP:
/* Set group of the device */
- tun->group= (gid_t) arg;
-
- tun_debug(KERN_INFO, tun, "group set to %d\n", tun->group);
+ group = make_kgid(current_user_ns(), arg);
+ if (!gid_valid(group)) {
+ ret = -EINVAL;
+ break;
+ }
+ tun->group = group;
+ tun_debug(KERN_INFO, tun, "group set to %d\n",
+ from_kgid(&init_user_ns, tun->group));
break;

case TUNSETLINK:
diff --git a/init/Kconfig b/init/Kconfig
index eac23a6..b445d6f 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1003,7 +1003,6 @@ config UIDGID_CONVERTED
depends on !UML || HOSTFS = n

# The rare drivers that won't build
- depends on TUN = n
depends on INFINIBAND_QIB = n
depends on BLK_DEV_LOOP = n
depends on ANDROID_BINDER_IPC = n
--
1.7.5.4

2012-08-13 20:33:24

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 15/21] net sched: Pass the skb into change so it can access NETLINK_CB

From: "Eric W. Biederman" <[email protected]>

cls_flow.c plays with uids and gids. Unless I misread that
code it is possible for classifiers to depend on the specific uid and
gid values. Therefore I need to know the user namespace of the
netlink socket that is installing the packet classifiers. Pass
in the rtnetlink skb so I can access the NETLINK_CB of the passed
packet. In particular I want access to sk_user_ns(NETLINK_CB(in_skb).ssk).

Pass in not the user namespace but the incomming rtnetlink skb into
the the classifier change routines as that is generally the more useful
parameter.

Cc: Jamal Hadi Salim <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
include/net/sch_generic.h | 3 ++-
net/sched/cls_api.c | 2 +-
net/sched/cls_basic.c | 3 ++-
net/sched/cls_cgroup.c | 3 ++-
net/sched/cls_flow.c | 3 ++-
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 ++-
10 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index d9611e0..4616f46 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -188,7 +188,8 @@ struct tcf_proto_ops {

unsigned long (*get)(struct tcf_proto*, u32 handle);
void (*put)(struct tcf_proto*, unsigned long);
- int (*change)(struct tcf_proto*, unsigned long,
+ int (*change)(struct sk_buff *,
+ struct tcf_proto*, unsigned long,
u32 handle, struct nlattr **,
unsigned long *);
int (*delete)(struct tcf_proto*, unsigned long);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 6dd1131..dc3ef5a 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -319,7 +319,7 @@ replay:
}
}

- err = tp->ops->change(tp, cl, t->tcm_handle, tca, &fh);
+ err = tp->ops->change(skb, tp, cl, t->tcm_handle, tca, &fh);
if (err == 0) {
if (tp_created) {
spin_lock_bh(root_lock);
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index 590960a..344a11b 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -162,7 +162,8 @@ errout:
return err;
}

-static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle,
+static int basic_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base, u32 handle,
struct nlattr **tca, unsigned long *arg)
{
int err;
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 7743ea8..91de666 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -151,7 +151,8 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
[TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED },
};

-static int cls_cgroup_change(struct tcf_proto *tp, unsigned long base,
+static int cls_cgroup_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base,
u32 handle, struct nlattr **tca,
unsigned long *arg)
{
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index ccd08c8..ae854f3 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -347,7 +347,8 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
[TCA_FLOW_PERTURB] = { .type = NLA_U32 },
};

-static int flow_change(struct tcf_proto *tp, unsigned long base,
+static int flow_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base,
u32 handle, struct nlattr **tca,
unsigned long *arg)
{
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 8384a47..4075a0a 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -233,7 +233,8 @@ errout:
return err;
}

-static int fw_change(struct tcf_proto *tp, unsigned long base,
+static int fw_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base,
u32 handle,
struct nlattr **tca,
unsigned long *arg)
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index 44f405c..c10d57b 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -427,7 +427,8 @@ errout:
return err;
}

-static int route4_change(struct tcf_proto *tp, unsigned long base,
+static int route4_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base,
u32 handle,
struct nlattr **tca,
unsigned long *arg)
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index 18ab93e..494bbb9 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -416,7 +416,8 @@ static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
[TCA_RSVP_PINFO] = { .len = sizeof(struct tc_rsvp_pinfo) },
};

-static int rsvp_change(struct tcf_proto *tp, unsigned long base,
+static int rsvp_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base,
u32 handle,
struct nlattr **tca,
unsigned long *arg)
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index fe29420..a1293b4 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -332,7 +332,8 @@ errout:
}

static int
-tcindex_change(struct tcf_proto *tp, unsigned long base, u32 handle,
+tcindex_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base, u32 handle,
struct nlattr **tca, unsigned long *arg)
{
struct nlattr *opt = tca[TCA_OPTIONS];
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index d45373f..c7c27bc 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -544,7 +544,8 @@ errout:
return err;
}

-static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle,
+static int u32_change(struct sk_buff *in_skb,
+ struct tcf_proto *tp, unsigned long base, u32 handle,
struct nlattr **tca,
unsigned long *arg)
{
--
1.7.5.4

2012-08-13 20:33:21

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 13/21] userns: Teach inet_diag to work with user namespaces

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Cc: Pavel Emelyanov <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:34:13

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 14/21] userns: nfnetlink_log: Report socket uids in the log sockets user namespace

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:45:21

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 09/21] pidns: Export free_pid_ns

From: "Eric W. Biederman" <[email protected]>

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" <[email protected]>
---
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

2012-08-13 20:46:13

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 06/21] userns: Print out socket uids in a user namespace aware fashion.

From: "Eric W. Biederman" <[email protected]>

Cc: David Miller <[email protected]>
Cc: Alexey Kuznetsov <[email protected]>
Cc: James Morris <[email protected]>
Cc: Hideaki YOSHIFUJI <[email protected]>
Cc: Patrick McHardy <[email protected]>
Cc: Remi Denis-Courmont <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Vlad Yasevich <[email protected]>
Cc: Sridhar Samudrala <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:46:09

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 08/21] net ip6 flowlabel: Make owner a union of struct pid * and kuid_t

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:47:18

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 07/21] userns: Use kgids for sysctl_ping_group_range

From: "Eric W. Biederman" <[email protected]>

- 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 <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:20:15

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 04/21] userns: Allow USER_NS and NET simultaneously in Kconfig

From: "Eric W. Biederman" <[email protected]>

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 <[email protected]>
---
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

2012-08-13 20:20:11

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 03/21] userns: Convert sock_i_uid to return a kuid_t

From: "Eric W. Biederman" <[email protected]>

Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Eric W. Biederman <[email protected]>
---
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

2012-08-13 20:20:08

by Eric W. Biederman

[permalink] [raw]
Subject: [PATCH 02/21] userns: Convert __dev_set_promiscuity to use kuids in audit logs

From: "Eric W. Biederman" <[email protected]>

Cc: Klaus Heinrich Kiwi <[email protected]>
Cc: Eric Paris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: "Eric W. Biederman" <[email protected]>
---
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

2012-08-14 08:35:42

by Pavel Emelyanov

[permalink] [raw]
Subject: Re: [PATCH 13/21] userns: Teach inet_diag to work with user namespaces

On 08/14/2012 12:18 AM, Eric W. Biederman wrote:
> From: "Eric W. Biederman" <[email protected]>
>
> 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 <[email protected]>
> Cc: Pavel Emelyanov <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>
> Signed-off-by: Eric W. Biederman <[email protected]>

Acked-by: Pavel Emelyanov <[email protected]>

2012-08-15 03:22:53

by Vlad Yasevich

[permalink] [raw]
Subject: Re: [PATCH 06/21] userns: Print out socket uids in a user namespace aware fashion.

On 08/13/2012 04:18 PM, Eric W. Biederman wrote:
> From: "Eric W. Biederman" <[email protected]>
>
> Cc: David Miller <[email protected]>
> Cc: Alexey Kuznetsov <[email protected]>
> Cc: James Morris <[email protected]>
> Cc: Hideaki YOSHIFUJI <[email protected]>
> Cc: Patrick McHardy <[email protected]>
> Cc: Remi Denis-Courmont <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: Vlad Yasevich <[email protected]>
> Cc: Sridhar Samudrala <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>
> Signed-off-by: Eric W. Biederman <[email protected]>

ACK sctp parts

Acked-by: Vlad Yasevich <[email protected]>

> ---
> 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, " ");
>

2012-08-15 04:47:19

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 06/21] userns: Print out socket uids in a user namespace aware fashion.

"Rémi Denis-Courmont" <[email protected]> writes:

> Le lundi 13 août 2012 23:18:20, vous avez écrit :
>> From: "Eric W. Biederman" <[email protected]>
>>
>> Cc: David Miller <[email protected]>
>> Cc: Alexey Kuznetsov <[email protected]>
>> Cc: James Morris <[email protected]>
>> Cc: Hideaki YOSHIFUJI <[email protected]>
>> Cc: Patrick McHardy <[email protected]>
>> Cc: Arnaldo Carvalho de Melo <[email protected]>
>> Cc: Vlad Yasevich <[email protected]>
>> Cc: Sridhar Samudrala <[email protected]>
>> Acked-by: Serge Hallyn <[email protected]>
>> Signed-off-by: Eric W. Biederman <[email protected]>
>
> FWIW, ...

Well I will take every bit of review I can get. It can be terribly
embarrassing to discover you messed up uid/gid handling and no one
noticed the security hole for 3 kernel releases...

> Acked-By: Rémi Denis-Courmont <[email protected]>

2012-08-15 08:20:20

by Jamal Hadi Salim

[permalink] [raw]
Subject: Re: [PATCH 15/21] net sched: Pass the skb into change so it can access NETLINK_CB

On Mon, 2012-08-13 at 13:18 -0700, Eric W. Biederman wrote:
> From: "Eric W. Biederman" <[email protected]>
>
> cls_flow.c plays with uids and gids. Unless I misread that
> code it is possible for classifiers to depend on the specific uid and
> gid values. Therefore I need to know the user namespace of the
> netlink socket that is installing the packet classifiers. Pass
> in the rtnetlink skb so I can access the NETLINK_CB of the passed
> packet. In particular I want access to sk_user_ns(NETLINK_CB(in_skb).ssk).
>
> Pass in not the user namespace but the incomming rtnetlink skb into
> the the classifier change routines as that is generally the more useful
> parameter.
>
> Cc: Jamal Hadi Salim <[email protected]>
> Acked-by: Serge Hallyn <[email protected]>
> Signed-off-by: Eric W. Biederman <[email protected]>


Acked-by: Jamal Hadi Salim <[email protected]>

cheers,
jamal

2012-08-20 18:09:31

by Vasily Kulikov

[permalink] [raw]
Subject: Re: [PATCH 07/21] userns: Use kgids for sysctl_ping_group_range

On Mon, Aug 13, 2012 at 13:18 -0700, Eric W. Biederman wrote:
> From: "Eric W. Biederman" <[email protected]>
>
> - 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 <[email protected]>
> Signed-off-by: Eric W. Biederman <[email protected]>

Looks good.

Acked-by: Vasiliy Kulikov <[email protected]>

Thanks,

--
Vasiliy Kulikov
http://www.openwall.com - bringing security into open computing environments