forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools/testing: add a test to check nsfs ioctl-s
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: Andrei Vagin <avagin@openvz.org> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
- Loading branch information
Showing
4 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 != EPERM) | ||
return pr_err("Don't get EPERM"); | ||
|
||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#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 *ns_strs[] = {"pid", "user"}; | ||
char path[] = "/proc/0123456789/ns/pid"; | ||
struct cr_clone_arg ca; | ||
struct stat st1, st2; | ||
int ns, pns, i; | ||
pid_t pid; | ||
|
||
pid = clone(child, ca.stack_ptr, CLONE_NEWUSER | CLONE_NEWPID | SIGCHLD, NULL); | ||
if (pid < 0) | ||
return pr_err("clone"); | ||
|
||
for (i = 0; i < 2; i++) { | ||
snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, ns_strs[i]); | ||
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"); | ||
|
||
snprintf(path, sizeof(path), "/proc/self/ns/%s", ns_strs[i]); | ||
if (stat(path, &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 != EPERM) | ||
return pr_err("Don't get EPERM");; | ||
} | ||
|
||
kill(pid, SIGKILL); | ||
wait(NULL); | ||
return 0; | ||
} |