mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
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:
commit
e6acb38480
52 changed files with 368 additions and 180 deletions
|
@ -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:
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
19
init/Kconfig
19
init/Kconfig
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -185,10 +185,10 @@ static struct sock *ping_v4_lookup(struct net *net, __be32 saddr, __be32 daddr,
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
|
||||||
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 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) |
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 @@ int netlink_unicast(struct sock *ssk, struct sk_buff *skb,
|
||||||
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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, "");
|
||||||
|
|
|
@ -319,7 +319,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -162,7 +162,8 @@ static int basic_set_parms(struct tcf_proto *tp, struct basic_filter *f,
|
||||||
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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -233,7 +233,8 @@ fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
|
||||||
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)
|
||||||
|
|
|
@ -427,7 +427,8 @@ static int route4_set_parms(struct tcf_proto *tp, unsigned long base,
|
||||||
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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -332,7 +332,8 @@ tcindex_set_parms(struct tcf_proto *tp, unsigned long base, u32 handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
||||||
|
|
|
@ -544,7 +544,8 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base,
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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, " ");
|
||||||
|
|
Loading…
Reference in a new issue