Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

This is an initial merge in of Eric Biederman's work to start adding
user namespace support to the networking.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2012-08-24 18:54:37 -04:00
commit e6acb38480
52 changed files with 368 additions and 180 deletions

View File

@ -120,8 +120,8 @@ struct tun_sock;
struct tun_struct { struct tun_struct {
struct tun_file *tfile; struct tun_file *tfile;
unsigned int flags; unsigned int flags;
uid_t owner; kuid_t owner;
gid_t group; kgid_t group;
struct net_device *dev; struct net_device *dev;
netdev_features_t set_features; netdev_features_t set_features;
@ -1031,8 +1031,8 @@ static void tun_setup(struct net_device *dev)
{ {
struct tun_struct *tun = netdev_priv(dev); struct tun_struct *tun = netdev_priv(dev);
tun->owner = -1; tun->owner = INVALID_UID;
tun->group = -1; tun->group = INVALID_GID;
dev->ethtool_ops = &tun_ethtool_ops; dev->ethtool_ops = &tun_ethtool_ops;
dev->destructor = tun_free_netdev; dev->destructor = tun_free_netdev;
@ -1155,14 +1155,20 @@ static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct tun_struct *tun = netdev_priv(to_net_dev(dev)); 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, static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct tun_struct *tun = netdev_priv(to_net_dev(dev)); 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); static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL);
@ -1189,8 +1195,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
else else
return -EINVAL; return -EINVAL;
if (((tun->owner != -1 && cred->euid != tun->owner) || if (((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) ||
(tun->group != -1 && !in_egroup_p(tun->group))) && (gid_valid(tun->group) && !in_egroup_p(tun->group))) &&
!capable(CAP_NET_ADMIN)) !capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
err = security_tun_dev_attach(tun->socket.sk); err = security_tun_dev_attach(tun->socket.sk);
@ -1374,6 +1380,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
void __user* argp = (void __user*)arg; void __user* argp = (void __user*)arg;
struct sock_fprog fprog; struct sock_fprog fprog;
struct ifreq ifr; struct ifreq ifr;
kuid_t owner;
kgid_t group;
int sndbuf; int sndbuf;
int vnet_hdr_sz; int vnet_hdr_sz;
int ret; int ret;
@ -1447,16 +1455,26 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case TUNSETOWNER: case TUNSETOWNER:
/* Set owner of the device */ /* Set owner of the device */
tun->owner = (uid_t) arg; owner = make_kuid(current_user_ns(), arg);
if (!uid_valid(owner)) {
tun_debug(KERN_INFO, tun, "owner set to %d\n", tun->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; break;
case TUNSETGROUP: case TUNSETGROUP:
/* Set group of the device */ /* Set group of the device */
tun->group= (gid_t) arg; group = make_kgid(current_user_ns(), arg);
if (!gid_valid(group)) {
tun_debug(KERN_INFO, tun, "group set to %d\n", tun->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; break;
case TUNSETLINK: case TUNSETLINK:

View File

@ -232,8 +232,10 @@ static int adhoc;
static int probe = 1; static int probe = 1;
static kuid_t proc_kuid;
static int proc_uid /* = 0 */; static int proc_uid /* = 0 */;
static kgid_t proc_kgid;
static int proc_gid /* = 0 */; static int proc_gid /* = 0 */;
static int airo_perm = 0555; static int airo_perm = 0555;
@ -4499,78 +4501,79 @@ struct proc_data {
static int setup_proc_entry( struct net_device *dev, static int setup_proc_entry( struct net_device *dev,
struct airo_info *apriv ) { struct airo_info *apriv ) {
struct proc_dir_entry *entry; struct proc_dir_entry *entry;
/* First setup the device directory */ /* First setup the device directory */
strcpy(apriv->proc_name,dev->name); strcpy(apriv->proc_name,dev->name);
apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm, apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
airo_entry); airo_entry);
if (!apriv->proc_entry) if (!apriv->proc_entry)
goto fail; goto fail;
apriv->proc_entry->uid = proc_uid; apriv->proc_entry->uid = proc_kuid;
apriv->proc_entry->gid = proc_gid; apriv->proc_entry->gid = proc_kgid;
/* Setup the StatsDelta */ /* Setup the StatsDelta */
entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm, entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_statsdelta_ops, dev); apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry) if (!entry)
goto fail_stats_delta; goto fail_stats_delta;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the Stats */ /* Setup the Stats */
entry = proc_create_data("Stats", S_IRUGO & proc_perm, entry = proc_create_data("Stats", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_stats_ops, dev); apriv->proc_entry, &proc_stats_ops, dev);
if (!entry) if (!entry)
goto fail_stats; goto fail_stats;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the Status */ /* Setup the Status */
entry = proc_create_data("Status", S_IRUGO & proc_perm, entry = proc_create_data("Status", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_status_ops, dev); apriv->proc_entry, &proc_status_ops, dev);
if (!entry) if (!entry)
goto fail_status; goto fail_status;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the Config */ /* Setup the Config */
entry = proc_create_data("Config", proc_perm, entry = proc_create_data("Config", proc_perm,
apriv->proc_entry, &proc_config_ops, dev); apriv->proc_entry, &proc_config_ops, dev);
if (!entry) if (!entry)
goto fail_config; goto fail_config;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the SSID */ /* Setup the SSID */
entry = proc_create_data("SSID", proc_perm, entry = proc_create_data("SSID", proc_perm,
apriv->proc_entry, &proc_SSID_ops, dev); apriv->proc_entry, &proc_SSID_ops, dev);
if (!entry) if (!entry)
goto fail_ssid; goto fail_ssid;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the APList */ /* Setup the APList */
entry = proc_create_data("APList", proc_perm, entry = proc_create_data("APList", proc_perm,
apriv->proc_entry, &proc_APList_ops, dev); apriv->proc_entry, &proc_APList_ops, dev);
if (!entry) if (!entry)
goto fail_aplist; goto fail_aplist;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the BSSList */ /* Setup the BSSList */
entry = proc_create_data("BSSList", proc_perm, entry = proc_create_data("BSSList", proc_perm,
apriv->proc_entry, &proc_BSSList_ops, dev); apriv->proc_entry, &proc_BSSList_ops, dev);
if (!entry) if (!entry)
goto fail_bsslist; goto fail_bsslist;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
/* Setup the WepKey */ /* Setup the WepKey */
entry = proc_create_data("WepKey", proc_perm, entry = proc_create_data("WepKey", proc_perm,
apriv->proc_entry, &proc_wepkey_ops, dev); apriv->proc_entry, &proc_wepkey_ops, dev);
if (!entry) if (!entry)
goto fail_wepkey; goto fail_wepkey;
entry->uid = proc_uid; entry->uid = proc_kuid;
entry->gid = proc_gid; entry->gid = proc_kgid;
return 0; return 0;
@ -5697,11 +5700,16 @@ static int __init airo_init_module( void )
{ {
int i; 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); airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);
if (airo_entry) { if (airo_entry) {
airo_entry->uid = proc_uid; airo_entry->uid = proc_kuid;
airo_entry->gid = proc_gid; airo_entry->gid = proc_kgid;
} }
for (i = 0; i < 4 && io[i] && irq[i]; i++) { for (i = 0; i < 4 && io[i] && irq[i]; i++) {

View File

@ -678,7 +678,7 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd)
/* Allowed if owner and follower match. */ /* Allowed if owner and follower match. */
inode = link->dentry->d_inode; inode = link->dentry->d_inode;
if (current_cred()->fsuid == inode->i_uid) if (uid_eq(current_cred()->fsuid, inode->i_uid))
return 0; return 0;
/* Allowed if parent directory not sticky and world-writable. */ /* Allowed if parent directory not sticky and world-writable. */
@ -687,7 +687,7 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd)
return 0; return 0;
/* Allowed if parent directory and link owner match. */ /* Allowed if parent directory and link owner match. */
if (parent->i_uid == inode->i_uid) if (uid_eq(parent->i_uid, inode->i_uid))
return 0; return 0;
path_put_conditional(link, nd); path_put_conditional(link, nd);
@ -757,7 +757,7 @@ static int may_linkat(struct path *link)
/* Source inode owner (or CAP_FOWNER) can hardlink all they like, /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
* otherwise, it must be a safe source. * otherwise, it must be a safe source.
*/ */
if (cred->fsuid == inode->i_uid || safe_hardlink_source(inode) || if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(inode) ||
capable(CAP_FOWNER)) capable(CAP_FOWNER))
return 0; return 0;

View File

@ -9,6 +9,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cred.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/page.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)); memset(p, 0, sizeof(*p));
mutex_init(&p->lock); mutex_init(&p->lock);
p->op = op; 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 * Wrappers around seq_open(e.g. swaps_open) need to be

View File

@ -159,6 +159,7 @@ struct inet_diag_handler {
struct inet_connection_sock; struct inet_connection_sock;
int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
struct sk_buff *skb, struct inet_diag_req_v2 *req, struct sk_buff *skb, struct inet_diag_req_v2 *req,
struct user_namespace *user_ns,
u32 pid, u32 seq, u16 nlmsg_flags, u32 pid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh); const struct nlmsghdr *unlh);
void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb,

View File

@ -165,6 +165,7 @@ struct netlink_skb_parms {
struct ucred creds; /* Skb credentials */ struct ucred creds; /* Skb credentials */
__u32 pid; __u32 pid;
__u32 dst_group; __u32 dst_group;
struct sock *ssk;
}; };
#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))

View File

@ -13,6 +13,7 @@ struct file;
struct path; struct path;
struct inode; struct inode;
struct dentry; struct dentry;
struct user_namespace;
struct seq_file { struct seq_file {
char *buf; char *buf;
@ -25,6 +26,9 @@ struct seq_file {
struct mutex lock; struct mutex lock;
const struct seq_operations *op; const struct seq_operations *op;
int poll_event; int poll_event;
#ifdef CONFIG_USER_NS
struct user_namespace *user_ns;
#endif
void *private; 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, int seq_put_decimal_ll(struct seq_file *m, char delimiter,
long long num); 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) #define SEQ_START_TOKEN ((void *)1)
/* /*
* Helpers for iteration over list_head-s in seq_files * Helpers for iteration over list_head-s in seq_files

View File

@ -157,7 +157,7 @@ enum {
typedef struct ax25_uid_assoc { typedef struct ax25_uid_assoc {
struct hlist_node uid_node; struct hlist_node uid_node;
atomic_t refcount; atomic_t refcount;
uid_t uid; kuid_t uid;
ax25_address call; ax25_address call;
} ax25_uid_assoc; } ax25_uid_assoc;
@ -434,7 +434,7 @@ extern unsigned long ax25_display_timer(struct timer_list *);
/* ax25_uid.c */ /* ax25_uid.c */
extern int ax25_uid_policy; 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 int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *);
extern const struct file_operations ax25_uid_fops; extern const struct file_operations ax25_uid_fops;
extern void ax25_uid_free(void); extern void ax25_uid_free(void);

View File

@ -223,7 +223,10 @@ struct ip6_flowlabel {
struct ipv6_txoptions *opt; struct ipv6_txoptions *opt;
unsigned long linger; unsigned long linger;
u8 share; u8 share;
u32 owner; union {
struct pid *pid;
kuid_t uid;
} owner;
unsigned long lastuse; unsigned long lastuse;
unsigned long expires; unsigned long expires;
struct net *fl_net; struct net *fl_net;

View File

@ -5,6 +5,7 @@
#ifndef __NETNS_IPV4_H__ #ifndef __NETNS_IPV4_H__
#define __NETNS_IPV4_H__ #define __NETNS_IPV4_H__
#include <linux/uidgid.h>
#include <net/inet_frag.h> #include <net/inet_frag.h>
struct tcpm_hash_bucket; struct tcpm_hash_bucket;
@ -62,7 +63,7 @@ struct netns_ipv4 {
int sysctl_icmp_ratemask; int sysctl_icmp_ratemask;
int sysctl_icmp_errors_use_inbound_ifaddr; 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]; long sysctl_tcp_mem[3];
atomic_t rt_genid; atomic_t rt_genid;

View File

@ -188,7 +188,8 @@ struct tcf_proto_ops {
unsigned long (*get)(struct tcf_proto*, u32 handle); unsigned long (*get)(struct tcf_proto*, u32 handle);
void (*put)(struct tcf_proto*, unsigned long); 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 **, u32 handle, struct nlattr **,
unsigned long *); unsigned long *);
int (*delete)(struct tcf_proto*, unsigned long); int (*delete)(struct tcf_proto*, unsigned long);

View File

@ -606,6 +606,15 @@ static inline void sk_add_bind_node(struct sock *sk,
#define sk_for_each_bound(__sk, node, list) \ #define sk_for_each_bound(__sk, node, list) \
hlist_for_each_entry(__sk, node, list, sk_bind_node) 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 */ /* Sock flags */
enum sock_flags { enum sock_flags {
SOCK_DEAD, SOCK_DEAD,
@ -1670,7 +1679,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
write_unlock_bh(&sk->sk_callback_lock); 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); extern unsigned long sock_i_ino(struct sock *sk);
static inline struct dst_entry * static inline struct dst_entry *

View File

@ -1510,7 +1510,8 @@ struct tcp_iter_state {
sa_family_t family; sa_family_t family;
enum tcp_seq_states state; enum tcp_seq_states state;
struct sock *syn_wait_sk; struct sock *syn_wait_sk;
int bucket, offset, sbucket, num, uid; int bucket, offset, sbucket, num;
kuid_t uid;
loff_t last_pos; loff_t last_pos;
}; };

View File

@ -942,28 +942,12 @@ config UIDGID_CONVERTED
depends on PROC_EVENTS = n depends on PROC_EVENTS = n
# Networking # Networking
depends on NET = n
depends on NET_9P = 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
depends on NETFILTER_XT_TARGET_LOG = n
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 AF_RXRPC = n
depends on LLC2 = n
depends on NET_KEY = n depends on NET_KEY = n
depends on INET_DIAG = n
depends on DNS_RESOLVER = n depends on DNS_RESOLVER = n
depends on AX25 = n
depends on ATALK = n
# Filesystems # Filesystems
depends on USB_DEVICEFS = n
depends on USB_GADGETFS = n depends on USB_GADGETFS = n
depends on USB_FUNCTIONFS = n depends on USB_FUNCTIONFS = n
depends on DEVTMPFS = n depends on DEVTMPFS = n
@ -1019,9 +1003,6 @@ config UIDGID_CONVERTED
depends on !UML || HOSTFS = n depends on !UML || HOSTFS = n
# The rare drivers that won't build # 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 INFINIBAND_QIB = n
depends on BLK_DEV_LOOP = n depends on BLK_DEV_LOOP = n
depends on ANDROID_BINDER_IPC = n depends on ANDROID_BINDER_IPC = n

View File

@ -479,6 +479,7 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)
} }
return nr; return nr;
} }
EXPORT_SYMBOL_GPL(pid_nr_ns);
pid_t pid_vnr(struct pid *pid) pid_t pid_vnr(struct pid *pid)
{ {

View File

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

View File

@ -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, ntohs(at->dest_net), at->dest_node, at->dest_port,
sk_wmem_alloc_get(s), sk_wmem_alloc_get(s),
sk_rmem_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: out:
return 0; return 0;
} }

View File

@ -51,14 +51,14 @@ int ax25_uid_policy;
EXPORT_SYMBOL(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; ax25_uid_assoc *ax25_uid, *res = NULL;
struct hlist_node *node; struct hlist_node *node;
read_lock(&ax25_uid_lock); read_lock(&ax25_uid_lock);
ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { 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); ax25_uid_hold(ax25_uid);
res = ax25_uid; res = ax25_uid;
break; break;
@ -84,7 +84,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
read_lock(&ax25_uid_lock); read_lock(&ax25_uid_lock);
ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
res = ax25_uid->uid; res = from_kuid_munged(current_user_ns(), ax25_uid->uid);
break; break;
} }
} }
@ -93,9 +93,14 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return res; return res;
case SIOCAX25ADDUID: case SIOCAX25ADDUID:
{
kuid_t sax25_kuid;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; 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) { if (user) {
ax25_uid_put(user); ax25_uid_put(user);
return -EEXIST; return -EEXIST;
@ -106,7 +111,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return -ENOMEM; return -ENOMEM;
atomic_set(&ax25_uid->refcount, 1); atomic_set(&ax25_uid->refcount, 1);
ax25_uid->uid = sax->sax25_uid; ax25_uid->uid = sax25_kuid;
ax25_uid->call = sax->sax25_call; ax25_uid->call = sax->sax25_call;
write_lock(&ax25_uid_lock); write_lock(&ax25_uid_lock);
@ -114,7 +119,7 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
write_unlock(&ax25_uid_lock); write_unlock(&ax25_uid_lock);
return 0; return 0;
}
case SIOCAX25DELUID: case SIOCAX25DELUID:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
@ -172,7 +177,9 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v)
struct ax25_uid_assoc *pt; struct ax25_uid_assoc *pt;
pt = hlist_entry(v, struct ax25_uid_assoc, uid_node); 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; return 0;
} }

View File

@ -4520,8 +4520,8 @@ static void dev_change_rx_flags(struct net_device *dev, int flags)
static int __dev_set_promiscuity(struct net_device *dev, int inc) static int __dev_set_promiscuity(struct net_device *dev, int inc)
{ {
unsigned int old_flags = dev->flags; unsigned int old_flags = dev->flags;
uid_t uid; kuid_t uid;
gid_t gid; kgid_t gid;
ASSERT_RTNL(); ASSERT_RTNL();
@ -4553,7 +4553,8 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
dev->name, (dev->flags & IFF_PROMISC), dev->name, (dev->flags & IFF_PROMISC),
(old_flags & IFF_PROMISC), (old_flags & IFF_PROMISC),
audit_get_loginuid(current), audit_get_loginuid(current),
uid, gid, from_kuid(&init_user_ns, uid),
from_kgid(&init_user_ns, gid),
audit_get_sessionid(current)); audit_get_sessionid(current));
} }

View File

@ -45,12 +45,17 @@
static __inline__ int scm_check_creds(struct ucred *creds) static __inline__ int scm_check_creds(struct ucred *creds)
{ {
const struct cred *cred = current_cred(); 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)) && if ((creds->pid == task_tgid_vnr(current) || capable(CAP_SYS_ADMIN)) &&
((creds->uid == cred->uid || creds->uid == cred->euid || ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) ||
creds->uid == cred->suid) || capable(CAP_SETUID)) && uid_eq(uid, cred->suid)) || capable(CAP_SETUID)) &&
((creds->gid == cred->gid || creds->gid == cred->egid || ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) ||
creds->gid == cred->sgid) || capable(CAP_SETGID))) { gid_eq(gid, cred->sgid)) || capable(CAP_SETGID))) {
return 0; return 0;
} }
return -EPERM; return -EPERM;
@ -149,6 +154,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
goto error; goto error;
break; break;
case SCM_CREDENTIALS: case SCM_CREDENTIALS:
{
kuid_t uid;
kgid_t gid;
if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
goto error; goto error;
memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); 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; 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 || if (!p->cred ||
(p->cred->euid != p->creds.uid) || !uid_eq(p->cred->euid, uid) ||
(p->cred->egid != p->creds.gid)) { !gid_eq(p->cred->egid, gid)) {
struct cred *cred; struct cred *cred;
err = -ENOMEM; err = -ENOMEM;
cred = prepare_creds(); cred = prepare_creds();
if (!cred) if (!cred)
goto error; goto error;
cred->uid = cred->euid = p->creds.uid; cred->uid = cred->euid = uid;
cred->gid = cred->egid = p->creds.gid; cred->gid = cred->egid = gid;
if (p->cred) if (p->cred)
put_cred(p->cred); put_cred(p->cred);
p->cred = cred; p->cred = cred;
} }
break; break;
}
default: default:
goto error; goto error;
} }

View File

@ -868,8 +868,8 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred,
if (cred) { if (cred) {
struct user_namespace *current_ns = current_user_ns(); struct user_namespace *current_ns = current_user_ns();
ucred->uid = from_kuid(current_ns, cred->euid); ucred->uid = from_kuid_munged(current_ns, cred->euid);
ucred->gid = from_kgid(current_ns, cred->egid); ucred->gid = from_kgid_munged(current_ns, cred->egid);
} }
} }
EXPORT_SYMBOL_GPL(cred_to_ucred); EXPORT_SYMBOL_GPL(cred_to_ucred);
@ -1527,12 +1527,12 @@ void sock_edemux(struct sk_buff *skb)
} }
EXPORT_SYMBOL(sock_edemux); 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); 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); read_unlock_bh(&sk->sk_callback_lock);
return uid; return uid;
} }

View File

@ -69,6 +69,7 @@ static inline void inet_diag_unlock_handler(
int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
struct sk_buff *skb, struct inet_diag_req_v2 *req, struct sk_buff *skb, struct inet_diag_req_v2 *req,
struct user_namespace *user_ns,
u32 pid, u32 seq, u16 nlmsg_flags, u32 pid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh) const struct nlmsghdr *unlh)
{ {
@ -124,7 +125,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
} }
#endif #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); r->idiag_inode = sock_i_ino(sk);
if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { 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, static int inet_csk_diag_fill(struct sock *sk,
struct sk_buff *skb, struct inet_diag_req_v2 *req, struct sk_buff *skb, struct inet_diag_req_v2 *req,
struct user_namespace *user_ns,
u32 pid, u32 seq, u16 nlmsg_flags, u32 pid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh) const struct nlmsghdr *unlh)
{ {
return inet_sk_diag_fill(sk, inet_csk(sk), 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, 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, 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) const struct nlmsghdr *unlh)
{ {
if (sk->sk_state == TCP_TIME_WAIT) if (sk->sk_state == TCP_TIME_WAIT)
return inet_twsk_diag_fill((struct inet_timewait_sock *)sk, return inet_twsk_diag_fill((struct inet_timewait_sock *)sk,
skb, r, pid, seq, nlmsg_flags, skb, r, pid, seq, nlmsg_flags,
unlh); 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, 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, err = sk_diag_fill(sk, rep, req,
sk_user_ns(NETLINK_CB(in_skb).ssk),
NETLINK_CB(in_skb).pid, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0, nlh); nlh->nlmsg_seq, 0, nlh);
if (err < 0) { if (err < 0) {
@ -551,6 +556,7 @@ static int inet_csk_diag_dump(struct sock *sk,
return 0; return 0;
return inet_csk_diag_fill(sk, skb, r, return inet_csk_diag_fill(sk, skb, r,
sk_user_ns(NETLINK_CB(cb->skb).ssk),
NETLINK_CB(cb->skb).pid, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); 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, 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 nlmsghdr *unlh)
{ {
const struct inet_request_sock *ireq = inet_rsk(req); 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_expires = jiffies_to_msecs(tmo);
r->idiag_rqueue = 0; r->idiag_rqueue = 0;
r->idiag_wqueue = 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; r->idiag_inode = 0;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (r->idiag_family == AF_INET6) { 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, err = inet_diag_fill_req(skb, sk, req,
sk_user_ns(NETLINK_CB(cb->skb).ssk),
NETLINK_CB(cb->skb).pid, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, cb->nlh); cb->nlh->nlmsg_seq, cb->nlh);
if (err < 0) { if (err < 0) {

View File

@ -185,10 +185,10 @@ exit:
return sk; return sk;
} }
static void inet_get_ping_group_range_net(struct net *net, gid_t *low, static void inet_get_ping_group_range_net(struct net *net, kgid_t *low,
gid_t *high) kgid_t *high)
{ {
gid_t *data = net->ipv4.sysctl_ping_group_range; kgid_t *data = net->ipv4.sysctl_ping_group_range;
unsigned int seq; unsigned int seq;
do { 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) static int ping_init_sock(struct sock *sk)
{ {
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
gid_t group = current_egid(); kgid_t group = current_egid();
gid_t range[2];
struct group_info *group_info = get_current_groups(); struct group_info *group_info = get_current_groups();
int i, j, count = group_info->ngroups; int i, j, count = group_info->ngroups;
kgid_t low, high; kgid_t low, high;
inet_get_ping_group_range_net(net, range, range+1); inet_get_ping_group_range_net(net, &low, &high);
low = make_kgid(&init_user_ns, range[0]); if (gid_lte(low, group) && gid_lte(group, high))
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])
return 0; return 0;
for (i = 0; i < group_info->nblocks; i++) { for (i = 0; i < group_info->nblocks; i++) {
@ -845,7 +839,9 @@ static void ping_format_sock(struct sock *sp, struct seq_file *f,
bucket, src, srcp, dest, destp, sp->sk_state, bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp), sk_wmem_alloc_get(sp),
sk_rmem_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_refcnt), sp,
atomic_read(&sp->sk_drops), len); atomic_read(&sp->sk_drops), len);
} }

View File

@ -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, i, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp), sk_wmem_alloc_get(sp),
sk_rmem_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)); atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
} }

View File

@ -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; unsigned int seq;
do { do {
seq = read_seqbegin(&sysctl_local_ports.lock); 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 */ /* 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); write_seqlock(&sysctl_local_ports.lock);
data[0] = range[0]; data[0] = low;
data[1] = range[1]; data[1] = high;
write_sequnlock(&sysctl_local_ports.lock); write_sequnlock(&sysctl_local_ports.lock);
} }
@ -103,21 +103,33 @@ static int ipv4_ping_group_range(ctl_table *table, int write,
void __user *buffer, void __user *buffer,
size_t *lenp, loff_t *ppos) size_t *lenp, loff_t *ppos)
{ {
struct user_namespace *user_ns = current_user_ns();
int ret; int ret;
gid_t range[2]; gid_t urange[2];
kgid_t low, high;
ctl_table tmp = { ctl_table tmp = {
.data = &range, .data = &urange,
.maxlen = sizeof(range), .maxlen = sizeof(urange),
.mode = table->mode, .mode = table->mode,
.extra1 = &ip_ping_group_range_min, .extra1 = &ip_ping_group_range_min,
.extra2 = &ip_ping_group_range_max, .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); ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
if (write && ret == 0) if (write && ret == 0) {
set_ping_group_range(table, range); 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; return ret;
} }
@ -786,7 +798,7 @@ static struct ctl_table ipv4_net_table[] = {
{ {
.procname = "ping_group_range", .procname = "ping_group_range",
.data = &init_net.ipv4.sysctl_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, .mode = 0644,
.proc_handler = ipv4_ping_group_range, .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. * Sane defaults - nobody may create ping sockets.
* Boot scripts should set this to distro-specific group. * Boot scripts should set this to distro-specific group.
*/ */
net->ipv4.sysctl_ping_group_range[0] = 1; net->ipv4.sysctl_ping_group_range[0] = make_kgid(&init_user_ns, 1);
net->ipv4.sysctl_ping_group_range[1] = 0; net->ipv4.sysctl_ping_group_range[1] = make_kgid(&init_user_ns, 0);
tcp_init_mem(net); tcp_init_mem(net);

View File

@ -2393,7 +2393,7 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
EXPORT_SYMBOL(tcp_proc_unregister); EXPORT_SYMBOL(tcp_proc_unregister);
static void get_openreq4(const struct sock *sk, const struct request_sock *req, 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); const struct inet_request_sock *ireq = inet_rsk(req);
long delta = req->expires - jiffies; long delta = req->expires - jiffies;
@ -2410,7 +2410,7 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
1, /* timers active (only the expire timer) */ 1, /* timers active (only the expire timer) */
jiffies_delta_to_clock_t(delta), jiffies_delta_to_clock_t(delta),
req->retrans, req->retrans,
uid, from_kuid_munged(seq_user_ns(f), uid),
0, /* non standard timer */ 0, /* non standard timer */
0, /* open_requests have no inode */ 0, /* open_requests have no inode */
atomic_read(&sk->sk_refcnt), atomic_read(&sk->sk_refcnt),
@ -2461,7 +2461,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
timer_active, timer_active,
jiffies_delta_to_clock_t(timer_expires - jiffies), jiffies_delta_to_clock_t(timer_expires - jiffies),
icsk->icsk_retransmits, icsk->icsk_retransmits,
sock_i_uid(sk), from_kuid_munged(seq_user_ns(f), sock_i_uid(sk)),
icsk->icsk_probes_out, icsk->icsk_probes_out,
sock_i_ino(sk), sock_i_ino(sk),
atomic_read(&sk->sk_refcnt), sk, atomic_read(&sk->sk_refcnt), sk,

View File

@ -2110,7 +2110,9 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
bucket, src, srcp, dest, destp, sp->sk_state, bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp), sk_wmem_alloc_get(sp),
sk_rmem_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_refcnt), sp,
atomic_read(&sp->sk_drops), len); atomic_read(&sp->sk_drops), len);
} }

View File

@ -24,7 +24,9 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
if (!inet_diag_bc_sk(bc, sk)) if (!inet_diag_bc_sk(bc, sk))
return 0; 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); 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; goto out;
err = inet_sk_diag_fill(sk, NULL, rep, req, err = inet_sk_diag_fill(sk, NULL, rep, req,
sk_user_ns(NETLINK_CB(in_skb).ssk),
NETLINK_CB(in_skb).pid, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0, nlh); nlh->nlmsg_seq, 0, nlh);
if (err < 0) { if (err < 0) {

View File

@ -22,6 +22,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/pid_namespace.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
@ -91,6 +92,8 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
static void fl_free(struct ip6_flowlabel *fl) static void fl_free(struct ip6_flowlabel *fl)
{ {
if (fl) { if (fl) {
if (fl->share == IPV6_FL_S_PROCESS)
put_pid(fl->owner.pid);
release_net(fl->fl_net); release_net(fl->fl_net);
kfree(fl->opt); kfree(fl->opt);
} }
@ -394,10 +397,10 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
case IPV6_FL_S_ANY: case IPV6_FL_S_ANY:
break; break;
case IPV6_FL_S_PROCESS: case IPV6_FL_S_PROCESS:
fl->owner = current->pid; fl->owner.pid = get_task_pid(current, PIDTYPE_PID);
break; break;
case IPV6_FL_S_USER: case IPV6_FL_S_USER:
fl->owner = current_euid(); fl->owner.uid = current_euid();
break; break;
default: default:
err = -EINVAL; err = -EINVAL;
@ -561,7 +564,10 @@ recheck:
err = -EPERM; err = -EPERM;
if (fl1->share == IPV6_FL_S_EXCL || if (fl1->share == IPV6_FL_S_EXCL ||
fl1->share != fl->share || 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; goto release;
err = -EINVAL; err = -EINVAL;
@ -621,6 +627,7 @@ done:
struct ip6fl_iter_state { struct ip6fl_iter_state {
struct seq_net_private p; struct seq_net_private p;
struct pid_namespace *pid_ns;
int bucket; int bucket;
}; };
@ -699,6 +706,7 @@ static void ip6fl_seq_stop(struct seq_file *seq, void *v)
static int ip6fl_seq_show(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) if (v == SEQ_START_TOKEN)
seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n", seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-32s %s\n",
"Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt"); "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
@ -708,7 +716,11 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v)
"%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n",
(unsigned int)ntohl(fl->label), (unsigned int)ntohl(fl->label),
fl->share, 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), atomic_read(&fl->users),
fl->linger/HZ, fl->linger/HZ,
(long)(fl->expires - jiffies)/HZ, (long)(fl->expires - jiffies)/HZ,
@ -727,8 +739,29 @@ static const struct seq_operations ip6fl_seq_ops = {
static int ip6fl_seq_open(struct inode *inode, struct file *file) static int ip6fl_seq_open(struct inode *inode, struct file *file)
{ {
return seq_open_net(inode, file, &ip6fl_seq_ops, struct seq_file *seq;
sizeof(struct ip6fl_iter_state)); 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 = { static const struct file_operations ip6fl_seq_fops = {
@ -736,7 +769,7 @@ static const struct file_operations ip6fl_seq_fops = {
.open = ip6fl_seq_open, .open = ip6fl_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release_net, .release = ip6fl_seq_release,
}; };
static int __net_init ip6_flowlabel_proc_init(struct net *net) static int __net_init ip6_flowlabel_proc_init(struct net *net)

View File

@ -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_wmem_alloc_get(sp),
sk_rmem_alloc_get(sp), sk_rmem_alloc_get(sp),
0, 0L, 0, 0, 0L, 0,
sock_i_uid(sp), 0, from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
0,
sock_i_ino(sp), sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
} }

View File

@ -1828,7 +1828,7 @@ static void tcp_v6_destroy_sock(struct sock *sk)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* Proc filesystem TCPv6 sock list dumping. */ /* Proc filesystem TCPv6 sock list dumping. */
static void get_openreq6(struct seq_file *seq, 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; int ttd = req->expires - jiffies;
const struct in6_addr *src = &inet6_rsk(req)->loc_addr; const struct in6_addr *src = &inet6_rsk(req)->loc_addr;
@ -1852,7 +1852,7 @@ static void get_openreq6(struct seq_file *seq,
1, /* timers active (only the expire timer) */ 1, /* timers active (only the expire timer) */
jiffies_to_clock_t(ttd), jiffies_to_clock_t(ttd),
req->retrans, req->retrans,
uid, from_kuid_munged(seq_user_ns(seq), uid),
0, /* non standard timer */ 0, /* non standard timer */
0, /* open_requests have no inode */ 0, /* open_requests have no inode */
0, req); 0, req);
@ -1902,7 +1902,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
timer_active, timer_active,
jiffies_delta_to_clock_t(timer_expires - jiffies), jiffies_delta_to_clock_t(timer_expires - jiffies),
icsk->icsk_retransmits, icsk->icsk_retransmits,
sock_i_uid(sp), from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
icsk->icsk_probes_out, icsk->icsk_probes_out,
sock_i_ino(sp), sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_refcnt), sp,

View File

@ -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_wmem_alloc_get(sp),
sk_rmem_alloc_get(sp), sk_rmem_alloc_get(sp),
0, 0L, 0, 0, 0L, 0,
sock_i_uid(sp), 0, from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
0,
sock_i_ino(sp), sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_refcnt), sp,
atomic_read(&sp->sk_drops)); atomic_read(&sp->sk_drops));

View File

@ -217,7 +217,8 @@ static int ipx_seq_socket_show(struct seq_file *seq, void *v)
seq_printf(seq, "%08X %08X %02X %03d\n", seq_printf(seq, "%08X %08X %02X %03d\n",
sk_wmem_alloc_get(s), sk_wmem_alloc_get(s),
sk_rmem_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: out:
return 0; return 0;
} }

View File

@ -3661,7 +3661,7 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
atomic_read(&s->sk_refcnt), atomic_read(&s->sk_refcnt),
sk_rmem_alloc_get(s), sk_rmem_alloc_get(s),
sk_wmem_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) sock_i_ino(s)
); );
return 0; return 0;

View File

@ -151,7 +151,7 @@ static int llc_seq_socket_show(struct seq_file *seq, void *v)
sk_wmem_alloc_get(sk), sk_wmem_alloc_get(sk),
sk_rmem_alloc_get(sk) - llc->copied_seq, sk_rmem_alloc_get(sk) - llc->copied_seq,
sk->sk_state, 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); llc->link);
out: out:
return 0; return 0;

View File

@ -55,6 +55,7 @@ struct nfulnl_instance {
unsigned int qlen; /* number of nlmsgs in skb */ unsigned int qlen; /* number of nlmsgs in skb */
struct sk_buff *skb; /* pre-allocatd skb */ struct sk_buff *skb; /* pre-allocatd skb */
struct timer_list timer; struct timer_list timer;
struct user_namespace *peer_user_ns; /* User namespace of the peer process */
int peer_pid; /* PID of the peer process */ int peer_pid; /* PID of the peer process */
/* configurable parameters */ /* configurable parameters */
@ -132,7 +133,7 @@ instance_put(struct nfulnl_instance *inst)
static void nfulnl_timer(unsigned long data); static void nfulnl_timer(unsigned long data);
static struct nfulnl_instance * 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; struct nfulnl_instance *inst;
int err; int err;
@ -162,6 +163,7 @@ instance_create(u_int16_t group_num, int pid)
setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst); setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);
inst->peer_user_ns = user_ns;
inst->peer_pid = pid; inst->peer_pid = pid;
inst->group_num = group_num; inst->group_num = group_num;
@ -503,8 +505,11 @@ __build_packet_message(struct nfulnl_instance *inst,
read_lock_bh(&skb->sk->sk_callback_lock); 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) {
struct file *file = skb->sk->sk_socket->file; struct file *file = skb->sk->sk_socket->file;
__be32 uid = htonl(file->f_cred->fsuid); __be32 uid = htonl(from_kuid_munged(inst->peer_user_ns,
__be32 gid = htonl(file->f_cred->fsgid); 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); read_unlock_bh(&skb->sk->sk_callback_lock);
if (nla_put_be32(inst->skb, NFULA_UID, uid) || if (nla_put_be32(inst->skb, NFULA_UID, uid) ||
nla_put_be32(inst->skb, NFULA_GID, gid)) 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, inst = instance_create(group_num,
NETLINK_CB(skb).pid); NETLINK_CB(skb).pid,
sk_user_ns(NETLINK_CB(skb).ssk));
if (IS_ERR(inst)) { if (IS_ERR(inst)) {
ret = PTR_ERR(inst); ret = PTR_ERR(inst);
goto out; goto out;

View File

@ -363,10 +363,12 @@ static void dump_ipv4_packet(struct sbuff *m,
/* Max length: 15 "UID=4294967295 " */ /* Max length: 15 "UID=4294967295 " */
if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) { if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock); 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 ", sb_add(m, "UID=%u GID=%u ",
skb->sk->sk_socket->file->f_cred->fsuid, from_kuid_munged(&init_user_ns, cred->fsuid),
skb->sk->sk_socket->file->f_cred->fsgid); from_kgid_munged(&init_user_ns, cred->fsgid));
}
read_unlock_bh(&skb->sk->sk_callback_lock); 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 " */ /* Max length: 15 "UID=4294967295 " */
if ((logflags & XT_LOG_UID) && recurse && skb->sk) { if ((logflags & XT_LOG_UID) && recurse && skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock); 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 ", sb_add(m, "UID=%u GID=%u ",
skb->sk->sk_socket->file->f_cred->fsuid, from_kuid_munged(&init_user_ns, cred->fsuid),
skb->sk->sk_socket->file->f_cred->fsgid); from_kgid_munged(&init_user_ns, cred->fsgid));
}
read_unlock_bh(&skb->sk->sk_callback_lock); read_unlock_bh(&skb->sk->sk_callback_lock);
} }

View File

@ -17,6 +17,17 @@
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_owner.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 static bool
owner_mt(const struct sk_buff *skb, struct xt_action_param *par) 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) & return ((info->match ^ info->invert) &
(XT_OWNER_UID | XT_OWNER_GID)) == 0; (XT_OWNER_UID | XT_OWNER_GID)) == 0;
if (info->match & XT_OWNER_UID) if (info->match & XT_OWNER_UID) {
if ((filp->f_cred->fsuid >= info->uid_min && kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min);
filp->f_cred->fsuid <= info->uid_max) ^ 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)) !(info->invert & XT_OWNER_UID))
return false; return false;
}
if (info->match & XT_OWNER_GID) if (info->match & XT_OWNER_GID) {
if ((filp->f_cred->fsgid >= info->gid_min && kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min);
filp->f_cred->fsgid <= info->gid_max) ^ 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)) !(info->invert & XT_OWNER_GID))
return false; return false;
}
return true; return true;
} }
@ -56,6 +73,7 @@ static struct xt_match owner_mt_reg __read_mostly = {
.name = "owner", .name = "owner",
.revision = 1, .revision = 1,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.checkentry = owner_check,
.match = owner_mt, .match = owner_mt,
.matchsize = sizeof(struct xt_owner_match_info), .matchsize = sizeof(struct xt_owner_match_info),
.hooks = (1 << NF_INET_LOCAL_OUT) | .hooks = (1 << NF_INET_LOCAL_OUT) |

View File

@ -317,6 +317,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
struct recent_table *t; struct recent_table *t;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct proc_dir_entry *pde; struct proc_dir_entry *pde;
kuid_t uid;
kgid_t gid;
#endif #endif
unsigned int i; unsigned int i;
int ret = -EINVAL; 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++) for (i = 0; i < ip_list_hash_size; i++)
INIT_LIST_HEAD(&t->iphash[i]); INIT_LIST_HEAD(&t->iphash[i]);
#ifdef CONFIG_PROC_FS #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, pde = proc_create_data(t->name, ip_list_perms, recent_net->xt_recent,
&recent_mt_fops, t); &recent_mt_fops, t);
if (pde == NULL) { if (pde == NULL) {
@ -379,8 +388,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
pde->uid = ip_list_uid; pde->uid = uid;
pde->gid = ip_list_gid; pde->gid = gid;
#endif #endif
spin_lock_bh(&recent_lock); spin_lock_bh(&recent_lock);
list_add_tail(&t->list, &recent_net->tables); list_add_tail(&t->list, &recent_net->tables);

View File

@ -912,7 +912,8 @@ static void netlink_rcv_wake(struct sock *sk)
wake_up_interruptible(&nlk->wait); 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; int ret;
struct netlink_sock *nlk = nlk_sk(sk); 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) { if (nlk->netlink_rcv != NULL) {
ret = skb->len; ret = skb->len;
skb_set_owner_r(skb, sk); skb_set_owner_r(skb, sk);
NETLINK_CB(skb).ssk = ssk;
nlk->netlink_rcv(skb); nlk->netlink_rcv(skb);
consume_skb(skb); consume_skb(skb);
} else { } else {
@ -947,7 +949,7 @@ retry:
return PTR_ERR(sk); return PTR_ERR(sk);
} }
if (netlink_is_kernel(sk)) if (netlink_is_kernel(sk))
return netlink_unicast_kernel(sk, skb); return netlink_unicast_kernel(sk, skb, ssk);
if (sk_filter(sk, skb)) { if (sk_filter(sk, skb)) {
err = skb->len; err = skb->len;

View File

@ -3749,7 +3749,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
po->ifindex, po->ifindex,
po->running, po->running,
atomic_read(&s->sk_rmem_alloc), 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)); sock_i_ino(s));
} }

View File

@ -612,7 +612,8 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
sk->sk_protocol, pn->sobject, pn->dobject, sk->sk_protocol, pn->sobject, pn->dobject,
pn->resource, sk->sk_state, pn->resource, sk->sk_state,
sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk), 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_refcnt), sk,
atomic_read(&sk->sk_drops), &len); 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; struct sock *sk = *psk;
seq_printf(seq, "%02X %5d %lu%n", 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); sock_i_ino(sk), &len);
} }
seq_printf(seq, "%*s\n", 63 - len, ""); seq_printf(seq, "%*s\n", 63 - len, "");

View File

@ -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 (err == 0) {
if (tp_created) { if (tp_created) {
spin_lock_bh(root_lock); spin_lock_bh(root_lock);

View File

@ -162,7 +162,8 @@ errout:
return err; 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) struct nlattr **tca, unsigned long *arg)
{ {
int err; int err;

View File

@ -151,7 +151,8 @@ static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = {
[TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, [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, u32 handle, struct nlattr **tca,
unsigned long *arg) unsigned long *arg)
{ {

View File

@ -193,15 +193,19 @@ static u32 flow_get_rtclassid(const struct sk_buff *skb)
static u32 flow_get_skuid(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) if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) {
return skb->sk->sk_socket->file->f_cred->fsuid; kuid_t skuid = skb->sk->sk_socket->file->f_cred->fsuid;
return from_kuid(&init_user_ns, skuid);
}
return 0; return 0;
} }
static u32 flow_get_skgid(const struct sk_buff *skb) static u32 flow_get_skgid(const struct sk_buff *skb)
{ {
if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) {
return skb->sk->sk_socket->file->f_cred->fsgid; kgid_t skgid = skb->sk->sk_socket->file->f_cred->fsgid;
return from_kgid(&init_user_ns, skgid);
}
return 0; return 0;
} }
@ -347,7 +351,8 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
[TCA_FLOW_PERTURB] = { .type = NLA_U32 }, [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, u32 handle, struct nlattr **tca,
unsigned long *arg) unsigned long *arg)
{ {
@ -386,6 +391,10 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
if (fls(keymask) - 1 > FLOW_KEY_MAX) if (fls(keymask) - 1 > FLOW_KEY_MAX)
return -EOPNOTSUPP; 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); err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &flow_ext_map);

View File

@ -233,7 +233,8 @@ errout:
return err; 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, u32 handle,
struct nlattr **tca, struct nlattr **tca,
unsigned long *arg) unsigned long *arg)

View File

@ -427,7 +427,8 @@ errout:
return err; 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, u32 handle,
struct nlattr **tca, struct nlattr **tca,
unsigned long *arg) unsigned long *arg)

View File

@ -416,7 +416,8 @@ static const struct nla_policy rsvp_policy[TCA_RSVP_MAX + 1] = {
[TCA_RSVP_PINFO] = { .len = sizeof(struct tc_rsvp_pinfo) }, [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, u32 handle,
struct nlattr **tca, struct nlattr **tca,
unsigned long *arg) unsigned long *arg)

View File

@ -332,7 +332,8 @@ errout:
} }
static int 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 **tca, unsigned long *arg)
{ {
struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *opt = tca[TCA_OPTIONS];

View File

@ -544,7 +544,8 @@ errout:
return err; 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, struct nlattr **tca,
unsigned long *arg) unsigned long *arg)
{ {

View File

@ -220,7 +220,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, seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
sctp_sk(sk)->type, sk->sk_state, hash, sctp_sk(sk)->type, sk->sk_state, hash,
epb->bind_addr.port, 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); sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "\n"); seq_printf(seq, "\n");
@ -332,7 +333,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
assoc->assoc_id, assoc->assoc_id,
assoc->sndbuf_used, assoc->sndbuf_used,
atomic_read(&assoc->rmem_alloc), 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, epb->bind_addr.port,
assoc->peer.port); assoc->peer.port);
seq_printf(seq, " "); seq_printf(seq, " ");