/** * open_namespace - open a namespace * @ns: the namespace to open * * This will consume a reference to @ns indendent of success or failure. * * Return: A file descriptor on success or a negative error code on failure.
*/ int open_namespace(struct ns_common *ns)
{ struct path path __free(path_put) = {}; struct file *f; int err;
/* call first to consume reference */
err = path_from_stashed(&ns->stashed, nsfs_mnt, ns, &path); if (err < 0) return err;
CLASS(get_unused_fd, fd)(O_CLOEXEC); if (fd < 0) return fd;
f = dentry_open(&path, O_RDONLY, current_cred()); if (IS_ERR(f)) return PTR_ERR(f);
staticint copy_ns_info_to_user(conststruct mnt_namespace *mnt_ns, struct mnt_ns_info __user *uinfo, size_t usize, struct mnt_ns_info *kinfo)
{ /* * If userspace and the kernel have the same struct size it can just * be copied. If userspace provides an older struct, only the bits that * userspace knows about will be copied. If userspace provides a new * struct, only the bits that the kernel knows aobut will be copied and * the size value will be set to the size the kernel knows about.
*/
kinfo->size = min(usize, sizeof(*kinfo));
kinfo->mnt_ns_id = mnt_ns->seq;
kinfo->nr_mounts = READ_ONCE(mnt_ns->nr_mounts); /* Subtract the root mount of the mount namespace. */ if (kinfo->nr_mounts)
kinfo->nr_mounts--;
if (copy_to_user(uinfo, kinfo, kinfo->size)) return -EFAULT;
return 0;
}
staticbool nsfs_ioctl_valid(unsignedint cmd)
{ switch (cmd) { case NS_GET_USERNS: case NS_GET_PARENT: case NS_GET_NSTYPE: case NS_GET_OWNER_UID: case NS_GET_MNTNS_ID: case NS_GET_PID_FROM_PIDNS: case NS_GET_TGID_FROM_PIDNS: case NS_GET_PID_IN_PIDNS: case NS_GET_TGID_IN_PIDNS: return (_IOC_TYPE(cmd) == _IOC_TYPE(cmd));
}
/* Extensible ioctls require some extra handling. */ switch (_IOC_NR(cmd)) { case _IOC_NR(NS_MNT_GET_INFO): return extensible_ioctl_valid(cmd, NS_MNT_GET_INFO, MNT_NS_INFO_SIZE_VER0); case _IOC_NR(NS_MNT_GET_NEXT): return extensible_ioctl_valid(cmd, NS_MNT_GET_NEXT, MNT_NS_INFO_SIZE_VER0); case _IOC_NR(NS_MNT_GET_PREV): return extensible_ioctl_valid(cmd, NS_MNT_GET_PREV, MNT_NS_INFO_SIZE_VER0);
}
if (!nsfs_ioctl_valid(ioctl)) return -ENOIOCTLCMD;
ns = get_proc_ns(file_inode(filp)); switch (ioctl) { case NS_GET_USERNS: return open_related_ns(ns, ns_get_owner); case NS_GET_PARENT: if (!ns->ops->get_parent) return -EINVAL; return open_related_ns(ns, ns->ops->get_parent); case NS_GET_NSTYPE: return ns->ops->type; case NS_GET_OWNER_UID: if (ns->ops->type != CLONE_NEWUSER) return -EINVAL;
user_ns = container_of(ns, struct user_namespace, ns);
argp = (uid_t __user *) arg;
uid = from_kuid_munged(current_user_ns(), user_ns->owner); return put_user(uid, argp); case NS_GET_MNTNS_ID: {
__u64 __user *idp;
__u64 id;
if (ns->ops->type != CLONE_NEWNS) return -EINVAL;
mnt_ns = container_of(ns, struct mnt_namespace, ns);
idp = (__u64 __user *)arg;
id = mnt_ns->seq; return put_user(id, idp);
} case NS_GET_PID_FROM_PIDNS:
fallthrough; case NS_GET_TGID_FROM_PIDNS:
fallthrough; case NS_GET_PID_IN_PIDNS:
fallthrough; case NS_GET_TGID_IN_PIDNS: { if (ns->ops->type != CLONE_NEWPID) return -EINVAL;
ret = -ESRCH;
pid_ns = container_of(ns, struct pid_namespace, ns);
guard(rcu)();
if (ioctl == NS_GET_PID_IN_PIDNS ||
ioctl == NS_GET_TGID_IN_PIDNS)
tsk = find_task_by_vpid(arg); else
tsk = find_task_by_pid_ns(arg, pid_ns); if (!tsk) break;
switch (ioctl) { case NS_GET_PID_FROM_PIDNS:
ret = task_pid_vnr(tsk); break; case NS_GET_TGID_FROM_PIDNS:
ret = task_tgid_vnr(tsk); break; case NS_GET_PID_IN_PIDNS:
ret = task_pid_nr_ns(tsk, pid_ns); break; case NS_GET_TGID_IN_PIDNS:
ret = task_tgid_nr_ns(tsk, pid_ns); break; default:
ret = 0; break;
}
if (usize < MNT_NS_INFO_SIZE_VER0) return -EINVAL;
mnt_ns = get_sequential_mnt_ns(to_mnt_ns(ns), previous); if (IS_ERR(mnt_ns)) return PTR_ERR(mnt_ns);
ns = to_ns_common(mnt_ns); /* Transfer ownership of @mnt_ns reference to @path. */
ret = path_from_stashed(&ns->stashed, nsfs_mnt, ns, &path); if (ret) return ret;
CLASS(get_unused_fd, fd)(O_CLOEXEC); if (fd < 0) return fd;
f = dentry_open(&path, O_RDONLY, current_cred()); if (IS_ERR(f)) return PTR_ERR(f);
if (uinfo) { /* * If @uinfo is passed return all information about the * mount namespace as well.
*/
ret = copy_ns_info_to_user(to_mnt_ns(ns), uinfo, usize, &kinfo); if (ret) return ret;
}
/* Transfer reference of @f to caller's fdtable. */
fd_install(fd, no_free_ptr(f)); /* File descriptor is live so hand it off to the caller. */ return take_fd(fd);
} default:
ret = -ENOTTY;
}
return ret;
}
int ns_get_name(char *buf, size_t size, struct task_struct *task, conststruct proc_ns_operations *ns_ops)
{ struct ns_common *ns; int res = -ENOENT; constchar *name;
ns = ns_ops->get(task); if (ns) {
name = ns_ops->real_ns_name ? : ns_ops->name;
res = snprintf(buf, size, "%s:[%u]", name, ns->inum);
ns_ops->put(ns);
} return res;
}
/** * ns_match() - Returns true if current namespace matches dev/ino provided. * @ns: current namespace * @dev: dev_t from nsfs that will be matched against current nsfs * @ino: ino_t from nsfs that will be matched against current nsfs * * Return: true if dev and ino matches the current nsfs.
*/ bool ns_match(conststruct ns_common *ns, dev_t dev, ino_t ino)
{ return (ns->inum == ino) && (nsfs_mnt->mnt_sb->s_dev == dev);
}
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 und die Messung sind noch experimentell.