aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/base.c15
-rw-r--r--include/linux/projid.h104
-rw-r--r--include/linux/user_namespace.h3
-rw-r--r--kernel/user.c8
-rw-r--r--kernel/user_namespace.c128
5 files changed, 257 insertions, 1 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 138cff4b05dd..acd1960c28a2 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2991,6 +2991,11 @@ static int proc_gid_map_open(struct inode *inode, struct file *file)
2991 return proc_id_map_open(inode, file, &proc_gid_seq_operations); 2991 return proc_id_map_open(inode, file, &proc_gid_seq_operations);
2992} 2992}
2993 2993
2994static int proc_projid_map_open(struct inode *inode, struct file *file)
2995{
2996 return proc_id_map_open(inode, file, &proc_projid_seq_operations);
2997}
2998
2994static const struct file_operations proc_uid_map_operations = { 2999static const struct file_operations proc_uid_map_operations = {
2995 .open = proc_uid_map_open, 3000 .open = proc_uid_map_open,
2996 .write = proc_uid_map_write, 3001 .write = proc_uid_map_write,
@@ -3006,6 +3011,14 @@ static const struct file_operations proc_gid_map_operations = {
3006 .llseek = seq_lseek, 3011 .llseek = seq_lseek,
3007 .release = proc_id_map_release, 3012 .release = proc_id_map_release,
3008}; 3013};
3014
3015static const struct file_operations proc_projid_map_operations = {
3016 .open = proc_projid_map_open,
3017 .write = proc_projid_map_write,
3018 .read = seq_read,
3019 .llseek = seq_lseek,
3020 .release = proc_id_map_release,
3021};
3009#endif /* CONFIG_USER_NS */ 3022#endif /* CONFIG_USER_NS */
3010 3023
3011static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, 3024static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
@@ -3113,6 +3126,7 @@ static const struct pid_entry tgid_base_stuff[] = {
3113#ifdef CONFIG_USER_NS 3126#ifdef CONFIG_USER_NS
3114 REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), 3127 REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations),
3115 REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), 3128 REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
3129 REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
3116#endif 3130#endif
3117}; 3131};
3118 3132
@@ -3476,6 +3490,7 @@ static const struct pid_entry tid_base_stuff[] = {
3476#ifdef CONFIG_USER_NS 3490#ifdef CONFIG_USER_NS
3477 REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), 3491 REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations),
3478 REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), 3492 REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
3493 REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
3479#endif 3494#endif
3480}; 3495};
3481 3496
diff --git a/include/linux/projid.h b/include/linux/projid.h
new file mode 100644
index 000000000000..36517b95be5c
--- /dev/null
+++ b/include/linux/projid.h
@@ -0,0 +1,104 @@
1#ifndef _LINUX_PROJID_H
2#define _LINUX_PROJID_H
3
4/*
5 * A set of types for the internal kernel types representing project ids.
6 *
7 * The types defined in this header allow distinguishing which project ids in
8 * the kernel are values used by userspace and which project id values are
9 * the internal kernel values. With the addition of user namespaces the values
10 * can be different. Using the type system makes it possible for the compiler
11 * to detect when we overlook these differences.
12 *
13 */
14#include <linux/types.h>
15
16struct user_namespace;
17extern struct user_namespace init_user_ns;
18
19typedef __kernel_uid32_t projid_t;
20
21#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS
22
23typedef struct {
24 projid_t val;
25} kprojid_t;
26
27static inline projid_t __kprojid_val(kprojid_t projid)
28{
29 return projid.val;
30}
31
32#define KPROJIDT_INIT(value) (kprojid_t){ value }
33
34#else
35
36typedef projid_t kprojid_t;
37
38static inline projid_t __kprojid_val(kprojid_t projid)
39{
40 return projid;
41}
42
43#define KPROJIDT_INIT(value) ((kprojid_t) value )
44
45#endif
46
47#define INVALID_PROJID KPROJIDT_INIT(-1)
48#define OVERFLOW_PROJID 65534
49
50static inline bool projid_eq(kprojid_t left, kprojid_t right)
51{
52 return __kprojid_val(left) == __kprojid_val(right);
53}
54
55static inline bool projid_lt(kprojid_t left, kprojid_t right)
56{
57 return __kprojid_val(left) < __kprojid_val(right);
58}
59
60static inline bool projid_valid(kprojid_t projid)
61{
62 return !projid_eq(projid, INVALID_PROJID);
63}
64
65#ifdef CONFIG_USER_NS
66
67extern kprojid_t make_kprojid(struct user_namespace *from, projid_t projid);
68
69extern projid_t from_kprojid(struct user_namespace *to, kprojid_t projid);
70extern projid_t from_kprojid_munged(struct user_namespace *to, kprojid_t projid);
71
72static inline bool kprojid_has_mapping(struct user_namespace *ns, kprojid_t projid)
73{
74 return from_kprojid(ns, projid) != (projid_t)-1;
75}
76
77#else
78
79static inline kprojid_t make_kprojid(struct user_namespace *from, projid_t projid)
80{
81 return KPROJIDT_INIT(projid);
82}
83
84static inline projid_t from_kprojid(struct user_namespace *to, kprojid_t kprojid)
85{
86 return __kprojid_val(kprojid);
87}
88
89static inline projid_t from_kprojid_munged(struct user_namespace *to, kprojid_t kprojid)
90{
91 projid_t projid = from_kprojid(to, kprojid);
92 if (projid == (projid_t)-1)
93 projid = OVERFLOW_PROJID;
94 return projid;
95}
96
97static inline bool kprojid_has_mapping(struct user_namespace *ns, kprojid_t projid)
98{
99 return true;
100}
101
102#endif /* CONFIG_USER_NS */
103
104#endif /* _LINUX_PROJID_H */
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 4e72922e5a75..95142cae446a 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -20,6 +20,7 @@ struct uid_gid_map { /* 64 bytes -- 1 cache line */
20struct user_namespace { 20struct user_namespace {
21 struct uid_gid_map uid_map; 21 struct uid_gid_map uid_map;
22 struct uid_gid_map gid_map; 22 struct uid_gid_map gid_map;
23 struct uid_gid_map projid_map;
23 struct kref kref; 24 struct kref kref;
24 struct user_namespace *parent; 25 struct user_namespace *parent;
25 kuid_t owner; 26 kuid_t owner;
@@ -49,8 +50,10 @@ static inline void put_user_ns(struct user_namespace *ns)
49struct seq_operations; 50struct seq_operations;
50extern struct seq_operations proc_uid_seq_operations; 51extern struct seq_operations proc_uid_seq_operations;
51extern struct seq_operations proc_gid_seq_operations; 52extern struct seq_operations proc_gid_seq_operations;
53extern struct seq_operations proc_projid_seq_operations;
52extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *); 54extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *);
53extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *); 55extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *);
56extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, loff_t *);
54#else 57#else
55 58
56static inline struct user_namespace *get_user_ns(struct user_namespace *ns) 59static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
diff --git a/kernel/user.c b/kernel/user.c
index b815fefbe76f..750acffbe9ec 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -38,6 +38,14 @@ struct user_namespace init_user_ns = {
38 .count = 4294967295U, 38 .count = 4294967295U,
39 }, 39 },
40 }, 40 },
41 .projid_map = {
42 .nr_extents = 1,
43 .extent[0] = {
44 .first = 0,
45 .lower_first = 0,
46 .count = 4294967295U,
47 },
48 },
41 .kref = { 49 .kref = {
42 .refcount = ATOMIC_INIT(3), 50 .refcount = ATOMIC_INIT(3),
43 }, 51 },
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 86602316422d..456a6b9fba34 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -19,6 +19,7 @@
19#include <linux/fs.h> 19#include <linux/fs.h>
20#include <linux/uaccess.h> 20#include <linux/uaccess.h>
21#include <linux/ctype.h> 21#include <linux/ctype.h>
22#include <linux/projid.h>
22 23
23static struct kmem_cache *user_ns_cachep __read_mostly; 24static struct kmem_cache *user_ns_cachep __read_mostly;
24 25
@@ -295,6 +296,75 @@ gid_t from_kgid_munged(struct user_namespace *targ, kgid_t kgid)
295} 296}
296EXPORT_SYMBOL(from_kgid_munged); 297EXPORT_SYMBOL(from_kgid_munged);
297 298
299/**
300 * make_kprojid - Map a user-namespace projid pair into a kprojid.
301 * @ns: User namespace that the projid is in
302 * @projid: Project identifier
303 *
304 * Maps a user-namespace uid pair into a kernel internal kuid,
305 * and returns that kuid.
306 *
307 * When there is no mapping defined for the user-namespace projid
308 * pair INVALID_PROJID is returned. Callers are expected to test
309 * for and handle handle INVALID_PROJID being returned. INVALID_PROJID
310 * may be tested for using projid_valid().
311 */
312kprojid_t make_kprojid(struct user_namespace *ns, projid_t projid)
313{
314 /* Map the uid to a global kernel uid */
315 return KPROJIDT_INIT(map_id_down(&ns->projid_map, projid));
316}
317EXPORT_SYMBOL(make_kprojid);
318
319/**
320 * from_kprojid - Create a projid from a kprojid user-namespace pair.
321 * @targ: The user namespace we want a projid in.
322 * @kprojid: The kernel internal project identifier to start with.
323 *
324 * Map @kprojid into the user-namespace specified by @targ and
325 * return the resulting projid.
326 *
327 * There is always a mapping into the initial user_namespace.
328 *
329 * If @kprojid has no mapping in @targ (projid_t)-1 is returned.
330 */
331projid_t from_kprojid(struct user_namespace *targ, kprojid_t kprojid)
332{
333 /* Map the uid from a global kernel uid */
334 return map_id_up(&targ->projid_map, __kprojid_val(kprojid));
335}
336EXPORT_SYMBOL(from_kprojid);
337
338/**
339 * from_kprojid_munged - Create a projiid from a kprojid user-namespace pair.
340 * @targ: The user namespace we want a projid in.
341 * @kprojid: The kernel internal projid to start with.
342 *
343 * Map @kprojid into the user-namespace specified by @targ and
344 * return the resulting projid.
345 *
346 * There is always a mapping into the initial user_namespace.
347 *
348 * Unlike from_kprojid from_kprojid_munged never fails and always
349 * returns a valid projid. This makes from_kprojid_munged
350 * appropriate for use in syscalls like stat and where
351 * failing the system call and failing to provide a valid projid are
352 * not an options.
353 *
354 * If @kprojid has no mapping in @targ OVERFLOW_PROJID is returned.
355 */
356projid_t from_kprojid_munged(struct user_namespace *targ, kprojid_t kprojid)
357{
358 projid_t projid;
359 projid = from_kprojid(targ, kprojid);
360
361 if (projid == (projid_t) -1)
362 projid = OVERFLOW_PROJID;
363 return projid;
364}
365EXPORT_SYMBOL(from_kprojid_munged);
366
367
298static int uid_m_show(struct seq_file *seq, void *v) 368static int uid_m_show(struct seq_file *seq, void *v)
299{ 369{
300 struct user_namespace *ns = seq->private; 370 struct user_namespace *ns = seq->private;
@@ -337,6 +407,27 @@ static int gid_m_show(struct seq_file *seq, void *v)
337 return 0; 407 return 0;
338} 408}
339 409
410static int projid_m_show(struct seq_file *seq, void *v)
411{
412 struct user_namespace *ns = seq->private;
413 struct uid_gid_extent *extent = v;
414 struct user_namespace *lower_ns;
415 projid_t lower;
416
417 lower_ns = seq_user_ns(seq);
418 if ((lower_ns == ns) && lower_ns->parent)
419 lower_ns = lower_ns->parent;
420
421 lower = from_kprojid(lower_ns, KPROJIDT_INIT(extent->lower_first));
422
423 seq_printf(seq, "%10u %10u %10u\n",
424 extent->first,
425 lower,
426 extent->count);
427
428 return 0;
429}
430
340static void *m_start(struct seq_file *seq, loff_t *ppos, struct uid_gid_map *map) 431static void *m_start(struct seq_file *seq, loff_t *ppos, struct uid_gid_map *map)
341{ 432{
342 struct uid_gid_extent *extent = NULL; 433 struct uid_gid_extent *extent = NULL;
@@ -362,6 +453,13 @@ static void *gid_m_start(struct seq_file *seq, loff_t *ppos)
362 return m_start(seq, ppos, &ns->gid_map); 453 return m_start(seq, ppos, &ns->gid_map);
363} 454}
364 455
456static void *projid_m_start(struct seq_file *seq, loff_t *ppos)
457{
458 struct user_namespace *ns = seq->private;
459
460 return m_start(seq, ppos, &ns->projid_map);
461}
462
365static void *m_next(struct seq_file *seq, void *v, loff_t *pos) 463static void *m_next(struct seq_file *seq, void *v, loff_t *pos)
366{ 464{
367 (*pos)++; 465 (*pos)++;
@@ -387,6 +485,13 @@ struct seq_operations proc_gid_seq_operations = {
387 .show = gid_m_show, 485 .show = gid_m_show,
388}; 486};
389 487
488struct seq_operations proc_projid_seq_operations = {
489 .start = projid_m_start,
490 .stop = m_stop,
491 .next = m_next,
492 .show = projid_m_show,
493};
494
390static DEFINE_MUTEX(id_map_mutex); 495static DEFINE_MUTEX(id_map_mutex);
391 496
392static ssize_t map_write(struct file *file, const char __user *buf, 497static ssize_t map_write(struct file *file, const char __user *buf,
@@ -434,7 +539,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
434 /* Require the appropriate privilege CAP_SETUID or CAP_SETGID 539 /* Require the appropriate privilege CAP_SETUID or CAP_SETGID
435 * over the user namespace in order to set the id mapping. 540 * over the user namespace in order to set the id mapping.
436 */ 541 */
437 if (!ns_capable(ns, cap_setid)) 542 if (cap_valid(cap_setid) && !ns_capable(ns, cap_setid))
438 goto out; 543 goto out;
439 544
440 /* Get a buffer */ 545 /* Get a buffer */
@@ -584,9 +689,30 @@ ssize_t proc_gid_map_write(struct file *file, const char __user *buf, size_t siz
584 &ns->gid_map, &ns->parent->gid_map); 689 &ns->gid_map, &ns->parent->gid_map);
585} 690}
586 691
692ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
693{
694 struct seq_file *seq = file->private_data;
695 struct user_namespace *ns = seq->private;
696 struct user_namespace *seq_ns = seq_user_ns(seq);
697
698 if (!ns->parent)
699 return -EPERM;
700
701 if ((seq_ns != ns) && (seq_ns != ns->parent))
702 return -EPERM;
703
704 /* Anyone can set any valid project id no capability needed */
705 return map_write(file, buf, size, ppos, -1,
706 &ns->projid_map, &ns->parent->projid_map);
707}
708
587static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, 709static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
588 struct uid_gid_map *new_map) 710 struct uid_gid_map *new_map)
589{ 711{
712 /* Allow anyone to set a mapping that doesn't require privilege */
713 if (!cap_valid(cap_setid))
714 return true;
715
590 /* Allow the specified ids if we have the appropriate capability 716 /* Allow the specified ids if we have the appropriate capability
591 * (CAP_SETUID or CAP_SETGID) over the parent user namespace. 717 * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
592 */ 718 */