diff options
Diffstat (limited to 'kernel/utsname.c')
-rw-r--r-- | kernel/utsname.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/kernel/utsname.c b/kernel/utsname.c index 1824384ecfa3..c859164a6993 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c | |||
@@ -15,6 +15,41 @@ | |||
15 | #include <linux/version.h> | 15 | #include <linux/version.h> |
16 | 16 | ||
17 | /* | 17 | /* |
18 | * Clone a new ns copying an original utsname, setting refcount to 1 | ||
19 | * @old_ns: namespace to clone | ||
20 | * Return NULL on error (failure to kmalloc), new ns otherwise | ||
21 | */ | ||
22 | static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) | ||
23 | { | ||
24 | struct uts_namespace *ns; | ||
25 | |||
26 | ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); | ||
27 | if (ns) { | ||
28 | memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); | ||
29 | kref_init(&ns->kref); | ||
30 | } | ||
31 | return ns; | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * unshare the current process' utsname namespace. | ||
36 | * called only in sys_unshare() | ||
37 | */ | ||
38 | int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts) | ||
39 | { | ||
40 | if (unshare_flags & CLONE_NEWUTS) { | ||
41 | if (!capable(CAP_SYS_ADMIN)) | ||
42 | return -EPERM; | ||
43 | |||
44 | *new_uts = clone_uts_ns(current->nsproxy->uts_ns); | ||
45 | if (!*new_uts) | ||
46 | return -ENOMEM; | ||
47 | } | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | /* | ||
18 | * Copy task tsk's utsname namespace, or clone it if flags | 53 | * Copy task tsk's utsname namespace, or clone it if flags |
19 | * specifies CLONE_NEWUTS. In latter case, changes to the | 54 | * specifies CLONE_NEWUTS. In latter case, changes to the |
20 | * utsname of this process won't be seen by parent, and vice | 55 | * utsname of this process won't be seen by parent, and vice |
@@ -23,6 +58,7 @@ | |||
23 | int copy_utsname(int flags, struct task_struct *tsk) | 58 | int copy_utsname(int flags, struct task_struct *tsk) |
24 | { | 59 | { |
25 | struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; | 60 | struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; |
61 | struct uts_namespace *new_ns; | ||
26 | int err = 0; | 62 | int err = 0; |
27 | 63 | ||
28 | if (!old_ns) | 64 | if (!old_ns) |
@@ -30,6 +66,23 @@ int copy_utsname(int flags, struct task_struct *tsk) | |||
30 | 66 | ||
31 | get_uts_ns(old_ns); | 67 | get_uts_ns(old_ns); |
32 | 68 | ||
69 | if (!(flags & CLONE_NEWUTS)) | ||
70 | return 0; | ||
71 | |||
72 | if (!capable(CAP_SYS_ADMIN)) { | ||
73 | err = -EPERM; | ||
74 | goto out; | ||
75 | } | ||
76 | |||
77 | new_ns = clone_uts_ns(old_ns); | ||
78 | if (!new_ns) { | ||
79 | err = -ENOMEM; | ||
80 | goto out; | ||
81 | } | ||
82 | tsk->nsproxy->uts_ns = new_ns; | ||
83 | |||
84 | out: | ||
85 | put_uts_ns(old_ns); | ||
33 | return err; | 86 | return err; |
34 | } | 87 | } |
35 | 88 | ||