[PATCH] Implement decoding of NS_* ioctl commands

Dmitry V. Levin ldv at altlinux.org
Mon Mar 27 12:44:00 UTC 2017


On Mon, Mar 27, 2017 at 07:25:48PM +0700, Nikolay Marchuk wrote:
> * configure.ac: Add check for linux/nsfs.h header.

The tradition is to write it this way:

* configure.ac (AC_CHECK_HEADERS): Add linux/nsfs.h.

> * defs.h: Add definition for new ioctl decoder.

* defs.h (DECL_IOCTL(nsfs)): New prototype.

> * ioctl.c: Modify to support new ioctl decoder.

* ioctl.c (ioctl_decode): Call nsfs_ioctl for 0xb7 code.

> * nsfs.c: New file.
> * nsfs.h: Likewise.
> * Makefile.am (strace_SOURCES): Add them.
> * tests/.gitignore: Add ioctl_nsfs.
> * tests/Makefile.am (check_PROGRAMS): Likewise.
> (DECODER_TESTS): Add ioctl_nsfs.test

Trailing dot is missing.

> * tests/ioctl_nsfs.c: New file.

This should go before tests/.gitignore and tests/Makefile.am.

> * tests/ioctl_nsfs.h: Likewise.

What is tests/ioctl_nsfs.h?
Where is tests/ioctl_nsfs.test?

> ---
>  Makefile.am           |   2 +
>  configure.ac          |   1 +
>  defs.h                |   1 +
>  ioctl.c               |   2 +
>  nsfs.c                |  68 +++++++++++++++++++++++++
>  nsfs.h                |  19 +++++++
>  tests/.gitignore      |   1 +
>  tests/Makefile.am     |   2 +
>  tests/ioctl_nsfs.c    | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/ioctl_nsfs.test |  13 +++++
>  10 files changed, 243 insertions(+)
>  create mode 100644 nsfs.c
>  create mode 100644 nsfs.h
>  create mode 100644 tests/ioctl_nsfs.c
>  create mode 100755 tests/ioctl_nsfs.test
> 
> diff --git a/Makefile.am b/Makefile.am
> index 8af709b..24e94ed 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -172,6 +172,8 @@ strace_SOURCES =	\
>  	net.c		\
>  	netlink.c       \
>  	nsig.h		\
> +	nsfs.h		\
> +	nsfs.c		\

Please keep the list sorted.

>  	numa.c		\
>  	oldstat.c	\
>  	open.c		\
> diff --git a/configure.ac b/configure.ac
> index 9e5087b..dc49fdc 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -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 793971e..0f3ec14 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -640,6 +640,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 aa1880f..4511e0b 100644
> --- 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
> index 0000000..28abcb8
> --- /dev/null
> +++ b/nsfs.c
> @@ -0,0 +1,68 @@
> +/*
> + * Support for decoding of NS_* ioctl commands.
> + *
> + * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a at 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 <linux/ioctl.h>
> +#include "nsfs.h"
> +#include "xlat/setns_types.h"
> +
> +int
> +nsfs_ioctl(struct tcb *tcp, unsigned int code, kernel_ulong_t arg)
> +{
> +	const char *outstr;

Please move this variable into the case.

> +	uid_t 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)) {
> +			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 0;

Why 0?  I though it should rather be RVAL_DECODED.

> +	}
> +}
> diff --git a/nsfs.h b/nsfs.h
> new file mode 100644
> index 0000000..d3a6fca
> --- /dev/null
> +++ b/nsfs.h
> @@ -0,0 +1,19 @@
> +#ifndef STRACE_NSFS_H
> +#define STRACE_NSFS_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 */
> diff --git a/tests/.gitignore b/tests/.gitignore
> index 477529d..1998097 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -122,6 +122,7 @@ ioctl_loop
>  ioctl_loop-nv
>  ioctl_loop-v
>  ioctl_mtd
> +ioctl_nsfs
>  ioctl_rtc
>  ioctl_rtc-v
>  ioctl_scsi
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index c6c28cc..44b0463 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -185,6 +185,7 @@ check_PROGRAMS = \
>  	ioctl_loop-nv \
>  	ioctl_loop-v \
>  	ioctl_mtd \
> +	ioctl_nsfs \
>  	ioctl_rtc \
>  	ioctl_rtc-v \
>  	ioctl_scsi \
> @@ -595,6 +596,7 @@ DECODER_TESTS = \
>  	ioctl_loop-v.test \
>  	ioctl_loop.test \
>  	ioctl_mtd.test \
> +	ioctl_nsfs.test \
>  	ioctl_rtc-v.test \
>  	ioctl_rtc.test \
>  	ioctl_scsi.test \
> diff --git a/tests/ioctl_nsfs.c b/tests/ioctl_nsfs.c
> new file mode 100644
> index 0000000..58364d7
> --- /dev/null
> +++ b/tests/ioctl_nsfs.c
> @@ -0,0 +1,134 @@
> +/*
> + * Check decoding of NS_* commands of ioctl syscall.
> + *
> + * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a at 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 <linux/ioctl.h>
> +#include <sched.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/ioctl.h>
> +#include <unistd.h>
> +#include "nsfs.h"
> +
> +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)
> +{
> +	int ns_fd, userns_fd, parent_ns_fd, nstype, rc;
> +	/* Path length with terminator is less then 22 in any case. */
> +	char path[22];
> +	TAIL_ALLOC_OBJECT_CONST_PTR(uid_t, uid);
> +
> +	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
> +	ns_fd = open(path, O_RDONLY);
> +	if (ns_fd == -1)
> +		perror_msg_and_skip("open: %s", path);
> +
> +	userns_fd = ioctl(ns_fd, NS_GET_USERNS);
> +	printf("ioctl(%d, NS_GET_USERNS) = %s\n", ns_fd, sprintrc(userns_fd));
> +
> +	parent_ns_fd = ioctl(userns_fd, NS_GET_PARENT);
> +	printf("ioctl(%d, NS_GET_PARENT) = %s\n", userns_fd,
> +	       sprintrc(parent_ns_fd));
> +
> +	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);
> +	}
> +
> +	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)
> +{
> +	char c;
> +	int *pipefd = (int *)arg;
> +	while (read(pipefd[1], &c, 1) != 1);
> +	close(pipefd[1]);
> +	return 0;
> +}
> +
> +#define STACK_SIZE (1024 * 1024)
> +
> +static void
> +test_user_namespace(void)
> +{
> +	char stack[STACK_SIZE];
> +	pid_t pid;
> +	int pipefd[2];
> +	int rc;
> +
> +	rc = pipe(pipefd);
> +	if (rc == -1)
> +		perror_msg_and_skip("pipe");
> +
> +	pid = clone(child, stack + STACK_SIZE, CLONE_NEWUSER | CLONE_UNTRACED,
> +	            pipefd);
> +	if (pid == -1)
> +		perror_msg_and_skip("clone");
> +
> +	test_clone(pid);
> +	if (write(pipefd[0], "", 1) != 1){
> +		perror_msg_and_skip("pipe write");
> +	}
> +	close(pipefd[0]);
> +}

The proper pipe synchronization is implemented this way:
- parent creates a pipe
- parent forks a child
- parent closes the read end of the pipe
- child closes the write end of the pipe
- child blocks in a read from the pipe
- parent goes to perform other tasks
- parent closes the write end of the pipe
- child reads EOF from the pipe and exits
- parent waits for the child

You can find several examples in the test suite.


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20170327/d467bde7/attachment.bin>


More information about the Strace-devel mailing list