/* * Create new nsproxy and all of its the associated namespaces. * Return the newly created nsproxy. Do not attach this to the task, * leave it to the caller to do proper locking and attach it to task.
*/ staticstruct nsproxy *create_new_namespaces(unsignedlong flags, struct task_struct *tsk, struct user_namespace *user_ns, struct fs_struct *new_fs)
{ struct nsproxy *new_nsp; int err;
new_nsp = create_nsproxy(); if (!new_nsp) return ERR_PTR(-ENOMEM);
/* * called from clone. This now handles copy for nsproxy and all * namespaces therein.
*/ int copy_namespaces(unsignedlong flags, struct task_struct *tsk)
{ struct nsproxy *old_ns = tsk->nsproxy; struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); struct nsproxy *new_ns;
/* * CLONE_NEWIPC must detach from the undolist: after switching * to a new ipc namespace, the semaphore arrays from the old * namespace are unreachable. In clone parlance, CLONE_SYSVSEM * means share undolist with parent, so we must forbid using * it along with CLONE_NEWIPC.
*/ if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
(CLONE_NEWIPC | CLONE_SYSVSEM)) return -EINVAL;
new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); if (IS_ERR(new_ns)) return PTR_ERR(new_ns);
if ((flags & CLONE_VM) == 0)
timens_on_fork(new_ns, tsk);
/* * Called from unshare. Unshare all the namespaces part of nsproxy. * On success, returns the new nsproxy.
*/ int unshare_nsproxy_namespaces(unsignedlong unshare_flags, struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs)
{ struct user_namespace *user_ns; int err = 0;
if (flags & CLONE_NEWUSER)
put_cred(nsset_cred(nsset)); /* * We only created a temporary copy if we attached to more than just * the mount namespace.
*/ if (nsset->fs && (flags & CLONE_NEWNS) && (flags & ~CLONE_NEWNS))
free_fs_struct(nsset->fs); if (nsset->nsproxy)
free_nsproxy(nsset->nsproxy);
}
nsset->nsproxy = create_new_namespaces(0, me, current_user_ns(), me->fs); if (IS_ERR(nsset->nsproxy)) return PTR_ERR(nsset->nsproxy);
if (flags & CLONE_NEWUSER)
nsset->cred = prepare_creds(); else
nsset->cred = current_cred(); if (!nsset->cred) goto out;
/* Only create a temporary copy of fs_struct if we really need to. */ if (flags == CLONE_NEWNS) {
nsset->fs = me->fs;
} elseif (flags & CLONE_NEWNS) {
nsset->fs = copy_fs_struct(me->fs); if (!nsset->fs) goto out;
}
/* * This is the inverse operation to unshare(). * Ordering is equivalent to the standard ordering used everywhere else * during unshare and process creation. The switch to the new set of * namespaces occurs at the point of no return after installation of * all requested namespaces was successful in commit_nsset().
*/ staticint validate_nsset(struct nsset *nsset, struct pid *pid)
{ int ret = 0; unsigned flags = nsset->flags; struct user_namespace *user_ns = NULL; struct pid_namespace *pid_ns = NULL; struct nsproxy *nsp; struct task_struct *tsk;
/* Take a "snapshot" of the target task's namespaces. */
rcu_read_lock();
tsk = pid_task(pid, PIDTYPE_PID); if (!tsk) {
rcu_read_unlock(); return -ESRCH;
}
if (!ptrace_may_access(tsk, PTRACE_MODE_READ_REALCREDS)) {
rcu_read_unlock(); return -EPERM;
}
task_lock(tsk);
nsp = tsk->nsproxy; if (nsp)
get_nsproxy(nsp);
task_unlock(tsk); if (!nsp) {
rcu_read_unlock(); return -ESRCH;
}
#ifdef CONFIG_PID_NS if (flags & CLONE_NEWPID) {
pid_ns = task_active_pid_ns(tsk); if (unlikely(!pid_ns)) {
rcu_read_unlock();
ret = -ESRCH; goto out;
}
get_pid_ns(pid_ns);
} #endif
/* * Install requested namespaces. The caller will have * verified earlier that the requested namespaces are * supported on this kernel. We don't report errors here * if a namespace is requested that isn't supported.
*/ #ifdef CONFIG_USER_NS if (flags & CLONE_NEWUSER) {
ret = validate_ns(nsset, &user_ns->ns); if (ret) goto out;
} #endif
if (flags & CLONE_NEWNS) {
ret = validate_ns(nsset, from_mnt_ns(nsp->mnt_ns)); if (ret) goto out;
}
#ifdef CONFIG_UTS_NS if (flags & CLONE_NEWUTS) {
ret = validate_ns(nsset, &nsp->uts_ns->ns); if (ret) goto out;
} #endif
#ifdef CONFIG_IPC_NS if (flags & CLONE_NEWIPC) {
ret = validate_ns(nsset, &nsp->ipc_ns->ns); if (ret) goto out;
} #endif
#ifdef CONFIG_PID_NS if (flags & CLONE_NEWPID) {
ret = validate_ns(nsset, &pid_ns->ns); if (ret) goto out;
} #endif
#ifdef CONFIG_CGROUPS if (flags & CLONE_NEWCGROUP) {
ret = validate_ns(nsset, &nsp->cgroup_ns->ns); if (ret) goto out;
} #endif
#ifdef CONFIG_NET_NS if (flags & CLONE_NEWNET) {
ret = validate_ns(nsset, &nsp->net_ns->ns); if (ret) goto out;
} #endif
#ifdef CONFIG_TIME_NS if (flags & CLONE_NEWTIME) {
ret = validate_ns(nsset, &nsp->time_ns->ns); if (ret) goto out;
} #endif
out: if (pid_ns)
put_pid_ns(pid_ns); if (nsp)
put_nsproxy(nsp);
put_user_ns(user_ns);
return ret;
}
/* * This is the point of no return. There are just a few namespaces * that do some actual work here and it's sufficiently minimal that * a separate ns_common operation seems unnecessary for now. * Unshare is doing the same thing. If we'll end up needing to do * more in a given namespace or a helper here is ultimately not * exported anymore a simple commit handler for each namespace * should be added to ns_common.
*/ staticvoid commit_nsset(struct nsset *nsset)
{ unsigned flags = nsset->flags; struct task_struct *me = current;
#ifdef CONFIG_USER_NS if (flags & CLONE_NEWUSER) { /* transfer ownership */
commit_creds(nsset_cred(nsset));
nsset->cred = NULL;
} #endif
/* We only need to commit if we have used a temporary fs_struct. */ if ((flags & CLONE_NEWNS) && (flags & ~CLONE_NEWNS)) {
set_fs_root(me->fs, &nsset->fs->root);
set_fs_pwd(me->fs, &nsset->fs->pwd);
}
#ifdef CONFIG_IPC_NS if (flags & CLONE_NEWIPC)
exit_sem(me); #endif
#ifdef CONFIG_TIME_NS if (flags & CLONE_NEWTIME)
timens_commit(me, nsset->nsproxy->time_ns); #endif
/* transfer ownership */
switch_task_namespaces(me, nsset->nsproxy);
nsset->nsproxy = NULL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.