Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1443665 > unrolled thread
| Started by | Andrey Vagin <avagin@openvz.org> |
|---|---|
| First post | 2016-07-14 20:30 +0200 |
| Last post | 2016-07-24 07:10 +0200 |
| Articles | 20 on this page of 29 — 6 participants |
Back to article view | Back to linux.kernel
[PATCH 0/5 RFC] Add an interface to discover relationships between namespaces Andrey Vagin <avagin@openvz.org> - 2016-07-14 20:30 +0200
[PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace Andrey Vagin <avagin@openvz.org> - 2016-07-14 20:30 +0200
Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace "W. Trevor King" <wking@tremily.us> - 2016-07-14 21:10 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces Andrey Vagin <avagin@openvz.org> - 2016-07-15 00:10 +0200
[PATCH 5/5] tools/testing: add a test to check nsfs ioctl-s Andrey Vagin <avagin@openvz.org> - 2016-07-15 04:20 +0200
[PATCH 4/5] nsfs: add ioctl to get a parent namespace Andrey Vagin <avagin@openvz.org> - 2016-07-15 04:20 +0200
Re: [PATCH 4/5] nsfs: add ioctl to get a parent namespace ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 07:30 +0200
[PATCH 3/5] nsfs: add ioctl to get an owning user namespace for ns file descriptor Andrey Vagin <avagin@openvz.org> - 2016-07-15 04:20 +0200
[PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace Andrey Vagin <avagin@openvz.org> - 2016-07-15 04:20 +0200
Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 07:20 +0200
Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 16:50 +0200
Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace "W. Trevor King" <wking@tremily.us> - 2016-07-24 19:10 +0200
Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace "W. Trevor King" <wking@tremily.us> - 2016-07-24 19:00 +0200
Re: [PATCH 1/5] namespaces: move user_ns into ns_common ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 07:20 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 07:30 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2016-07-21 16:50 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces Andrey Vagin <avagin@openvz.org> - 2016-07-22 20:30 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2016-07-25 13:50 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-25 15:40 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> - 2016-07-25 16:50 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "Serge E. Hallyn" <serge@hallyn.com> - 2016-07-25 17:00 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-25 17:40 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-25 17:20 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "W. Trevor King" <wking@tremily.us> - 2016-07-23 23:20 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces James Bottomley <James.Bottomley@HansenPartnership.com> - 2016-07-23 23:40 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "W. Trevor King" <wking@tremily.us> - 2016-07-24 00:10 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 00:20 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces "W. Trevor King" <wking@tremily.us> - 2016-07-24 00:40 +0200
Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces ebiederm@xmission.com (Eric W. Biederman) - 2016-07-24 07:10 +0200
Page 1 of 2 [1] 2 Next page →
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-14 20:30 +0200 |
| Subject | [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces |
| Message-ID | <rUTyx-4Je-5@gated-at.bofh.it> |
Each namespace has an owning user namespace and now there is not way to discover these relationships. Pid and user namepaces are hierarchical. There is no way to discover parent-child relationships too. Why we may want to know relationships between namespaces? One use would be visualization, in order to understand the running system. Another would be to answer the question: what capability does process X have to perform operations on a resource governed by namespace Y? One more use-case (which usually called abnormal) is checkpoint/restart. In CRIU we age going to dump and restore nested namespaces. There [1] was a discussion about which interface to choose to determing relationships between namespaces. Eric suggested to add two ioctl-s [2]: > Grumble, Grumble. I think this may actually a case for creating ioctls > for these two cases. Now that random nsfs file descriptors are bind > mountable the original reason for using proc files is not as pressing. > > One ioctl for the user namespace that owns a file descriptor. > One ioctl for the parent namespace of a namespace file descriptor. Here is an implementaions of these ioctl-s. [1] https://lkml.org/lkml/2016/7/6/158 [2] https://lkml.org/lkml/2016/7/9/101 Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> Cc: "W. Trevor King" <wking@tremily.us> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Serge Hallyn <serge.hallyn@canonical.com> -- 2.5.5
[toc] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-14 20:30 +0200 |
| Subject | [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rUTyy-4Je-41@gated-at.bofh.it> |
| In reply to | #1443665 |
Return -EPERM if an owning user namespace is outside of a process
current user namespace.
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
include/linux/user_namespace.h | 7 +++++++
kernel/user_namespace.c | 24 ++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index a941b44..e416b76 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -76,6 +76,8 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t,
extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
extern int proc_setgroups_show(struct seq_file *m, void *v);
extern bool userns_may_setgroups(const struct user_namespace *ns);
+
+struct ns_common *ns_get_owner(struct ns_common *ns);
#else
static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -104,6 +106,11 @@ static inline bool userns_may_setgroups(const struct user_namespace *ns)
{
return true;
}
+
+static inline struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ return ERR_PTR(-ENOENT);
+}
#endif
#endif /* _LINUX_USER_H */
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index a5bc78c..6382e5e 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -994,6 +994,30 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
return commit_creds(cred);
}
+struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ const struct cred *cred = current_cred();
+ struct user_namespace *user_ns, *p;
+
+ user_ns = p = ns->user_ns;
+ if (user_ns == NULL) { /* ns is init_user_ns */
+ /* Unprivileged user should not know that it's init_user_ns. */
+ if (capable(CAP_SYS_ADMIN))
+ return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EPERM);
+ }
+
+ for (;;) {
+ if (p == cred->user_ns)
+ break;
+ if (p == &init_user_ns)
+ return ERR_PTR(-EPERM);
+ p = p->parent;
+ }
+
+ return &get_user_ns(user_ns)->ns;
+}
+
const struct proc_ns_operations userns_operations = {
.name = "user",
.type = CLONE_NEWUSER,
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | "W. Trevor King" <wking@tremily.us> |
|---|---|
| Date | 2016-07-14 21:10 +0200 |
| Subject | Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rUUbf-5bU-7@gated-at.bofh.it> |
| In reply to | #1443667 |
[Multipart message — attachments visible in raw view] — view raw
On Thu, Jul 14, 2016 at 11:20:16AM -0700, Andrey Vagin wrote:
> +struct ns_common *ns_get_owner(struct ns_common *ns)
> +{
> + const struct cred *cred = current_cred();
> + struct user_namespace *user_ns, *p;
> +
> + user_ns = p = ns->user_ns;
> + if (user_ns == NULL) { /* ns is init_user_ns */
> + /* Unprivileged user should not know that it's init_user_ns. */
> + if (capable(CAP_SYS_ADMIN))
> + return ERR_PTR(-ENOENT);
> + return ERR_PTR(-EPERM);
> + }
> +
> + for (;;) {
> + if (p == cred->user_ns)
> + break;
> + if (p == &init_user_ns)
> + return ERR_PTR(-EPERM);
> + p = p->parent;
> + }
> +
> + return &get_user_ns(user_ns)->ns;
> +}
I'm still not sure we need the CAP_SYS_ADMIN check [1]. Maybe “you
have an open file descriptor for the namespace” means you've already
been authorized to access the parent information (e.g. via POSIX
permissions on /proc/<pid>/ns/… or the bind-mounted namespace).
Whether you can get the parent information probably depends whether
you can use setns to join the parent namespace (I haven't looked up
the backing code for that).
But whichever way we go there, I think we do want to be consistent
between init_user_ns and other namespaces. So we should have a
CAP_SYS_ADMIN check for init_user_ns if and only if we also have a
CAP_SYS_ADMIN check for the returned parent in the non-init_user_ns
case as well:
user_ns = p = ns->user_ns;
if (user_ns == NULL) { /* ns is init_user_ns */
/* Unprivileged user should not know that it's init_user_ns. */
if (capable(CAP_SYS_ADMIN))
return ERR_PTR(-ENOENT);
return ERR_PTR(-EPERM);
} else if (! capable_in(user_ns, CAP_SYS_ADMIN)) {
/* Unprivileged user should not know about the owning user ns. */
return ERR_PTR(-ENOENT);
}
Although I'm not sure what the real name for capable_in is, or even if
it exists.
Cheers,
Trevor
[1]: https://github.com/avagin/linux-task-diag/commit/2663bc803d324785e328261f3c07a0fef37d2088#commitcomment-18223327
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[toc] | [prev] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-15 00:10 +0200 |
| Subject | Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces |
| Message-ID | <rUWZs-6XY-11@gated-at.bofh.it> |
| In reply to | #1443665 |
Hello, I forgot to add --cc-cover for git send-email, so everyone who is in Cc got only a cover letter. All messages were sent in mail lists. Sorry for inconvenience. On Thu, Jul 14, 2016 at 11:20 AM, Andrey Vagin <avagin@openvz.org> wrote: > Each namespace has an owning user namespace and now there is not way > to discover these relationships. > > Pid and user namepaces are hierarchical. There is no way to discover > parent-child relationships too. > > Why we may want to know relationships between namespaces? > > One use would be visualization, in order to understand the running system. > Another would be to answer the question: what capability does process X have to > perform operations on a resource governed by namespace Y? > > One more use-case (which usually called abnormal) is checkpoint/restart. > In CRIU we age going to dump and restore nested namespaces. > > There [1] was a discussion about which interface to choose to determing > relationships between namespaces. > > Eric suggested to add two ioctl-s [2]: >> Grumble, Grumble. I think this may actually a case for creating ioctls >> for these two cases. Now that random nsfs file descriptors are bind >> mountable the original reason for using proc files is not as pressing. >> >> One ioctl for the user namespace that owns a file descriptor. >> One ioctl for the parent namespace of a namespace file descriptor. > > Here is an implementaions of these ioctl-s. > > [1] https://lkml.org/lkml/2016/7/6/158 > [2] https://lkml.org/lkml/2016/7/9/101 > > Cc: "Eric W. Biederman" <ebiederm@xmission.com> > Cc: James Bottomley <James.Bottomley@HansenPartnership.com> > Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> > Cc: "W. Trevor King" <wking@tremily.us> > Cc: Alexander Viro <viro@zeniv.linux.org.uk> > Cc: Serge Hallyn <serge.hallyn@canonical.com> > > -- > 2.5.5 >
[toc] | [prev] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-15 04:20 +0200 |
| Subject | [PATCH 5/5] tools/testing: add a test to check nsfs ioctl-s |
| Message-ID | <rV0Tn-ZV-3@gated-at.bofh.it> |
| In reply to | #1443807 |
There are two new ioctl-s:
One ioctl for the user namespace that owns a file descriptor.
One ioctl for the parent namespace of a namespace file descriptor.
The test checks that these ioctl-s works and that they handle a case
when a target namespace is outside of the current process namespace.
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/nsfs/Makefile | 12 +++++
tools/testing/selftests/nsfs/owner.c | 91 +++++++++++++++++++++++++++++++++++
tools/testing/selftests/nsfs/pidns.c | 74 ++++++++++++++++++++++++++++
4 files changed, 178 insertions(+)
create mode 100644 tools/testing/selftests/nsfs/Makefile
create mode 100644 tools/testing/selftests/nsfs/owner.c
create mode 100644 tools/testing/selftests/nsfs/pidns.c
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index ff9e5f2..f770dba 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -15,6 +15,7 @@ TARGETS += memory-hotplug
TARGETS += mount
TARGETS += mqueue
TARGETS += net
+TARGETS += nsfs
TARGETS += powerpc
TARGETS += pstore
TARGETS += ptrace
diff --git a/tools/testing/selftests/nsfs/Makefile b/tools/testing/selftests/nsfs/Makefile
new file mode 100644
index 0000000..2306054
--- /dev/null
+++ b/tools/testing/selftests/nsfs/Makefile
@@ -0,0 +1,12 @@
+TEST_PROGS := owner pidns
+
+CFLAGS := -Wall -Werror
+
+all: owner pidns
+owner: owner.c
+pidns: pidns.c
+
+clean:
+ $(RM) owner pidns
+
+include ../lib.mk
diff --git a/tools/testing/selftests/nsfs/owner.c b/tools/testing/selftests/nsfs/owner.c
new file mode 100644
index 0000000..c97aa50
--- /dev/null
+++ b/tools/testing/selftests/nsfs/owner.c
@@ -0,0 +1,91 @@
+#define _GNU_SOURCE
+#include <sched.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+
+#define NSIO 0xb7
+#define NS_GET_USERNS _IO(NSIO, 0x1)
+
+#define pr_err(fmt, ...) \
+ ({ \
+ fprintf(stderr, "%s:%d:" fmt ": %m\n", \
+ __func__, __LINE__, ##__VA_ARGS__); \
+ 1; \
+ })
+
+int main(int argc, char *argvp[])
+{
+ int pfd[2], ns, uns, init_uns;
+ struct stat st1, st2;
+ char path[128];
+ pid_t pid;
+ char c;
+
+ if (pipe(pfd))
+ return 1;
+
+ pid = fork();
+ if (pid < 0)
+ return pr_err("fork");
+ if (pid == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+ if (unshare(CLONE_NEWUTS | CLONE_NEWUSER))
+ return pr_err("unshare");
+ close(pfd[0]);
+ close(pfd[1]);
+ while (1)
+ sleep(1);
+ return 0;
+ }
+ close(pfd[1]);
+ if (read(pfd[0], &c, 1) != 0)
+ return pr_err("Unable to read from pipe");
+ close(pfd[0]);
+
+ snprintf(path, sizeof(path), "/proc/%d/ns/uts", pid);
+ ns = open(path, O_RDONLY);
+ if (ns < 0)
+ return pr_err("Unable to open %s", path);
+
+ uns = ioctl(ns, NS_GET_USERNS);
+ if (uns < 0)
+ return pr_err("Unable to get an owning user namespace");
+
+ if (fstat(uns, &st1))
+ return pr_err("fstat");
+
+ snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
+ if (stat(path, &st2))
+ return pr_err("stat");
+
+ if (st1.st_ino != st2.st_ino)
+ return pr_err("NS_GET_USERNS returned a wrong namespace");
+
+ init_uns = ioctl(uns, NS_GET_USERNS);
+ if (uns < 0)
+ return pr_err("Unable to get an owning user namespace");
+
+ if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != ENOENT)
+ return pr_err("Don't get ENOENT");
+
+ if (unshare(CLONE_NEWUSER))
+ return pr_err("unshare");
+
+ if (ioctl(ns, NS_GET_USERNS) >= 0 || errno != EPERM)
+ return pr_err("Don't get EPERM");
+ if (ioctl(init_uns, NS_GET_USERNS) >= 0 || errno != EPERM)
+ return pr_err("Don't get EPERM");
+
+ kill(pid, SIGKILL);
+ wait(NULL);
+ return 0;
+}
diff --git a/tools/testing/selftests/nsfs/pidns.c b/tools/testing/selftests/nsfs/pidns.c
new file mode 100644
index 0000000..99b1131
--- /dev/null
+++ b/tools/testing/selftests/nsfs/pidns.c
@@ -0,0 +1,74 @@
+#define _GNU_SOURCE
+#include <sched.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+
+#define pr_err(fmt, ...) \
+ ({ \
+ fprintf(stderr, "%s:%d:" fmt ": %m\n", \
+ __func__, __LINE__, ##__VA_ARGS__); \
+ 1; \
+ })
+
+#define NSIO 0xb7
+#define NS_GET_USERNS _IO(NSIO, 0x1)
+#define NS_GET_PARENT _IO(NSIO, 0x2)
+
+#define __stack_aligned__ __attribute__((aligned(16)))
+struct cr_clone_arg {
+ char stack[128] __stack_aligned__;
+ char stack_ptr[0];
+};
+
+static int child(void *args)
+{
+ prctl(PR_SET_PDEATHSIG, SIGKILL);
+ while (1)
+ sleep(1);
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ char path[] = "/proc/0123456789/ns/pid";
+ struct cr_clone_arg ca;
+ struct stat st1, st2;
+ int ns, pns;
+ pid_t pid;
+
+ pid = clone(child, ca.stack_ptr, CLONE_NEWPID | SIGCLD, NULL);
+ if (pid < 0)
+ return pr_err("clone");
+
+ snprintf(path, sizeof(path), "/proc/%d/ns/pid", pid);
+ ns = open(path, O_RDONLY);
+ if (ns < 0)
+ return pr_err("Unable to open %s", path);
+
+ pns = ioctl(ns, NS_GET_PARENT);
+ if (pns < 0)
+ return pr_err("Unable to get a parent pidns");
+
+ if (stat("/proc/self/ns/pid", &st2))
+ return pr_err("Unable to stat %s", path);
+ if (fstat(pns, &st1))
+ return pr_err("Unable to stat the parent pidns");
+ if (st1.st_ino != st2.st_ino)
+ return pr_err("NS_GET_PARENT returned a wrong namespace");
+
+ if (ioctl(pns, NS_GET_PARENT) >= 0 || errno != ENOENT)
+ return pr_err("Don't get ENOENT");;
+
+ kill(pid, SIGKILL);
+ wait(NULL);
+ return 0;
+}
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-15 04:20 +0200 |
| Subject | [PATCH 4/5] nsfs: add ioctl to get a parent namespace |
| Message-ID | <rV0Tn-ZV-9@gated-at.bofh.it> |
| In reply to | #1443807 |
Pid and user namepaces are hierarchical. There is no way to discover
parent-child relationships.
In a future we will use this interface to dump and restore nested
namespaces.
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
fs/nsfs.c | 4 ++++
include/linux/proc_ns.h | 1 +
include/uapi/linux/nsfs.h | 1 +
kernel/pid_namespace.c | 26 ++++++++++++++++++++++++++
kernel/user_namespace.c | 1 +
5 files changed, 33 insertions(+)
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 1e5d2d0..b607a42 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -169,6 +169,10 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
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);
default:
return -ENOTTY;
}
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index de0e771..1c9f720 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -18,6 +18,7 @@ struct proc_ns_operations {
struct ns_common *(*get)(struct task_struct *task);
void (*put)(struct ns_common *ns);
int (*install)(struct nsproxy *nsproxy, struct ns_common *ns);
+ struct ns_common *(*get_parent)(struct ns_common *ns);
};
extern const struct proc_ns_operations netns_operations;
diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h
index 7a09ede..88098ea 100644
--- a/include/uapi/linux/nsfs.h
+++ b/include/uapi/linux/nsfs.h
@@ -5,5 +5,6 @@
#define NSIO 0xb7
#define NS_GET_USERNS _IO(NSIO, 0x1)
+#define NS_GET_PARENT _IO(NSIO, 0x2)
#endif /* __LINUX_NSFS_H */
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 3529a03..a63adfb 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -388,12 +388,38 @@ static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns)
return 0;
}
+static struct ns_common *pidns_get_parent(struct ns_common *ns)
+{
+ struct pid_namespace *active = task_active_pid_ns(current);
+ struct pid_namespace *pid_ns, *p;
+
+ pid_ns = to_pid_ns(ns);
+ if (pid_ns == &init_pid_ns) {
+ if (capable(CAP_SYS_ADMIN))
+ return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EPERM);
+ }
+
+ pid_ns = p = pid_ns->parent;
+
+ for (;;) {
+ if (p == active)
+ break;
+ if (p == &init_pid_ns)
+ return ERR_PTR(-EPERM);
+ p = p->parent;
+ }
+
+ return &get_pid_ns(pid_ns)->ns;
+}
+
const struct proc_ns_operations pidns_operations = {
.name = "pid",
.type = CLONE_NEWPID,
.get = pidns_get,
.put = pidns_put,
.install = pidns_install,
+ .get_parent = pidns_get_parent,
};
static __init int pid_namespaces_init(void)
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 6382e5e..d6ba0b8 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -1024,6 +1024,7 @@ const struct proc_ns_operations userns_operations = {
.get = userns_get,
.put = userns_put,
.install = userns_install,
+ .get_parent = ns_get_owner,
};
static __init int user_namespaces_init(void)
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-24 07:30 +0200 |
| Subject | Re: [PATCH 4/5] nsfs: add ioctl to get a parent namespace |
| Message-ID | <rYk9c-3Qv-9@gated-at.bofh.it> |
| In reply to | #1443878 |
Andrey Vagin <avagin@openvz.org> writes:
> diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
> index 3529a03..a63adfb 100644
> --- a/kernel/pid_namespace.c
> +++ b/kernel/pid_namespace.c
> @@ -388,12 +388,38 @@ static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns)
> return 0;
> }
>
> +static struct ns_common *pidns_get_parent(struct ns_common *ns)
> +{
> + struct pid_namespace *active = task_active_pid_ns(current);
> + struct pid_namespace *pid_ns, *p;
> +
> + pid_ns = to_pid_ns(ns);
> + if (pid_ns == &init_pid_ns) {
> + if (capable(CAP_SYS_ADMIN))
> + return ERR_PTR(-ENOENT);
> + return ERR_PTR(-EPERM);
> + }
> +
> + pid_ns = p = pid_ns->parent;
> +
> + for (;;) {
> + if (p == active)
> + break;
> + if (p == &init_pid_ns)
> + return ERR_PTR(-EPERM);
> + p = p->parent;
> + }
Similarly to the user namespace issue the permission check here needs to
be:
if (!ns_capable(pid_ns->user_ns, CAP_SYS_ADMIN)
return ERR_PTR(-EPERM);
> +
> + return &get_pid_ns(pid_ns)->ns;
> +}
> +
> const struct proc_ns_operations pidns_operations = {
> .name = "pid",
> .type = CLONE_NEWPID,
> .get = pidns_get,
> .put = pidns_put,
> .install = pidns_install,
> + .get_parent = pidns_get_parent,
> };
>
Eric
[toc] | [prev] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-15 04:20 +0200 |
| Subject | [PATCH 3/5] nsfs: add ioctl to get an owning user namespace for ns file descriptor |
| Message-ID | <rV0Tn-ZV-11@gated-at.bofh.it> |
| In reply to | #1443807 |
Each namespace has an owning user namespace and now there is not way
to discover these relationships.
Understending namespaces relationships allows to answer the question:
what capability does process X have to perform operations on a resource
governed by namespace Y?
After a long discussion, Eric W. Biederman proposed to use ioctl-s for
this purpose.
The NS_GET_USERNS ioctl returns a file descriptor to an owning user
namespace.
It returns EPERM if a target namespace is outside of a current user
namespace.
Link: https://lkml.org/lkml/2016/7/6/158
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
fs/nsfs.c | 94 ++++++++++++++++++++++++++++++++++++++++-------
include/uapi/linux/nsfs.h | 9 +++++
2 files changed, 90 insertions(+), 13 deletions(-)
create mode 100644 include/uapi/linux/nsfs.h
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 8f20d60..1e5d2d0 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -5,11 +5,16 @@
#include <linux/magic.h>
#include <linux/ktime.h>
#include <linux/seq_file.h>
+#include <linux/user_namespace.h>
+#include <linux/nsfs.h>
static struct vfsmount *nsfs_mnt;
+static long ns_ioctl(struct file *filp, unsigned int ioctl,
+ unsigned long arg);
static const struct file_operations ns_file_operations = {
.llseek = no_llseek,
+ .unlocked_ioctl = ns_ioctl,
};
static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
@@ -44,22 +49,14 @@ static void nsfs_evict(struct inode *inode)
ns->ops->put(ns);
}
-void *ns_get_path(struct path *path, struct task_struct *task,
- const struct proc_ns_operations *ns_ops)
+static void *__ns_get_path(struct path *path, struct ns_common *ns)
{
struct vfsmount *mnt = mntget(nsfs_mnt);
struct qstr qname = { .name = "", };
struct dentry *dentry;
struct inode *inode;
- struct ns_common *ns;
unsigned long d;
-again:
- ns = ns_ops->get(task);
- if (!ns) {
- mntput(mnt);
- return ERR_PTR(-ENOENT);
- }
rcu_read_lock();
d = atomic_long_read(&ns->stashed);
if (!d)
@@ -68,7 +65,7 @@ again:
if (!lockref_get_not_dead(&dentry->d_lockref))
goto slow;
rcu_read_unlock();
- ns_ops->put(ns);
+ ns->ops->put(ns);
got_it:
path->mnt = mnt;
path->dentry = dentry;
@@ -77,7 +74,7 @@ slow:
rcu_read_unlock();
inode = new_inode_pseudo(mnt->mnt_sb);
if (!inode) {
- ns_ops->put(ns);
+ ns->ops->put(ns);
mntput(mnt);
return ERR_PTR(-ENOMEM);
}
@@ -95,17 +92,88 @@ slow:
return ERR_PTR(-ENOMEM);
}
d_instantiate(dentry, inode);
- dentry->d_fsdata = (void *)ns_ops;
+ dentry->d_fsdata = (void *)ns->ops;
d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
if (d) {
d_delete(dentry); /* make sure ->d_prune() does nothing */
dput(dentry);
cpu_relax();
- goto again;
+ return ERR_PTR(-EAGAIN);
}
goto got_it;
}
+void *ns_get_path(struct path *path, struct task_struct *task,
+ const struct proc_ns_operations *ns_ops)
+{
+ struct ns_common *ns;
+ void *ret;
+
+again:
+ ns = ns_ops->get(task);
+ if (!ns)
+ return ERR_PTR(-ENOENT);
+
+ ret = __ns_get_path(path, ns);
+ if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN)
+ goto again;
+ return ret;
+}
+
+int open_related_ns(struct ns_common *ns,
+ struct ns_common *(*get_ns)(struct ns_common *ns))
+{
+ struct path path = {};
+ struct file *f;
+ void *err;
+ int fd;
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ while (1) {
+ struct ns_common *parent;
+
+ parent = get_ns(ns);
+ if (IS_ERR(parent)) {
+ put_unused_fd(fd);
+ return PTR_ERR(parent);
+ }
+
+ err = __ns_get_path(&path, parent);
+ if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN)
+ continue;
+ break;
+ }
+ if (IS_ERR(err)) {
+ put_unused_fd(fd);
+ return PTR_ERR(err);
+ }
+
+ f = dentry_open(&path, O_RDONLY, current_cred());
+ path_put(&path);
+ if (IS_ERR(f)) {
+ put_unused_fd(fd);
+ fd = PTR_ERR(f);
+ } else
+ fd_install(fd, f);
+ return fd;
+}
+
+static long ns_ioctl(struct file *filp, unsigned int ioctl,
+ unsigned long arg)
+{
+ struct ns_common *ns = get_proc_ns(file_inode(filp));
+
+ switch (ioctl) {
+ case NS_GET_USERNS:
+ return open_related_ns(ns, ns_get_owner);
+ default:
+ return -ENOTTY;
+ }
+}
+
int ns_get_name(char *buf, size_t size, struct task_struct *task,
const struct proc_ns_operations *ns_ops)
{
diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h
new file mode 100644
index 0000000..7a09ede
--- /dev/null
+++ b/include/uapi/linux/nsfs.h
@@ -0,0 +1,9 @@
+#ifndef __LINUX_NSFS_H
+#define __LINUX_NSFS_H
+
+#include <linux/ioctl.h>
+
+#define NSIO 0xb7
+#define NS_GET_USERNS _IO(NSIO, 0x1)
+
+#endif /* __LINUX_NSFS_H */
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-15 04:20 +0200 |
| Subject | [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rV0Tn-ZV-15@gated-at.bofh.it> |
| In reply to | #1443807 |
Return -EPERM if an owning user namespace is outside of a process
current user namespace.
Signed-off-by: Andrey Vagin <avagin@openvz.org>
---
include/linux/user_namespace.h | 7 +++++++
kernel/user_namespace.c | 24 ++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index a941b44..e416b76 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -76,6 +76,8 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t,
extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
extern int proc_setgroups_show(struct seq_file *m, void *v);
extern bool userns_may_setgroups(const struct user_namespace *ns);
+
+struct ns_common *ns_get_owner(struct ns_common *ns);
#else
static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -104,6 +106,11 @@ static inline bool userns_may_setgroups(const struct user_namespace *ns)
{
return true;
}
+
+static inline struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ return ERR_PTR(-ENOENT);
+}
#endif
#endif /* _LINUX_USER_H */
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index a5bc78c..6382e5e 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -994,6 +994,30 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
return commit_creds(cred);
}
+struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ const struct cred *cred = current_cred();
+ struct user_namespace *user_ns, *p;
+
+ user_ns = p = ns->user_ns;
+ if (user_ns == NULL) { /* ns is init_user_ns */
+ /* Unprivileged user should not know that it's init_user_ns. */
+ if (capable(CAP_SYS_ADMIN))
+ return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EPERM);
+ }
+
+ for (;;) {
+ if (p == cred->user_ns)
+ break;
+ if (p == &init_user_ns)
+ return ERR_PTR(-EPERM);
+ p = p->parent;
+ }
+
+ return &get_user_ns(user_ns)->ns;
+}
+
const struct proc_ns_operations userns_operations = {
.name = "user",
.type = CLONE_NEWUSER,
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-24 07:20 +0200 |
| Subject | Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rYjZv-3Nk-1@gated-at.bofh.it> |
| In reply to | #1443880 |
Andrey Vagin <avagin@openvz.org> writes:
> Return -EPERM if an owning user namespace is outside of a process
> current user namespace.
>
> diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
> index a5bc78c..6382e5e 100644
> --- a/kernel/user_namespace.c
> +++ b/kernel/user_namespace.c
> @@ -994,6 +994,30 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
> return commit_creds(cred);
> }
>
> +struct ns_common *ns_get_owner(struct ns_common *ns)
> +{
> + const struct cred *cred = current_cred();
> + struct user_namespace *user_ns, *p;
> +
> + user_ns = p = ns->user_ns;
> + if (user_ns == NULL) { /* ns is init_user_ns */
> + /* Unprivileged user should not know that it's init_user_ns. */
> + if (capable(CAP_SYS_ADMIN))
> + return ERR_PTR(-ENOENT);
> + return ERR_PTR(-EPERM);
> + }
This permission check is not what I meant to request. This does not
handle nested user namespaces.
> + for (;;) {
> + if (p == cred->user_ns)
> + break;
> + if (p == &init_user_ns)
> + return ERR_PTR(-EPERM);
> + p = p->parent;
> + }
> +
The permission check really needs to be down here. And be:
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
return ERR_PTR(-EPERM).
That cleanly and easily handles more than a depth of a single user
namespace.
> + return &get_user_ns(user_ns)->ns;
> +}
> +
> const struct proc_ns_operations userns_operations = {
> .name = "user",
> .type = CLONE_NEWUSER,
Eric
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-24 16:50 +0200 |
| Subject | Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rYsT7-DS-9@gated-at.bofh.it> |
| In reply to | #1449052 |
Andrew Vagin <avagin@virtuozzo.com> writes:
> On Sun, Jul 24, 2016 at 12:03:49AM -0500, Eric W. Biederman wrote:
>> Andrey Vagin <avagin@openvz.org> writes:
>>
>> > Return -EPERM if an owning user namespace is outside of a process
>> > current user namespace.
>> >
>> > diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
>> > index a5bc78c..6382e5e 100644
>> > --- a/kernel/user_namespace.c
>> > +++ b/kernel/user_namespace.c
>> > @@ -994,6 +994,30 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
>> > return commit_creds(cred);
>> > }
>> >
>> > +struct ns_common *ns_get_owner(struct ns_common *ns)
>> > +{
>> > + const struct cred *cred = current_cred();
>> > + struct user_namespace *user_ns, *p;
>> > +
>> > + user_ns = p = ns->user_ns;
>> > + if (user_ns == NULL) { /* ns is init_user_ns */
>> > + /* Unprivileged user should not know that it's init_user_ns. */
>> > + if (capable(CAP_SYS_ADMIN))
>> > + return ERR_PTR(-ENOENT);
>> > + return ERR_PTR(-EPERM);
>> > + }
>>
>> This permission check is not what I meant to request. This does not
>> handle nested user namespaces.
>
> Here I handle a case when ns is init_user_ns. init_user_ns doesn't have
> a parent, so we need to return an error. We can't return ENOENT in all
> cases, because we don't want to expose "that file descriptor is for the
> root user namespace" to unprivileged users.
> (Trevor suggested to add this check and it looks resonable for me
> too).
Apologies. I was skimming and misread the code. I mistook that loop for
some useful part of getting the owner. Looking in more detail...
Your code says:
+struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ const struct cred *cred = current_cred();
+ struct user_namespace *user_ns, *p;
+
+ user_ns = p = ns->user_ns;
+ if (user_ns == NULL) { /* ns is init_user_ns */
+ /* Unprivileged user should not know that it's init_user_ns. */
+ if (capable(CAP_SYS_ADMIN))
+ return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EPERM);
+ }
+
+ for (;;) {
+ if (p == cred->user_ns)
+ break;
+ if (p == &init_user_ns)
+ return ERR_PTR(-EPERM);
+ p = p->parent;
+ }
+
+ return &get_user_ns(user_ns)->ns;
+}
And all else being equal it could say:
+struct ns_common *ns_get_owner(struct ns_common *ns)
s+{
+ struct user_namespace *user_ns = ns->user_ns;
+
+ /* Are we allowed to see the user namespace? */
+ if (!ns_capable(user_ns?user_ns:&init_user_ns, CAP_SYS_ADMIN))
+ return ERR_PTR(-EPERM);
+
+ if (!user_ns)
+ return ERR_PTR(-ENOENT);
+
+ return &get_user_ns(user_ns)->ns;
+}
Which I think is the root of my confusion. You hand rolled ns_capable,
and I did not recognize it because I was skimming, and just looking to
be certain the permission check was present.
Given that you have to hand roll the pid namespace check that hand
rolling may not be so bad. But it certainly was confusing the first
time I saw it especially without a comment.
Hmm.
I am not at all certain it makes sense to return -ENOENT.
Without the -ENOENT check the code is much cleaner, and clearer.
I may be blinkered but I don't see the value in letting someone know we
are talking about the initial namespace. If anything that information
is likely to cause issues with weird corner cases of checkpoint/restart,
as it acts different if you are in a container or not.
When things act different in a container that almost always is a source
of a problem somewhere.
So we could simplify the filter in the code to just this.
+struct ns_common *ns_get_owner(struct ns_common *ns)
+{
+ struct user_namespace *my_user_ns = current_user_ns();
+ struct user_namespace *owner, *p;
+
+ /* See if the owner is in the current user namespace */
+ owner = p = ns->user_ns;
+ for (;;) {
+ if (!p)
+ return ERR_PTR(-EPERM);
+ if (p == my_user_ns)
+ break;
+ p = p->parent;
+ }
+
+ return &get_user_ns(owner)->ns;
+}
And on reflection I do see the point of not using ns_capable as that
requires having privileges in a namespace while all we want here
is to see if someone is in a visible namespace.
So please ignore my comments about ns_capable on the pid namespace
parent.
But please simplify the loop and put an appropriate comment on it like I
have above. The fewer special cases the easier the code is to get
correct, and the easier it is to read.
Eric
[toc] | [prev] | [next] | [standalone]
| From | "W. Trevor King" <wking@tremily.us> |
|---|---|
| Date | 2016-07-24 19:10 +0200 |
| Subject | Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rYv4B-27v-1@gated-at.bofh.it> |
| In reply to | #1449151 |
[Multipart message — attachments visible in raw view] — view raw
On Sun, Jul 24, 2016 at 09:30:03AM -0500, Eric W. Biederman wrote:
> I am not at all certain it makes sense to return -ENOENT.
>
> Without the -ENOENT check the code is much cleaner, and clearer.
This is fine with me, and makes even more sense for owner (user)
namespaces than it does for net namespaces [1]. At least, I can't
think of a reason why the root user namespace would have special
userspace-visible behavior ;).
Cheers,
Trevor
[1]: http://thread.gmane.org/gmane.linux.kernel.api/20626/focus=30639
Subject: Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces
Date: Sat, 23 Jul 2016 23:51:07 -0500
Message-ID: <877fcboczo.fsf@x220.int.ebiederm.org>
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[toc] | [prev] | [next] | [standalone]
| From | "W. Trevor King" <wking@tremily.us> |
|---|---|
| Date | 2016-07-24 19:00 +0200 |
| Subject | Re: [PATCH 2/5] kernel: add a helper to get an owning user namespace for a namespace |
| Message-ID | <rYuUW-1OQ-9@gated-at.bofh.it> |
| In reply to | #1443880 |
[Multipart message — attachments visible in raw view] — view raw
On Thu, Jul 14, 2016 at 07:12:19PM -0700, Andrey Vagin wrote:
> +struct ns_common *ns_get_owner(struct ns_common *ns)
> +{
> + …
> + return &get_user_ns(user_ns)->ns;
> +}
Is there a reason to return the generic ‘struct ns_common *’ here
instead of ‘struct user_namespace *’? The current use case doesn't
need access to the additional information, but future ng_get_owner
callers might, and we know the returned namespace (if any) will be a
user namespace.
Cheers,
Trevor
--
This email may be signed or encrypted with GnuPG (http://www.gnupg.org).
For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-24 07:20 +0200 |
| Subject | Re: [PATCH 1/5] namespaces: move user_ns into ns_common |
| Message-ID | <rYjZv-3Nk-3@gated-at.bofh.it> |
| In reply to | #1443807 |
Andrey Vagin <avagin@openvz.org> writes:
> Every namespace has a pointer to an user namespace where is was created,
> but they're all privately embedded in the individual namespace specific
> structures.
>
> Now we are going to add an user-space interface to get an owning user
> namespace, so it looks reasonable to move it into ns_common.
>
> Originally this idea was suggested by James Bottomley.
I skimmed through this and I really don't like move user_ns into
ns_common. If for no other reason that it seems to have guarantteed
this patchset as written would not apply to my tree.
> diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
> index 8297e5b..a941b44 100644
> --- a/include/linux/user_namespace.h
> +++ b/include/linux/user_namespace.h
> @@ -27,11 +27,15 @@ struct user_namespace {
> struct uid_gid_map gid_map;
> struct uid_gid_map projid_map;
> atomic_t count;
> - struct user_namespace *parent;
> int level;
> kuid_t owner;
> kgid_t group;
> - struct ns_common ns;
> +
> + /* ->ns.user_ns and ->parent are synonyms */
> + union {
> + struct user_namespace *parent;
> + struct ns_common ns;
> + };
> unsigned long flags;
>
> /* Register of per-UID persistent keyrings for this namespace */
This union is unmaintainable. It is very easy for someone to change
ns_common and accidentially break this. The C standard does not
allow data to be accessed as either one union member or the other.
Which means semantically this code relies on undefined behavior, and
the compiler can do anything in this case and gcc has sometimes been
known to use that allowance.
Eric
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-24 07:30 +0200 |
| Message-ID | <rYk9c-3Qv-17@gated-at.bofh.it> |
| In reply to | #1443807 |
Andrey Vagin <avagin@openvz.org> writes: > Hello, > > I forgot to add --cc-cover for git send-email, so everyone who is in > Cc got only a cover letter. All messages were sent in mail lists. > > Sorry for inconvenience. Mostly the code looked sensible. But I had a couple of issues. Resend this in September (when the merge window is closed and I am back from vacation) and I will give this a thorough review and get this merged. Or possibly next week if Linus releases another -rc > On Thu, Jul 14, 2016 at 11:20 AM, Andrey Vagin <avagin@openvz.org> wrote: >> Each namespace has an owning user namespace and now there is not way >> to discover these relationships. >> >> Pid and user namepaces are hierarchical. There is no way to discover >> parent-child relationships too. >> >> Why we may want to know relationships between namespaces? >> >> One use would be visualization, in order to understand the running system. >> Another would be to answer the question: what capability does process X have to >> perform operations on a resource governed by namespace Y? >> >> One more use-case (which usually called abnormal) is checkpoint/restart. >> In CRIU we age going to dump and restore nested namespaces. >> >> There [1] was a discussion about which interface to choose to determing >> relationships between namespaces. >> >> Eric suggested to add two ioctl-s [2]: >>> Grumble, Grumble. I think this may actually a case for creating ioctls >>> for these two cases. Now that random nsfs file descriptors are bind >>> mountable the original reason for using proc files is not as pressing. >>> >>> One ioctl for the user namespace that owns a file descriptor. >>> One ioctl for the parent namespace of a namespace file descriptor. >> >> Here is an implementaions of these ioctl-s. >> >> [1] https://lkml.org/lkml/2016/7/6/158 >> [2] https://lkml.org/lkml/2016/7/9/101 >> >> Cc: "Eric W. Biederman" <ebiederm@xmission.com> >> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> >> Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> >> Cc: "W. Trevor King" <wking@tremily.us> >> Cc: Alexander Viro <viro@zeniv.linux.org.uk> >> Cc: Serge Hallyn <serge.hallyn@canonical.com> Eric
[toc] | [prev] | [next] | [standalone]
| From | "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> |
|---|---|
| Date | 2016-07-21 16:50 +0200 |
| Subject | Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces |
| Message-ID | <rXnsu-gG-27@gated-at.bofh.it> |
| In reply to | #1443665 |
Hi Andrey, On 07/14/2016 08:20 PM, Andrey Vagin wrote: > Each namespace has an owning user namespace and now there is not way > to discover these relationships. > > Pid and user namepaces are hierarchical. There is no way to discover > parent-child relationships too. > > Why we may want to know relationships between namespaces? > > One use would be visualization, in order to understand the running system. > Another would be to answer the question: what capability does process X have to > perform operations on a resource governed by namespace Y? > > One more use-case (which usually called abnormal) is checkpoint/restart. > In CRIU we age going to dump and restore nested namespaces. > > There [1] was a discussion about which interface to choose to determing > relationships between namespaces. > > Eric suggested to add two ioctl-s [2]: >> Grumble, Grumble. I think this may actually a case for creating ioctls >> for these two cases. Now that random nsfs file descriptors are bind >> mountable the original reason for using proc files is not as pressing. >> >> One ioctl for the user namespace that owns a file descriptor. >> One ioctl for the parent namespace of a namespace file descriptor. > > Here is an implementaions of these ioctl-s. Could you add here an of the API in detail: what do these FDs refer to, and how do you use them to solve the use case? And could you you add that info to the commit messages please. Thanks, Michael > [1] https://lkml.org/lkml/2016/7/6/158 > [2] https://lkml.org/lkml/2016/7/9/101 > > Cc: "Eric W. Biederman" <ebiederm@xmission.com> > Cc: James Bottomley <James.Bottomley@HansenPartnership.com> > Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> > Cc: "W. Trevor King" <wking@tremily.us> > Cc: Alexander Viro <viro@zeniv.linux.org.uk> > Cc: Serge Hallyn <serge.hallyn@canonical.com> > > -- > 2.5.5 > > -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/
[toc] | [prev] | [next] | [standalone]
| From | Andrey Vagin <avagin@openvz.org> |
|---|---|
| Date | 2016-07-22 20:30 +0200 |
| Subject | Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces |
| Message-ID | <rXNmW-WX-19@gated-at.bofh.it> |
| In reply to | #1447936 |
On Thu, Jul 21, 2016 at 11:48 PM, Michael Kerrisk (man-pages)
<mtk.manpages@gmail.com> wrote:
> Hi Andrey,
>
>
> On 07/21/2016 11:06 PM, Andrew Vagin wrote:
>>
>> On Thu, Jul 21, 2016 at 04:41:12PM +0200, Michael Kerrisk (man-pages)
>> wrote:
>>>
>>> Hi Andrey,
>>>
>>> On 07/14/2016 08:20 PM, Andrey Vagin wrote:
>>
>>
>> <snip>
>>
>>>
>>> Could you add here an of the API in detail: what do these FDs refer to,
>>> and how do you use them to solve the use case? And could you you add
>>> that info to the commit messages please.
>>
>>
>> Hi Michael,
>>
>> A patch for man-pages is attached. It adds the following text to
>> namespaces(7).
>>
>> Since Linux 4.X, the following ioctl(2) calls are supported for names‐
>> pace file descriptors. The correct syntax is:
>>
>> fd = ioctl(ns_fd, ioctl_type);
>>
>> where ioctl_type is one of the following:
>>
>> NS_GET_USERNS
>> Returns a file descriptor that refers to an owning user names‐
>> pace.
>>
>> NS_GET_PARENT
>> Returns a file descriptor that refers to a parent namespace.
>> This ioctl(2) can be used for pid and user namespaces. For user
>> namespaces, NS_GET_PARENT and NS_GET_USERNS have the same mean‐
>> ing.
>>
>> In addition to generic ioctl(2) errors, the following specific ones can
>> occur:
>>
>> EINVAL NS_GET_PARENT was called for a nonhierarchical namespace.
>>
>> EPERM The requested namespace is outside of the current namespace
>> scope.
>>
>> ENOENT ns_fd refers to the init namespace.
>
>
> Thanks for this. But still part of the question remains unanswered.
> How do we (in user-space) use the file descriptors to answer any of
> the questions that this patch series was designed to solve? (This
> info should be in the commit message and the man-pages patch.)
I'm sorry, but I am not sure that I understand what you ask.
Here are the origin questions:
Someone else then asked me a question that led me to wonder about
generally introspecting on the parental relationships between user
namespaces and the association of other namespaces types with user
namespaces. One use would be visualization, in order to understand the
running system. Another would be to answer the question I already
mentioned: what capability does process X have to perform operations
on a resource governed by namespace Y?
Here is an example which shows how we can get the owning namespace
inode number by using these ioctl-s.
$ ls -l /proc/13929/ns/pid
lrwxrwxrwx 1 root root 0 Jul 22 21:03 /proc/13929/ns/pid -> 'pid:[4026532228]'
$ ./nsowner /proc/13929/ns/pid
user:[4026532227]
The owning user namespace for pid:[4026532228] is user:[4026532227].
The nsowner tool is cimpiled from this code:
int main(int argc, char *argv[])
{
char buf[128], path[] = "/proc/self/fd/0123456789";
int ns, uns, ret;
ns = open(argv[1], O_RDONLY);
if (ns < 0)
return 1;
uns = ioctl(ns, NS_GET_USERNS);
if (uns < 0)
return 1;
snprintf(path, sizeof(path), "/proc/self/fd/%d", uns);
ret = readlink(path, buf, sizeof(buf) - 1);
if (ret < 0)
return 1;
buf[ret] = 0;
printf("%s\n", buf);
return 0;
}
Does this example answer to the origin question? If it isn't, could
you eloborate what you expect to see here.
And I wrote one more example which show all relationships between
namespaces. It enumirates all processes in a system, collects all
namespaces and determins parent and owning namespaces for each of
them, then it constructs a namespace tree and shows it.
Here is a code: https://gist.github.com/avagin/db805f95e15ffb0af7e559dbb8de4418
Here is an example of output for my test system:
[root@fc24 nsfs]# ./nstree
user:[4026531837]
\__ mnt:[4026532203]
\__ ipc:[4026531839]
\__ user:[4026532224]
\__ user:[4026532226]
\__ user:[4026532227]
\__ pid:[4026532228]
\__ pid:[4026532225]
\__ pid:[4026532228]
\__ user:[4026532221]
\__ pid:[4026532222]
\__ user:[4026532223]
\__ mnt:[4026532211]
\__ uts:[4026531838]
\__ cgroup:[4026531835]
\__ pid:[4026531836]
\__ pid:[4026532225]
\__ pid:[4026532228]
\__ pid:[4026532222]
\__ mnt:[4026531857]
\__ mnt:[4026531840]
\__ net:[4026531957]
Thanks,
Andrew
>
> Thanks,
>
> Michael
>
>
>>>> [1] https://lkml.org/lkml/2016/7/6/158
>>>> [2] https://lkml.org/lkml/2016/7/9/101
>>>>
>>>> Cc: "Eric W. Biederman" <ebiederm@xmission.com>
>>>> Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
>>>> Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com>
>>>> Cc: "W. Trevor King" <wking@tremily.us>
>>>> Cc: Alexander Viro <viro@zeniv.linux.org.uk>
>>>> Cc: Serge Hallyn <serge.hallyn@canonical.com>
>>>>
>>>> --
>>>> 2.5.5
>>>>
>>>>
>>>
>>>
>>> --
>>> Michael Kerrisk
>>> Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
>>> Linux/UNIX System Programming Training: http://man7.org/training/
>
>
>
> --
> Michael Kerrisk
> Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
> Linux/UNIX System Programming Training: http://man7.org/training/
> _______________________________________________
> Containers mailing list
> Containers@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/containers
[toc] | [prev] | [next] | [standalone]
| From | "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> |
|---|---|
| Date | 2016-07-25 13:50 +0200 |
| Subject | Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces |
| Message-ID | <rYMyt-43Y-1@gated-at.bofh.it> |
| In reply to | #1448717 |
Hi Andrey,
On 07/22/2016 08:25 PM, Andrey Vagin wrote:
> On Thu, Jul 21, 2016 at 11:48 PM, Michael Kerrisk (man-pages)
> <mtk.manpages@gmail.com> wrote:
>> Hi Andrey,
>>
>>
>> On 07/21/2016 11:06 PM, Andrew Vagin wrote:
>>>
>>> On Thu, Jul 21, 2016 at 04:41:12PM +0200, Michael Kerrisk (man-pages)
>>> wrote:
>>>>
>>>> Hi Andrey,
>>>>
>>>> On 07/14/2016 08:20 PM, Andrey Vagin wrote:
>>>
>>>
>>> <snip>
>>>
>>>>
>>>> Could you add here an of the API in detail: what do these FDs refer to,
>>>> and how do you use them to solve the use case? And could you you add
>>>> that info to the commit messages please.
>>>
>>>
>>> Hi Michael,
>>>
>>> A patch for man-pages is attached. It adds the following text to
>>> namespaces(7).
>>>
>>> Since Linux 4.X, the following ioctl(2) calls are supported for names‐
>>> pace file descriptors. The correct syntax is:
>>>
>>> fd = ioctl(ns_fd, ioctl_type);
>>>
>>> where ioctl_type is one of the following:
>>>
>>> NS_GET_USERNS
>>> Returns a file descriptor that refers to an owning user names‐
>>> pace.
>>>
>>> NS_GET_PARENT
>>> Returns a file descriptor that refers to a parent namespace.
>>> This ioctl(2) can be used for pid and user namespaces. For user
>>> namespaces, NS_GET_PARENT and NS_GET_USERNS have the same mean‐
>>> ing.
For each of the above, I think it is worth mentioning that the
close-on-exec flag is set for the returned file descriptor.
>>>
>>> In addition to generic ioctl(2) errors, the following specific ones can
>>> occur:
>>>
>>> EINVAL NS_GET_PARENT was called for a nonhierarchical namespace.
>>>
>>> EPERM The requested namespace is outside of the current namespace
>>> scope.
Perhaps add "and the caller does not have CAP_SYS_ADMIN" in the initial
user namespace"?
>>>
>>> ENOENT ns_fd refers to the init namespace.
>>
>>
>> Thanks for this. But still part of the question remains unanswered.
>> How do we (in user-space) use the file descriptors to answer any of
>> the questions that this patch series was designed to solve? (This
>> info should be in the commit message and the man-pages patch.)
>
> I'm sorry, but I am not sure that I understand what you ask.
>
> Here are the origin questions:
> Someone else then asked me a question that led me to wonder about
> generally introspecting on the parental relationships between user
> namespaces and the association of other namespaces types with user
> namespaces. One use would be visualization, in order to understand the
> running system. Another would be to answer the question I already
> mentioned: what capability does process X have to perform operations
> on a resource governed by namespace Y?
>
> Here is an example which shows how we can get the owning namespace
> inode number by using these ioctl-s.
>
> $ ls -l /proc/13929/ns/pid
> lrwxrwxrwx 1 root root 0 Jul 22 21:03 /proc/13929/ns/pid -> 'pid:[4026532228]'
>
> $ ./nsowner /proc/13929/ns/pid
> user:[4026532227]
>
> The owning user namespace for pid:[4026532228] is user:[4026532227].
>
> The nsowner tool is cimpiled from this code:
>
> int main(int argc, char *argv[])
> {
> char buf[128], path[] = "/proc/self/fd/0123456789";
> int ns, uns, ret;
>
> ns = open(argv[1], O_RDONLY);
> if (ns < 0)
> return 1;
>
> uns = ioctl(ns, NS_GET_USERNS);
> if (uns < 0)
> return 1;
>
> snprintf(path, sizeof(path), "/proc/self/fd/%d", uns);
> ret = readlink(path, buf, sizeof(buf) - 1);
> if (ret < 0)
> return 1;
> buf[ret] = 0;
>
> printf("%s\n", buf);
>
> return 0;
> }
So, from my point of view, the important piece that was missing from
your commit message was the note to use readlink("/proc/self/fd/%d")
on the returned FDs. I think that detail needs to be part of the
commit message (and also the man page text). I think it even be
helpful to include the above program as part of the commit message:
it helps people more quickly grasp the API.
> Does this example answer to the origin question?
Yes.
>If it isn't, could
> you eloborate what you expect to see here.
>
> And I wrote one more example which show all relationships between
> namespaces. It enumirates all processes in a system, collects all
> namespaces and determins parent and owning namespaces for each of
> them, then it constructs a namespace tree and shows it.
>
> Here is a code: https://gist.github.com/avagin/db805f95e15ffb0af7e559dbb8de4418
That's great! Thanks!
> Here is an example of output for my test system:
> [root@fc24 nsfs]# ./nstree
> user:[4026531837]
> \__ mnt:[4026532203]
> \__ ipc:[4026531839]
> \__ user:[4026532224]
> \__ user:[4026532226]
> \__ user:[4026532227]
> \__ pid:[4026532228]
> \__ pid:[4026532225]
> \__ pid:[4026532228]
> \__ user:[4026532221]
> \__ pid:[4026532222]
> \__ user:[4026532223]
> \__ mnt:[4026532211]
> \__ uts:[4026531838]
> \__ cgroup:[4026531835]
> \__ pid:[4026531836]
> \__ pid:[4026532225]
> \__ pid:[4026532228]
> \__ pid:[4026532222]
> \__ mnt:[4026531857]
> \__ mnt:[4026531840]
> \__ net:[4026531957]
Cheers,
Michael
>>>>> [1] https://lkml.org/lkml/2016/7/6/158
>>>>> [2] https://lkml.org/lkml/2016/7/9/101
--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
[toc] | [prev] | [next] | [standalone]
| From | ebiederm@xmission.com (Eric W. Biederman) |
|---|---|
| Date | 2016-07-25 15:40 +0200 |
| Message-ID | <rYOgW-584-31@gated-at.bofh.it> |
| In reply to | #1449437 |
"Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> writes:
> Hi Andrey,
>
> On 07/22/2016 08:25 PM, Andrey Vagin wrote:
>> On Thu, Jul 21, 2016 at 11:48 PM, Michael Kerrisk (man-pages)
>> <mtk.manpages@gmail.com> wrote:
>>> Hi Andrey,
>>>
>>>
>>> On 07/21/2016 11:06 PM, Andrew Vagin wrote:
>>>>
>>>> On Thu, Jul 21, 2016 at 04:41:12PM +0200, Michael Kerrisk (man-pages)
>>>> wrote:
>>>>>
>>>>> Hi Andrey,
>>>>>
>>>>> On 07/14/2016 08:20 PM, Andrey Vagin wrote:
>>>>
>>>>
>>>> <snip>
>>>>
>>>>>
>>>>> Could you add here an of the API in detail: what do these FDs refer to,
>>>>> and how do you use them to solve the use case? And could you you add
>>>>> that info to the commit messages please.
>>>>
>>>>
>>>> Hi Michael,
>>>>
>>>> A patch for man-pages is attached. It adds the following text to
>>>> namespaces(7).
>>>>
>>>> Since Linux 4.X, the following ioctl(2) calls are supported for names‐
>>>> pace file descriptors. The correct syntax is:
>>>>
>>>> fd = ioctl(ns_fd, ioctl_type);
>>>>
>>>> where ioctl_type is one of the following:
>>>>
>>>> NS_GET_USERNS
>>>> Returns a file descriptor that refers to an owning user names‐
>>>> pace.
>>>>
>>>> NS_GET_PARENT
>>>> Returns a file descriptor that refers to a parent namespace.
>>>> This ioctl(2) can be used for pid and user namespaces. For user
>>>> namespaces, NS_GET_PARENT and NS_GET_USERNS have the same mean‐
>>>> ing.
>
> For each of the above, I think it is worth mentioning that the
> close-on-exec flag is set for the returned file descriptor.
Hmm. That is an odd default.
>>>>
>>>> In addition to generic ioctl(2) errors, the following specific ones can
>>>> occur:
>>>>
>>>> EINVAL NS_GET_PARENT was called for a nonhierarchical namespace.
>>>>
>>>> EPERM The requested namespace is outside of the current namespace
>>>> scope.
>
> Perhaps add "and the caller does not have CAP_SYS_ADMIN" in the initial
> user namespace"?
Having looked at that bit of code I don't think capabilities really
have a role to play.
>>>> ENOENT ns_fd refers to the init namespace.
>>>
>>>
>>> Thanks for this. But still part of the question remains unanswered.
>>> How do we (in user-space) use the file descriptors to answer any of
>>> the questions that this patch series was designed to solve? (This
>>> info should be in the commit message and the man-pages patch.)
>>
>> I'm sorry, but I am not sure that I understand what you ask.
>>
>> Here are the origin questions:
>> Someone else then asked me a question that led me to wonder about
>> generally introspecting on the parental relationships between user
>> namespaces and the association of other namespaces types with user
>> namespaces. One use would be visualization, in order to understand the
>> running system. Another would be to answer the question I already
>> mentioned: what capability does process X have to perform operations
>> on a resource governed by namespace Y?
>>
>> Here is an example which shows how we can get the owning namespace
>> inode number by using these ioctl-s.
>>
>> $ ls -l /proc/13929/ns/pid
>> lrwxrwxrwx 1 root root 0 Jul 22 21:03 /proc/13929/ns/pid -> 'pid:[4026532228]'
>>
>> $ ./nsowner /proc/13929/ns/pid
>> user:[4026532227]
>>
>> The owning user namespace for pid:[4026532228] is user:[4026532227].
>>
>> The nsowner tool is cimpiled from this code:
>>
>> int main(int argc, char *argv[])
>> {
>> char buf[128], path[] = "/proc/self/fd/0123456789";
>> int ns, uns, ret;
>>
>> ns = open(argv[1], O_RDONLY);
>> if (ns < 0)
>> return 1;
>>
>> uns = ioctl(ns, NS_GET_USERNS);
>> if (uns < 0)
>> return 1;
>>
>> snprintf(path, sizeof(path), "/proc/self/fd/%d", uns);
>> ret = readlink(path, buf, sizeof(buf) - 1);
>> if (ret < 0)
>> return 1;
>> buf[ret] = 0;
>>
>> printf("%s\n", buf);
>>
>> return 0;
>> }
>
> So, from my point of view, the important piece that was missing from
> your commit message was the note to use readlink("/proc/self/fd/%d")
> on the returned FDs. I think that detail needs to be part of the
> commit message (and also the man page text). I think it even be
> helpful to include the above program as part of the commit message:
> it helps people more quickly grasp the API.
Please, please make the standard way to compare these things fstat.
That is much less magic than a symlink, and a little more future proof.
Possibly even kcmp.
At some point we will care about migrating a migrating sub-container and we
may have to have some minor changes.
Eric
[toc] | [prev] | [next] | [standalone]
| From | "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> |
|---|---|
| Date | 2016-07-25 16:50 +0200 |
| Subject | Re: [PATCH 0/5 RFC] Add an interface to discover relationships between namespaces |
| Message-ID | <rYPmF-5Ly-3@gated-at.bofh.it> |
| In reply to | #1449488 |
Hi Eric,
On 07/25/2016 03:18 PM, Eric W. Biederman wrote:
> "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> writes:
>
>> Hi Andrey,
>>
>> On 07/22/2016 08:25 PM, Andrey Vagin wrote:
>>> On Thu, Jul 21, 2016 at 11:48 PM, Michael Kerrisk (man-pages)
>>> <mtk.manpages@gmail.com> wrote:
>>>> Hi Andrey,
>>>>
>>>>
>>>> On 07/21/2016 11:06 PM, Andrew Vagin wrote:
>>>>>
>>>>> On Thu, Jul 21, 2016 at 04:41:12PM +0200, Michael Kerrisk (man-pages)
>>>>> wrote:
>>>>>>
>>>>>> Hi Andrey,
>>>>>>
>>>>>> On 07/14/2016 08:20 PM, Andrey Vagin wrote:
>>>>>
>>>>>
>>>>> <snip>
>>>>>
>>>>>>
>>>>>> Could you add here an of the API in detail: what do these FDs refer to,
>>>>>> and how do you use them to solve the use case? And could you you add
>>>>>> that info to the commit messages please.
>>>>>
>>>>>
>>>>> Hi Michael,
>>>>>
>>>>> A patch for man-pages is attached. It adds the following text to
>>>>> namespaces(7).
>>>>>
>>>>> Since Linux 4.X, the following ioctl(2) calls are supported for names‐
>>>>> pace file descriptors. The correct syntax is:
>>>>>
>>>>> fd = ioctl(ns_fd, ioctl_type);
>>>>>
>>>>> where ioctl_type is one of the following:
>>>>>
>>>>> NS_GET_USERNS
>>>>> Returns a file descriptor that refers to an owning user names‐
>>>>> pace.
>>>>>
>>>>> NS_GET_PARENT
>>>>> Returns a file descriptor that refers to a parent namespace.
>>>>> This ioctl(2) can be used for pid and user namespaces. For user
>>>>> namespaces, NS_GET_PARENT and NS_GET_USERNS have the same mean‐
>>>>> ing.
>>
>> For each of the above, I think it is worth mentioning that the
>> close-on-exec flag is set for the returned file descriptor.
>
> Hmm. That is an odd default.
Why do you say that? It's pretty common as the default for various
APIs that create new FDs these days. (There's of course a strong argument
that the original UNIX default was a design blunder...)
>>>>>
>>>>> In addition to generic ioctl(2) errors, the following specific ones can
>>>>> occur:
>>>>>
>>>>> EINVAL NS_GET_PARENT was called for a nonhierarchical namespace.
>>>>>
>>>>> EPERM The requested namespace is outside of the current namespace
>>>>> scope.
>>
>> Perhaps add "and the caller does not have CAP_SYS_ADMIN" in the initial
>> user namespace"?
>
> Having looked at that bit of code I don't think capabilities really
> have a role to play.
Yes, I caught up with that now. I await to see how this plays out
in the next patch version.
>>>>> ENOENT ns_fd refers to the init namespace.
>>>>
>>>>
>>>> Thanks for this. But still part of the question remains unanswered.
>>>> How do we (in user-space) use the file descriptors to answer any of
>>>> the questions that this patch series was designed to solve? (This
>>>> info should be in the commit message and the man-pages patch.)
>>>
>>> I'm sorry, but I am not sure that I understand what you ask.
>>>
>>> Here are the origin questions:
>>> Someone else then asked me a question that led me to wonder about
>>> generally introspecting on the parental relationships between user
>>> namespaces and the association of other namespaces types with user
>>> namespaces. One use would be visualization, in order to understand the
>>> running system. Another would be to answer the question I already
>>> mentioned: what capability does process X have to perform operations
>>> on a resource governed by namespace Y?
>>>
>>> Here is an example which shows how we can get the owning namespace
>>> inode number by using these ioctl-s.
>>>
>>> $ ls -l /proc/13929/ns/pid
>>> lrwxrwxrwx 1 root root 0 Jul 22 21:03 /proc/13929/ns/pid -> 'pid:[4026532228]'
>>>
>>> $ ./nsowner /proc/13929/ns/pid
>>> user:[4026532227]
>>>
>>> The owning user namespace for pid:[4026532228] is user:[4026532227].
>>>
>>> The nsowner tool is cimpiled from this code:
>>>
>>> int main(int argc, char *argv[])
>>> {
>>> char buf[128], path[] = "/proc/self/fd/0123456789";
>>> int ns, uns, ret;
>>>
>>> ns = open(argv[1], O_RDONLY);
>>> if (ns < 0)
>>> return 1;
>>>
>>> uns = ioctl(ns, NS_GET_USERNS);
>>> if (uns < 0)
>>> return 1;
>>>
>>> snprintf(path, sizeof(path), "/proc/self/fd/%d", uns);
>>> ret = readlink(path, buf, sizeof(buf) - 1);
>>> if (ret < 0)
>>> return 1;
>>> buf[ret] = 0;
>>>
>>> printf("%s\n", buf);
>>>
>>> return 0;
>>> }
>>
>> So, from my point of view, the important piece that was missing from
>> your commit message was the note to use readlink("/proc/self/fd/%d")
>> on the returned FDs. I think that detail needs to be part of the
>> commit message (and also the man page text). I think it even be
>> helpful to include the above program as part of the commit message:
>> it helps people more quickly grasp the API.
>
> Please, please make the standard way to compare these things fstat.
> That is much less magic than a symlink, and a little more future proof.
> Possibly even kcmp.
As in fstat() to get the st_ino field, right?
Cheers,
Michael
> At some point we will care about migrating a migrating sub-container and we
> may have to have some minor changes.
>
> Eric
>
--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web