summaryrefslogtreecommitdiffstats
path: root/kernel/pid_namespace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 22:15:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-03 22:15:32 -0400
commit17dec0a949153d9ac00760ba2f5b78cb583e995f (patch)
treeaaf44fee3aca81a86ecfa46f3f409d5cf5675f1f /kernel/pid_namespace.c
parentd92cd810e64aa7cf22b05f0ea1c7d3e8dbae75fe (diff)
parent2236d4d39035b9839944603ec4b65ce71180a9ea (diff)
Merge branch 'userns-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace updates from Eric Biederman: "There was a lot of work this cycle fixing bugs that were discovered after the merge window and getting everything ready where we can reasonably support fully unprivileged fuse. The bug fixes you already have and much of the unprivileged fuse work is coming in via other trees. Still left for fully unprivileged fuse is figuring out how to cleanly handle .set_acl and .get_acl in the legacy case, and properly handling of evm xattrs on unprivileged mounts. Included in the tree is a cleanup from Alexely that replaced a linked list with a statically allocated fix sized array for the pid caches, which simplifies and speeds things up. Then there is are some cleanups and fixes for the ipc namespace. The motivation was that in reviewing other code it was discovered that access ipc objects from different pid namespaces recorded pids in such a way that when asked the wrong pids were returned. In the worst case there has been a measured 30% performance impact for sysvipc semaphores. Other test cases showed no measurable performance impact. Manfred Spraul and Davidlohr Bueso who tend to work on sysvipc performance both gave the nod that this is good enough. Casey Schaufler and James Morris have given their approval to the LSM side of the changes. I simplified the types and the code dealing with sysvipc to pass just kern_ipc_perm for all three types of ipc. Which reduced the header dependencies throughout the kernel and simplified the lsm code. Which let me work on the pid fixes without having to worry about trivial changes causing complete kernel recompiles" * 'userns-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: ipc/shm: Fix pid freeing. ipc/shm: fix up for struct file no longer being available in shm.h ipc/smack: Tidy up from the change in type of the ipc security hooks ipc: Directly call the security hook in ipc_ops.associate ipc/sem: Fix semctl(..., GETPID, ...) between pid namespaces ipc/msg: Fix msgctl(..., IPC_STAT, ...) between pid namespaces ipc/shm: Fix shmctl(..., IPC_STAT, ...) between pid namespaces. ipc/util: Helpers for making the sysvipc operations pid namespace aware ipc: Move IPCMNI from include/ipc.h into ipc/util.h msg: Move struct msg_queue into ipc/msg.c shm: Move struct shmid_kernel into ipc/shm.c sem: Move struct sem and struct sem_array into ipc/sem.c msg/security: Pass kern_ipc_perm not msg_queue into the msg_queue security hooks shm/security: Pass kern_ipc_perm not shmid_kernel into the shm security hooks sem/security: Pass kern_ipc_perm not sem_array into the sem security hooks pidns: simpler allocation of pid_* caches
Diffstat (limited to 'kernel/pid_namespace.c')
-rw-r--r--kernel/pid_namespace.c67
1 files changed, 24 insertions, 43 deletions
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 93b57f026688..2a2ac53d8b8b 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -23,55 +23,39 @@
23#include <linux/sched/signal.h> 23#include <linux/sched/signal.h>
24#include <linux/idr.h> 24#include <linux/idr.h>
25 25
26struct pid_cache {
27 int nr_ids;
28 char name[16];
29 struct kmem_cache *cachep;
30 struct list_head list;
31};
32
33static LIST_HEAD(pid_caches_lh);
34static DEFINE_MUTEX(pid_caches_mutex); 26static DEFINE_MUTEX(pid_caches_mutex);
35static struct kmem_cache *pid_ns_cachep; 27static struct kmem_cache *pid_ns_cachep;
28/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
29#define MAX_PID_NS_LEVEL 32
30/* Write once array, filled from the beginning. */
31static struct kmem_cache *pid_cache[MAX_PID_NS_LEVEL];
36 32
37/* 33/*
38 * creates the kmem cache to allocate pids from. 34 * creates the kmem cache to allocate pids from.
39 * @nr_ids: the number of numerical ids this pid will have to carry 35 * @level: pid namespace level
40 */ 36 */
41 37
42static struct kmem_cache *create_pid_cachep(int nr_ids) 38static struct kmem_cache *create_pid_cachep(unsigned int level)
43{ 39{
44 struct pid_cache *pcache; 40 /* Level 0 is init_pid_ns.pid_cachep */
45 struct kmem_cache *cachep; 41 struct kmem_cache **pkc = &pid_cache[level - 1];
46 42 struct kmem_cache *kc;
43 char name[4 + 10 + 1];
44 unsigned int len;
45
46 kc = READ_ONCE(*pkc);
47 if (kc)
48 return kc;
49
50 snprintf(name, sizeof(name), "pid_%u", level + 1);
51 len = sizeof(struct pid) + level * sizeof(struct upid);
47 mutex_lock(&pid_caches_mutex); 52 mutex_lock(&pid_caches_mutex);
48 list_for_each_entry(pcache, &pid_caches_lh, list) 53 /* Name collision forces to do allocation under mutex. */
49 if (pcache->nr_ids == nr_ids) 54 if (!*pkc)
50 goto out; 55 *pkc = kmem_cache_create(name, len, 0, SLAB_HWCACHE_ALIGN, 0);
51
52 pcache = kmalloc(sizeof(struct pid_cache), GFP_KERNEL);
53 if (pcache == NULL)
54 goto err_alloc;
55
56 snprintf(pcache->name, sizeof(pcache->name), "pid_%d", nr_ids);
57 cachep = kmem_cache_create(pcache->name,
58 sizeof(struct pid) + (nr_ids - 1) * sizeof(struct upid),
59 0, SLAB_HWCACHE_ALIGN, NULL);
60 if (cachep == NULL)
61 goto err_cachep;
62
63 pcache->nr_ids = nr_ids;
64 pcache->cachep = cachep;
65 list_add(&pcache->list, &pid_caches_lh);
66out:
67 mutex_unlock(&pid_caches_mutex); 56 mutex_unlock(&pid_caches_mutex);
68 return pcache->cachep; 57 /* current can fail, but someone else can succeed. */
69 58 return READ_ONCE(*pkc);
70err_cachep:
71 kfree(pcache);
72err_alloc:
73 mutex_unlock(&pid_caches_mutex);
74 return NULL;
75} 59}
76 60
77static void proc_cleanup_work(struct work_struct *work) 61static void proc_cleanup_work(struct work_struct *work)
@@ -80,9 +64,6 @@ static void proc_cleanup_work(struct work_struct *work)
80 pid_ns_release_proc(ns); 64 pid_ns_release_proc(ns);
81} 65}
82 66
83/* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */
84#define MAX_PID_NS_LEVEL 32
85
86static struct ucounts *inc_pid_namespaces(struct user_namespace *ns) 67static struct ucounts *inc_pid_namespaces(struct user_namespace *ns)
87{ 68{
88 return inc_ucount(ns, current_euid(), UCOUNT_PID_NAMESPACES); 69 return inc_ucount(ns, current_euid(), UCOUNT_PID_NAMESPACES);
@@ -119,7 +100,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
119 100
120 idr_init(&ns->idr); 101 idr_init(&ns->idr);
121 102
122 ns->pid_cachep = create_pid_cachep(level + 1); 103 ns->pid_cachep = create_pid_cachep(level);
123 if (ns->pid_cachep == NULL) 104 if (ns->pid_cachep == NULL)
124 goto out_free_idr; 105 goto out_free_idr;
125 106