X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=kernel%2Futsname.c;h=c859164a699311a10021f37f06c369e34ac4f4d5;hb=44f549217cd26daf7063984ae4ee6e46beca9c41;hp=1824384ecfa3225f11b1a30b0e9f79dea3c46327;hpb=4865ecf1315b450ab3317a745a6678c04d311e40;p=linux-2.6 diff --git a/kernel/utsname.c b/kernel/utsname.c index 1824384ecf..c859164a69 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -14,6 +14,41 @@ #include #include +/* + * Clone a new ns copying an original utsname, setting refcount to 1 + * @old_ns: namespace to clone + * Return NULL on error (failure to kmalloc), new ns otherwise + */ +static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) +{ + struct uts_namespace *ns; + + ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); + if (ns) { + memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); + kref_init(&ns->kref); + } + return ns; +} + +/* + * unshare the current process' utsname namespace. + * called only in sys_unshare() + */ +int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts) +{ + if (unshare_flags & CLONE_NEWUTS) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + *new_uts = clone_uts_ns(current->nsproxy->uts_ns); + if (!*new_uts) + return -ENOMEM; + } + + return 0; +} + /* * Copy task tsk's utsname namespace, or clone it if flags * specifies CLONE_NEWUTS. In latter case, changes to the @@ -23,6 +58,7 @@ int copy_utsname(int flags, struct task_struct *tsk) { struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; + struct uts_namespace *new_ns; int err = 0; if (!old_ns) @@ -30,6 +66,23 @@ int copy_utsname(int flags, struct task_struct *tsk) get_uts_ns(old_ns); + if (!(flags & CLONE_NEWUTS)) + return 0; + + if (!capable(CAP_SYS_ADMIN)) { + err = -EPERM; + goto out; + } + + new_ns = clone_uts_ns(old_ns); + if (!new_ns) { + err = -ENOMEM; + goto out; + } + tsk->nsproxy->uts_ns = new_ns; + +out: + put_uts_ns(old_ns); return err; }