diff options
Diffstat (limited to 'kernel/user_namespace.c')
-rw-r--r-- | kernel/user_namespace.c | 128 |
1 files changed, 127 insertions, 1 deletions
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 | ||
23 | static struct kmem_cache *user_ns_cachep __read_mostly; | 24 | static 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 | } |
296 | EXPORT_SYMBOL(from_kgid_munged); | 297 | EXPORT_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 | */ | ||
312 | kprojid_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 | } | ||
317 | EXPORT_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 | */ | ||
331 | projid_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 | } | ||
336 | EXPORT_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 | */ | ||
356 | projid_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 | } | ||
365 | EXPORT_SYMBOL(from_kprojid_munged); | ||
366 | |||
367 | |||
298 | static int uid_m_show(struct seq_file *seq, void *v) | 368 | static 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 | ||
410 | static 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 | |||
340 | static void *m_start(struct seq_file *seq, loff_t *ppos, struct uid_gid_map *map) | 431 | static 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 | ||
456 | static 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 | |||
365 | static void *m_next(struct seq_file *seq, void *v, loff_t *pos) | 463 | static 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 | ||
488 | struct 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 | |||
390 | static DEFINE_MUTEX(id_map_mutex); | 495 | static DEFINE_MUTEX(id_map_mutex); |
391 | 496 | ||
392 | static ssize_t map_write(struct file *file, const char __user *buf, | 497 | static 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 | ||
692 | ssize_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 | |||
587 | static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid, | 709 | static 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 | */ |