Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49f4d8b9 authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

pidns: Capture the user namespace and filter ns_last_pid



- Capture the the user namespace that creates the pid namespace
- Use that user namespace to test if it is ok to write to
  /proc/sys/kernel/ns_last_pid.

Zhao Hongjiang <zhaohongjiang@huawei.com> noticed I was missing a put_user_ns
in when destroying a pid_ns.  I have foloded his patch into this one
so that bisects will work properly.

Acked-by: default avatarSerge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent ae06c7c8
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ struct pid_namespace {
#ifdef CONFIG_BSD_PROCESS_ACCT
#ifdef CONFIG_BSD_PROCESS_ACCT
	struct bsd_acct_struct *bacct;
	struct bsd_acct_struct *bacct;
#endif
#endif
	struct user_namespace *user_ns;
	kgid_t pid_gid;
	kgid_t pid_gid;
	int hide_pid;
	int hide_pid;
	int reboot;	/* group exit code if this pidns was rebooted */
	int reboot;	/* group exit code if this pidns was rebooted */
@@ -46,7 +47,8 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns)
	return ns;
	return ns;
}
}


extern struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *ns);
extern struct pid_namespace *copy_pid_ns(unsigned long flags,
	struct user_namespace *user_ns, struct pid_namespace *ns);
extern void zap_pid_ns_processes(struct pid_namespace *pid_ns);
extern void zap_pid_ns_processes(struct pid_namespace *pid_ns);
extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd);
extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd);
extern void put_pid_ns(struct pid_namespace *ns);
extern void put_pid_ns(struct pid_namespace *ns);
@@ -59,8 +61,8 @@ static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns)
	return ns;
	return ns;
}
}


static inline struct pid_namespace *
static inline struct pid_namespace *copy_pid_ns(unsigned long flags,
copy_pid_ns(unsigned long flags, struct pid_namespace *ns)
	struct user_namespace *user_ns, struct pid_namespace *ns)
{
{
	if (flags & CLONE_NEWPID)
	if (flags & CLONE_NEWPID)
		ns = ERR_PTR(-EINVAL);
		ns = ERR_PTR(-EINVAL);
+1 −1
Original line number Original line Diff line number Diff line
@@ -84,7 +84,7 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
		goto out_ipc;
		goto out_ipc;
	}
	}


	new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk));
	new_nsp->pid_ns = copy_pid_ns(flags, task_cred_xxx(tsk, user_ns), task_active_pid_ns(tsk));
	if (IS_ERR(new_nsp->pid_ns)) {
	if (IS_ERR(new_nsp->pid_ns)) {
		err = PTR_ERR(new_nsp->pid_ns);
		err = PTR_ERR(new_nsp->pid_ns);
		goto out_pid;
		goto out_pid;
+1 −0
Original line number Original line Diff line number Diff line
@@ -78,6 +78,7 @@ struct pid_namespace init_pid_ns = {
	.last_pid = 0,
	.last_pid = 0,
	.level = 0,
	.level = 0,
	.child_reaper = &init_task,
	.child_reaper = &init_task,
	.user_ns = &init_user_ns,
};
};
EXPORT_SYMBOL_GPL(init_pid_ns);
EXPORT_SYMBOL_GPL(init_pid_ns);


+12 −5
Original line number Original line Diff line number Diff line
@@ -10,6 +10,7 @@


#include <linux/pid.h>
#include <linux/pid.h>
#include <linux/pid_namespace.h>
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include <linux/syscalls.h>
#include <linux/syscalls.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/acct.h>
#include <linux/acct.h>
@@ -74,7 +75,8 @@ static struct kmem_cache *create_pid_cachep(int nr_ids)
/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
#define MAX_PID_NS_LEVEL 32
#define MAX_PID_NS_LEVEL 32


static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_pid_ns)
static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns,
	struct pid_namespace *parent_pid_ns)
{
{
	struct pid_namespace *ns;
	struct pid_namespace *ns;
	unsigned int level = parent_pid_ns->level + 1;
	unsigned int level = parent_pid_ns->level + 1;
@@ -102,6 +104,7 @@ static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_p
	kref_init(&ns->kref);
	kref_init(&ns->kref);
	ns->level = level;
	ns->level = level;
	ns->parent = get_pid_ns(parent_pid_ns);
	ns->parent = get_pid_ns(parent_pid_ns);
	ns->user_ns = get_user_ns(user_ns);


	set_bit(0, ns->pidmap[0].page);
	set_bit(0, ns->pidmap[0].page);
	atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1);
	atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1);
@@ -117,6 +120,7 @@ static struct pid_namespace *create_pid_namespace(struct pid_namespace *parent_p


out_put_parent_pid_ns:
out_put_parent_pid_ns:
	put_pid_ns(parent_pid_ns);
	put_pid_ns(parent_pid_ns);
	put_user_ns(user_ns);
out_free_map:
out_free_map:
	kfree(ns->pidmap[0].page);
	kfree(ns->pidmap[0].page);
out_free:
out_free:
@@ -131,16 +135,18 @@ static void destroy_pid_namespace(struct pid_namespace *ns)


	for (i = 0; i < PIDMAP_ENTRIES; i++)
	for (i = 0; i < PIDMAP_ENTRIES; i++)
		kfree(ns->pidmap[i].page);
		kfree(ns->pidmap[i].page);
	put_user_ns(ns->user_ns);
	kmem_cache_free(pid_ns_cachep, ns);
	kmem_cache_free(pid_ns_cachep, ns);
}
}


struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns)
struct pid_namespace *copy_pid_ns(unsigned long flags,
	struct user_namespace *user_ns, struct pid_namespace *old_ns)
{
{
	if (!(flags & CLONE_NEWPID))
	if (!(flags & CLONE_NEWPID))
		return get_pid_ns(old_ns);
		return get_pid_ns(old_ns);
	if (flags & (CLONE_THREAD|CLONE_PARENT))
	if (flags & (CLONE_THREAD|CLONE_PARENT))
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);
	return create_pid_namespace(old_ns);
	return create_pid_namespace(user_ns, old_ns);
}
}


static void free_pid_ns(struct kref *kref)
static void free_pid_ns(struct kref *kref)
@@ -239,9 +245,10 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
static int pid_ns_ctl_handler(struct ctl_table *table, int write,
static int pid_ns_ctl_handler(struct ctl_table *table, int write,
		void __user *buffer, size_t *lenp, loff_t *ppos)
		void __user *buffer, size_t *lenp, loff_t *ppos)
{
{
	struct pid_namespace *pid_ns = task_active_pid_ns(current);
	struct ctl_table tmp = *table;
	struct ctl_table tmp = *table;


	if (write && !capable(CAP_SYS_ADMIN))
	if (write && !ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN))
		return -EPERM;
		return -EPERM;


	/*
	/*
@@ -250,7 +257,7 @@ static int pid_ns_ctl_handler(struct ctl_table *table, int write,
	 * it should synchronize its usage with external means.
	 * it should synchronize its usage with external means.
	 */
	 */


	tmp.data = &current->nsproxy->pid_ns->last_pid;
	tmp.data = &pid_ns->last_pid;
	return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
	return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
}
}