[PATCH] Implement decoding of NS_* ioctl commands

Dmitry V. Levin ldv at altlinux.org
Wed Apr 5 16:21:01 UTC 2017


On Thu, Mar 30, 2017 at 09:06:43PM +0700, Nikolay Marchuk wrote:
[...]
> +int
> +nsfs_ioctl(struct tcb *tcp, unsigned int code, kernel_ulong_t arg)
> +{
> +	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)) {
> +			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("]");
> +		}

printuid takes an unsigned int as uid and other parsers except those
defined in uid.c do not use uid_t.  As the libc's idea of uid_t may differ
from kernel's, let's use unsigned int so far.

[...]
> +#include "tests.h"
> +
> +#include <fcntl.h>
> +#include <linux/ioctl.h>
> +#include <sched.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/ioctl.h>
> +#include <sys/wait.h>
> +#include <unistd.h>

Please include linux/ headers after libc headers unless necessary.

> +#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);

Why 22?  Wouldn't it be better to use a sizeof based approach,
e.g. like in implementation of getfdproto()?

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

When wrapping printf statements, please wrap the line after format
string, it's more readable.

> +
> +	nstype = ioctl(userns_fd, NS_GET_NSTYPE);
> +	if (nstype == -1) {
> +		printf("ioctl(%d, NS_GET_NSTYPE) = %s\n", userns_fd, sprintrc(nstype));

The line is too long, please wrap.

> +	} else {
> +		printf("ioctl(%d, NS_GET_NSTYPE) = %d (CLONE_NEWUSER)\n", userns_fd,
> +		       nstype);

The line is still too long, please wrap it earlier.

> +	}
> +
> +	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));

When wrapping printf statements, please wrap the line after format
string, it's more readable.

> +	} else {
> +		printf("ioctl(%d, NS_GET_OWNER_UID, [%u]) = %d\n", userns_fd, *uid, rc);

The line is too long, please wrap.

> +	}
> +}
> +
> +static int
> +child(void *arg)
> +{
> +	int *pipefd = (int *)arg;

Please add a space before arg.

> +	close(pipefd[1]);
> +	/* Wait for EOF from pipe. */
> +	while(read(pipefd[0], &pipefd[1], 1) != 0);
> +	return 0;
> +}
> +
> +#define STACK_SIZE (1024 * 1024)
> +
> +static void
> +test_user_namespace(void)
> +{
> +	char stack[STACK_SIZE];

Do you really need 1M of stack for child()?

> +	pid_t pid;
> +	int pipefd[2];
> +	int rc, status;
> +
> +	rc = pipe(pipefd);
> +	if (rc == -1)
> +		perror_msg_and_skip("pipe");
> +
> +	pid = clone(child, stack + STACK_SIZE, (CLONE_NEWUSER | CLONE_UNTRACED
> +	            | SIGCHLD), pipefd);
> +	close(pipefd[0]);

This potentially clobbers errno used by perror_msg_and_skip.

> +	if (pid == -1)
> +		perror_msg_and_skip("clone");

User namespaces are not universally available,
let's just skip this part of the test.


-- 
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/20170405/5499f6ea/attachment.bin>


More information about the Strace-devel mailing list