]> granicus.if.org Git - strace/commitdiff
Implement decoding of NS_* ioctl commands
authorNikolay Marchuk <marchuk.nikolay.a@gmail.com>
Thu, 13 Apr 2017 15:10:11 +0000 (22:10 +0700)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 13 Apr 2017 15:46:49 +0000 (15:46 +0000)
* configure.ac (AC_CHECK_HEADERS): Add linux/nsfs.h.
* defs.h (DECL_IOCTL(nsfs)): New prototype.
(setns_types): Make global.
* ioctl.c (ioctl_decode): Call nsfs_ioctl for 0xb7 code.
* nsfs.c: New file.
* nsfs.h: Likewise.
* Makefile.am (strace_SOURCES): Add them.
* tests/ioctl_nsfs.c: New file.
* tests/ioctl_nsfs.test: Likewise.
* tests/.gitignore: Add ioctl_nsfs.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(DECODER_TESTS): Add ioctl_nsfs.test.
* NEWS: Mention this change.

Makefile.am
NEWS
configure.ac
defs.h
ioctl.c
nsfs.c [new file with mode: 0644]
nsfs.h [new file with mode: 0644]
tests/.gitignore
tests/Makefile.am
tests/ioctl_nsfs.c [new file with mode: 0644]
tests/ioctl_nsfs.test [new file with mode: 0755]

index 8af709b309d2722f39f6d99bd4bb53b9592cb6ea..7435e27342fb2118df860fa1697cfa8cd7c1cd27 100644 (file)
@@ -171,6 +171,8 @@ strace_SOURCES =    \
        native_defs.h   \
        net.c           \
        netlink.c       \
+       nsfs.c          \
+       nsfs.h          \
        nsig.h          \
        numa.c          \
        oldstat.c       \
diff --git a/NEWS b/NEWS
index 7bbd221bc1cf691278945acfec2c71e53a337c61..8eca949c7261552baa719d3ccc449289bc7dd7b8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,7 @@ Noteworthy changes in release ?.?? (????-??-??)
     powerpc, powerpc64, riscv, sh, sh64, sparc, sparc64, tile, x86, and xtensa
     architectures.
   * Implemented decoding of statx syscall.
+  * Implemented decoding of NS_* ioctl commands.
   * Updated lists of ioctl commands from Linux 4.11.
 
 * Bug fixes
index 9e5087b7ec155ea8578a3dc7960c48de59791b17..dc49fdc57024ff31073bfc02b670166be2c5da12 100644 (file)
@@ -366,6 +366,7 @@ AC_CHECK_HEADERS(m4_normalize([
        linux/ipc.h
        linux/mmtimer.h
        linux/msg.h
+       linux/nsfs.h
        linux/perf_event.h
        linux/quota.h
        linux/seccomp.h
diff --git a/defs.h b/defs.h
index 54f641747d8175c322e502bb28a85562aabe91ec..9c0518d3feb82d53204b9d5a5a0f31742850e0ef 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -301,6 +301,7 @@ extern const struct xlat netlink_protocols[];
 extern const struct xlat open_access_modes[];
 extern const struct xlat open_mode_flags[];
 extern const struct xlat resource_flags[];
+extern const struct xlat setns_types[];
 extern const struct xlat sg_io_info[];
 extern const struct xlat socketlayers[];
 extern const struct xlat whence_codes[];
@@ -642,6 +643,7 @@ name ## _ioctl(struct tcb *, unsigned int request, kernel_ulong_t arg)
 DECL_IOCTL(dm);
 DECL_IOCTL(file);
 DECL_IOCTL(fs_x);
+DECL_IOCTL(nsfs);
 DECL_IOCTL(ptp);
 DECL_IOCTL(scsi);
 DECL_IOCTL(term);
diff --git a/ioctl.c b/ioctl.c
index aa1880f8de56d6eccf260aa8331f4f4c915eb597..4511e0b24f286635c4abc886b34445a2745a7b2f 100644 (file)
--- a/ioctl.c
+++ b/ioctl.c
@@ -280,6 +280,8 @@ ioctl_decode(struct tcb *tcp)
        case 0x94:
                return btrfs_ioctl(tcp, code, arg);
 #endif
+       case 0xb7:
+               return nsfs_ioctl(tcp, code, arg);
 #ifdef HAVE_LINUX_DM_IOCTL_H
        case 0xfd:
                return dm_ioctl(tcp, code, arg);
diff --git a/nsfs.c b/nsfs.c
new file mode 100644 (file)
index 0000000..1048f9a
--- /dev/null
+++ b/nsfs.c
@@ -0,0 +1,65 @@
+/*
+ * Support for decoding of NS_* ioctl commands.
+ *
+ * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+#include "nsfs.h"
+
+int
+nsfs_ioctl(struct tcb *tcp, unsigned int code, kernel_ulong_t arg)
+{
+       unsigned int uid;
+       switch (code) {
+       case NS_GET_USERNS:
+       case NS_GET_PARENT:
+               return 1 + RVAL_FD + RVAL_DECODED;
+       case NS_GET_NSTYPE:
+               if (entering(tcp))
+                       return 0;
+               if (!syserror(tcp)) {
+                       const char *outstr;
+                       outstr = xlookup(setns_types, tcp->u_rval);
+                       if (outstr) {
+                               tcp->auxstr = outstr;
+                               return 1 + RVAL_STR;
+                       }
+               }
+               return 1;
+       case NS_GET_OWNER_UID:
+               if (entering(tcp))
+                       return 0;
+               tprints(", ");
+               if (!umove_or_printaddr(tcp, arg, &uid)) {
+                       printuid("[", uid);
+                       tprints("]");
+               }
+               return 1;
+       default:
+               return RVAL_DECODED;
+       }
+}
diff --git a/nsfs.h b/nsfs.h
new file mode 100644 (file)
index 0000000..3e17c53
--- /dev/null
+++ b/nsfs.h
@@ -0,0 +1,21 @@
+#ifndef STRACE_NSFS_H
+#define STRACE_NSFS_H
+
+#include <linux/ioctl.h>
+
+#ifdef HAVE_LINUX_NSFS_H
+# include <linux/nsfs.h>
+#else
+# define NSIO    0xb7
+# define NS_GET_USERNS   _IO(NSIO, 0x1)
+# define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
+#ifndef NS_GET_NSTYPE
+# define NS_GET_NSTYPE    _IO(NSIO, 0x3)
+#endif
+#ifndef NS_GET_OWNER_UID
+# define NS_GET_OWNER_UID _IO(NSIO, 0x4)
+#endif
+
+#endif /* !STRACE_NSFS_H */
index 1b03984661f2641ff6b2ac9b3ae5e2ecf01b0c95..03b221e343e9a7922a893a340038fcdb655103cd 100644 (file)
@@ -124,6 +124,7 @@ ioctl_loop
 ioctl_loop-nv
 ioctl_loop-v
 ioctl_mtd
+ioctl_nsfs
 ioctl_rtc
 ioctl_rtc-v
 ioctl_scsi
index ce75196a0303d437595f81afec275acc3e518aee..3533b595802278a4f1d870de8ac5453fed770e3b 100644 (file)
@@ -188,6 +188,7 @@ check_PROGRAMS = \
        ioctl_loop-nv \
        ioctl_loop-v \
        ioctl_mtd \
+       ioctl_nsfs \
        ioctl_rtc \
        ioctl_rtc-v \
        ioctl_scsi \
@@ -507,6 +508,7 @@ DECODER_TESTS = \
        ioctl_dm-v.test \
        ioctl_dm.test \
        ioctl_loop-nv.test \
+       ioctl_nsfs.test \
        ioctl_sock_gifconf.test \
        ipc_msgbuf.test \
        llseek.test \
diff --git a/tests/ioctl_nsfs.c b/tests/ioctl_nsfs.c
new file mode 100644 (file)
index 0000000..0261235
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Check decoding of NS_* commands of ioctl syscall.
+ *
+ * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "nsfs.h"
+
+#ifndef CLONE_NEWUSER
+# define CLONE_NEWUSER 0x10000000
+#endif
+
+static void
+test_no_namespace(void)
+{
+       ioctl(-1, NS_GET_USERNS);
+       printf("ioctl(-1, NS_GET_USERNS) = -1 EBADF (%m)\n");
+       ioctl(-1, NS_GET_PARENT);
+       printf("ioctl(-1, NS_GET_PARENT) = -1 EBADF (%m)\n");
+       ioctl(-1, NS_GET_NSTYPE);
+       printf("ioctl(-1, NS_GET_NSTYPE) = -1 EBADF (%m)\n");
+       ioctl(-1, NS_GET_OWNER_UID, NULL);
+       printf("ioctl(-1, NS_GET_OWNER_UID, NULL) = -1 EBADF (%m)\n");
+}
+
+static void
+test_clone(pid_t pid)
+{
+       char path[sizeof("/proc/%d/ns/user") + sizeof(int)*3];
+       snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
+
+       int ns_fd = open(path, O_RDONLY);
+       if (ns_fd == -1)
+               perror_msg_and_skip("open: %s", path);
+
+       int userns_fd = ioctl(ns_fd, NS_GET_USERNS);
+       printf("ioctl(%d, NS_GET_USERNS) = %s\n", ns_fd, sprintrc(userns_fd));
+
+       int parent_ns_fd = ioctl(userns_fd, NS_GET_PARENT);
+       printf("ioctl(%d, NS_GET_PARENT) = %s\n",
+              userns_fd, sprintrc(parent_ns_fd));
+
+       int nstype = ioctl(userns_fd, NS_GET_NSTYPE);
+       if (nstype == -1) {
+               printf("ioctl(%d, NS_GET_NSTYPE) = %s\n",
+                      userns_fd, sprintrc(nstype));
+       } else {
+               printf("ioctl(%d, NS_GET_NSTYPE) = %d (CLONE_NEWUSER)\n",
+                      userns_fd, nstype);
+       }
+
+       TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, uid);
+       int rc = ioctl(userns_fd, NS_GET_OWNER_UID, uid);
+       if (rc == -1) {
+               printf("ioctl(%d, NS_GET_OWNER_UID, %p) = %s\n",
+                      userns_fd, uid, sprintrc(rc));
+       } else {
+               printf("ioctl(%d, NS_GET_OWNER_UID, [%u]) = %d\n",
+                      userns_fd, *uid, rc);
+       }
+}
+
+static int
+child(void *arg)
+{
+       int *pipefd = (int *) arg;
+       close(pipefd[1]);
+       /* Wait for EOF from pipe. */
+       if (read(pipefd[0], &pipefd[1], 1))
+               perror_msg_and_fail("read");
+       return 0;
+}
+
+static void
+test_user_namespace(void)
+{
+       pid_t pid;
+       int pipefd[2];
+       int status;
+
+       if (pipe(pipefd))
+               perror_msg_and_fail("pipe");
+
+       pid = clone(child, tail_alloc(1) + 1,
+                   CLONE_NEWUSER | CLONE_UNTRACED | SIGCHLD, pipefd);
+       if (pid == -1) {
+               perror("clone");
+               return;
+       }
+       close(pipefd[0]);
+       test_clone(pid);
+       close(pipefd[1]);
+       if (wait(&status) != pid) {
+               perror_msg_and_fail("wait");
+       } else if (status != 0) {
+               error_msg_and_fail("unexpected child exit status %d", status);
+       }
+}
+
+int
+main(void)
+{
+       test_no_namespace();
+       test_user_namespace();
+       puts("+++ exited with 0 +++");
+       return 0;
+}
diff --git a/tests/ioctl_nsfs.test b/tests/ioctl_nsfs.test
new file mode 100755 (executable)
index 0000000..acdfb61
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Check decoding of NS_* ioctls.
+
+. "${srcdir=.}/init.sh"
+
+check_prog grep
+run_prog > /dev/null
+run_strace -a16 -eioctl -esignal=none $args > "$EXP"
+grep -v '^ioctl([012],' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"