Implement decoding of NS_* ioctl commands

* 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.
This commit is contained in:
Nikolay Marchuk 2017-04-13 22:10:11 +07:00 committed by Dmitry V. Levin
parent 0a3bb911c7
commit 2afd57decb
11 changed files with 247 additions and 0 deletions

View File

@ -171,6 +171,8 @@ strace_SOURCES = \
native_defs.h \
net.c \
netlink.c \
nsfs.c \
nsfs.h \
nsig.h \
numa.c \
oldstat.c \

1
NEWS
View File

@ -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

View 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

2
defs.h
View File

@ -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);

View File

@ -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);

65
nsfs.c Normal file
View File

@ -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;
}
}

21
nsfs.h Normal file
View File

@ -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 */

1
tests/.gitignore vendored
View File

@ -124,6 +124,7 @@ ioctl_loop
ioctl_loop-nv
ioctl_loop-v
ioctl_mtd
ioctl_nsfs
ioctl_rtc
ioctl_rtc-v
ioctl_scsi

View 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 \

139
tests/ioctl_nsfs.c Normal file
View File

@ -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;
}

11
tests/ioctl_nsfs.test Executable file
View File

@ -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"