All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v1] Test ioctl syscall for NS_GET_* requests
@ 2019-02-24 20:29 YourName
  2019-03-04 16:16 ` Cyril Hrubis
  0 siblings, 1 reply; 16+ messages in thread
From: YourName @ 2019-02-24 20:29 UTC (permalink / raw)
  To: ltp

From: Federico Bonfiglio <fedebonfi95@gmail.com>

---
 runtest/syscalls                             |  9 +++
 testcases/kernel/syscalls/ioctl/.gitignore   |  8 +++
 testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 87 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 63 ++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns03.c | 63 ++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 65 +++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 63 ++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 83 ++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 83 ++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns08.c | 72 +++++++++++++++++++++++
 10 files changed, 596 insertions(+)
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns03.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns08.c

diff --git a/runtest/syscalls b/runtest/syscalls
index bafe7378c..b518d574a 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -495,6 +495,15 @@ ioctl06      ioctl06
 
 ioctl07      ioctl07
 
+ioctl_ns01 ioctl_ns01
+ioctl_ns02 ioctl_ns02
+ioctl_ns03 ioctl_ns03
+ioctl_ns04 ioctl_ns04
+ioctl_ns05 ioctl_ns05
+ioctl_ns06 ioctl_ns06
+ioctl_ns07 ioctl_ns07
+ioctl_ns08 ioctl_ns08
+
 inotify_init1_01 inotify_init1_01
 inotify_init1_02 inotify_init1_02
 
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 79516a17c..f2e2301ac 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -5,3 +5,11 @@
 /ioctl05
 /ioctl06
 /ioctl07
+/ioctl_ns01
+/ioctl_ns02
+/ioctl_ns03
+/ioctl_ns04
+/ioctl_ns05
+/ioctl_ns06
+/ioctl_ns07
+/ioctl_ns08
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
new file mode 100644
index 000000000..68baafb48
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Child process has a new pid namespace, which should make the call fail
+ * with EPERM error.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_PARENT
+#define NSIO	0xb7
+#define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
+static void test_ns_get_parent(void)
+{
+	int fd, parent_fd;
+	char my_namespace[20];
+
+	sprintf(my_namespace, "/proc/self/ns/pid");
+	fd = SAFE_OPEN(my_namespace, O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_PARENT fails with EPERM");
+		else
+			tst_res(TFAIL, "unexpected error %u", errno);
+		exit(0);
+	} else {
+		SAFE_CLOSE(parent_fd);
+	}
+	SAFE_CLOSE(fd);
+	exit(-1);
+}
+
+static void run(void)
+{
+	int res = unshare(CLONE_NEWPID);
+
+	if (res == -1) {
+		tst_res(TCONF, "unshare syscall error");
+		exit(-1);
+	}
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0)
+		test_ns_get_parent();
+	else {
+		int status;
+
+		wait(&status);
+		if (status < 0)
+			tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
new file mode 100644
index 000000000..7feacd626
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Tries to get namespace parent for UTS namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_PARENT
+#define NSIO	0xb7
+#define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
+static void run(void)
+{
+	int fd, parent_fd;
+	char my_namespace[20];
+
+	sprintf(my_namespace, "/proc/self/ns/uts");
+	fd = SAFE_OPEN(my_namespace, O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_PARENT fails with EINVAL");
+		else
+			tst_res(TFAIL, "unexpected error %u", errno);
+	} else {
+		tst_res(TFAIL, "call to ioctl succeded");
+		SAFE_CLOSE(parent_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns03.c b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c
new file mode 100644
index 000000000..3d4e92872
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Tries to get parent of initial namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_PARENT
+#define NSIO	0xb7
+#define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
+static void run(void)
+{
+	int fd, parent_fd;
+	char my_namespace[20];
+
+	sprintf(my_namespace, "/proc/self/ns/pid");
+	fd = SAFE_OPEN(my_namespace, O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_PARENT of initial user fails");
+		else
+			tst_res(TFAIL, "unexpected error %u", errno);
+	} else {
+		tst_res(TFAIL, "call to ioctl succeded");
+		SAFE_CLOSE(parent_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
new file mode 100644
index 000000000..c61360611
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_OWNER_UID request.
+ *
+ * Fails attempting request for UTS namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_OWNER_UID
+#define NSIO    0xb7
+#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
+#endif
+
+static void run(void)
+{
+	int fd, owner_fd;
+	char my_namespace[20];
+
+	sprintf(my_namespace, "/proc/self/ns/uts");
+	fd = SAFE_OPEN(my_namespace, O_RDONLY);
+	uid_t uid;
+
+	owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid);
+	if (owner_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace");
+		else
+			tst_res(TFAIL, "unexpected error %u", errno);
+	} else {
+		tst_res(TFAIL, "call to ioctl succeded");
+		SAFE_CLOSE(owner_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.11",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
new file mode 100644
index 000000000..987012394
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * Fails attempting request for out of scope namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_USERNS
+#define NSIO    0xb7
+#define NS_GET_USERNS	   _IO(NSIO, 0x1)
+#endif
+
+static void run(void)
+{
+	int fd, parent_fd;
+	char my_namespace[20];
+
+	sprintf(my_namespace, "/proc/self/ns/user");
+	fd = SAFE_OPEN(my_namespace, O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_USERNS);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_USERNS fails with EPERM");
+		else
+			tst_res(TFAIL, "unexpected error %u", errno);
+	} else {
+		tst_res(TFAIL, "call to ioctl succeded");
+		SAFE_CLOSE(parent_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
new file mode 100644
index 000000000..9a0eb93f6
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Child process should have a new namespace.
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <sys/stat.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_PARENT
+#define NSIO	0xb7
+#define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
+static void run(void)
+{
+	int res = unshare(CLONE_NEWPID);
+
+	if (res < 0) {
+		tst_res(TCONF, "unshare error");
+		exit(0);
+	}
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0) {
+		exit(0);
+	} else {
+		char my_namespace[20], child_namespace[20];
+
+		sprintf(my_namespace, "/proc/self/ns/pid");
+		sprintf(child_namespace, "/proc/%i/ns/pid", pid);
+		int my_fd, child_fd, parent_fd;
+
+		my_fd = SAFE_OPEN(my_namespace, O_RDONLY);
+		child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+		parent_fd = ioctl(child_fd, NS_GET_PARENT);
+
+		struct stat my_stat, child_stat, parent_stat;
+
+		fstat(my_fd, &my_stat);
+		fstat(child_fd, &child_stat);
+		fstat(parent_fd, &parent_stat);
+		if (my_stat.st_ino != parent_stat.st_ino)
+			tst_res(TFAIL, "parents have different inodes");
+		else if (parent_stat.st_ino == child_stat.st_ino)
+			tst_res(TFAIL, "child and parent have same inode");
+		else
+			tst_res(TPASS, "child and parent are consistent");
+		SAFE_CLOSE(my_fd);
+		SAFE_CLOSE(child_fd);
+		SAFE_CLOSE(parent_fd);
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
new file mode 100644
index 000000000..a743bb1c8
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * Child process should have a new namespace.
+ */
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <sys/stat.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_USERNS
+#define NSIO	0xb7
+#define NS_GET_USERNS   _IO(NSIO, 0x1)
+#endif
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static int child(void *arg)
+{
+	return 0;
+}
+
+static void run(void)
+{
+	pid_t pid = ltp_clone(CLONE_NEWUSER, &child, 0,
+		STACK_SIZE, child_stack);
+
+	char my_namespace[20], child_namespace[20];
+
+	sprintf(my_namespace, "/proc/self/ns/user");
+	sprintf(child_namespace, "/proc/%i/ns/user", pid);
+	int my_fd, child_fd, parent_fd;
+
+	my_fd = SAFE_OPEN(my_namespace, O_RDONLY);
+	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+	parent_fd = ioctl(child_fd, NS_GET_USERNS);
+
+	struct stat my_stat, child_stat, parent_stat;
+
+	fstat(my_fd, &my_stat);
+	fstat(child_fd, &child_stat);
+	fstat(parent_fd, &parent_stat);
+	if (my_stat.st_ino != parent_stat.st_ino)
+		tst_res(TFAIL, "parents have different inodes");
+	else if (parent_stat.st_ino == child_stat.st_ino)
+		tst_res(TFAIL, "child and parent have same inode");
+	else
+		tst_res(TPASS, "child and parent are consistent");
+	SAFE_CLOSE(my_fd);
+	SAFE_CLOSE(parent_fd);
+	SAFE_CLOSE(child_fd);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns08.c b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
new file mode 100644
index 000000000..dcb2f11f4
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_* request for file descriptors
+ * that aren't namespaces.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include "tst_test.h"
+
+#ifndef NS_GET_USERNS
+#define NSIO	0xb7
+#define NS_GET_USERNS	   _IO(NSIO, 0x1)
+#define NS_GET_PARENT	   _IO(NSIO, 0x2)
+#define NS_GET_NSTYPE	   _IO(NSIO, 0x3)
+#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
+#endif
+
+static int requests[] = {NS_GET_PARENT, NS_GET_USERNS,
+	NS_GET_OWNER_UID, NS_GET_NSTYPE};
+
+static void test_request(unsigned int n)
+{
+	int request = requests[n];
+	int fd, ns_fd;
+
+	char *path = tst_get_tmpdir();
+
+	fd = SAFE_OPEN(path, O_RDONLY);
+	ns_fd = ioctl(fd, request);
+	if (ns_fd == -1) {
+		if (errno == ENOTTY)
+			tst_res(TPASS, "request failed with ENOTTY");
+		else
+			tst_res(TFAIL, "unexpected error %u", errno);
+	} else {
+		tst_res(TFAIL, "request succes for invalid fd");
+		SAFE_CLOSE(ns_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(requests),
+	.test = test_request,
+	.needs_tmpdir = 1,
+	.min_kver = "4.11",
+};
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v1] Test ioctl syscall for NS_GET_* requests
  2019-02-24 20:29 [LTP] [PATCH v1] Test ioctl syscall for NS_GET_* requests YourName
@ 2019-03-04 16:16 ` Cyril Hrubis
  2019-03-11  7:25   ` [LTP] [PATCH v2] " Federico Bonfiglio
  0 siblings, 1 reply; 16+ messages in thread
From: Cyril Hrubis @ 2019-03-04 16:16 UTC (permalink / raw)
  To: ltp

Hi!
> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
> new file mode 100644
> index 000000000..68baafb48
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.

We started to use SPDX identifiers instead of this, so this whole text
should be replaced with:

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
 */

> +/*
> + * Test ioctl_ns with NS_GET_PARENT request.
> + *
> + * Child process has a new pid namespace, which should make the call fail
> + * with EPERM error.
> + *
> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>

I guess that we don't need the stdio.h include and possibly others.

> +#include <sched.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_PARENT
> +#define NSIO	0xb7
> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
> +#endif

This should be put into a header so that it's not defined in each test,
ideal place would be the include/lapi/ directory in LTP tree.

> +static void test_ns_get_parent(void)
> +{
> +	int fd, parent_fd;
> +	char my_namespace[20];
> +
> +	sprintf(my_namespace, "/proc/self/ns/pid");

We should check in the test setup that this file is present, i.e. do
access(..., F_OK); and exit the test with TCONF if not (which would mean
that the kernel was compiled without namespaces).

Also why do we print the path to the buffer first, can't we just pass it
to the SAFE_OPEN()?

> +	fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +	parent_fd = ioctl(fd, NS_GET_PARENT);
> +	if (parent_fd == -1) {
> +		if (errno == EPERM)
> +			tst_res(TPASS, "NS_GET_PARENT fails with EPERM");
> +		else
> +			tst_res(TFAIL, "unexpected error %u", errno);

We never print errno with %u. You can just bit or the TERRNO flag to the
TFAIL one to get it printed automatically and in human-readable form.

> +		exit(0);
> +	} else {
> +		SAFE_CLOSE(parent_fd);
> +	}
> +	SAFE_CLOSE(fd);
> +	exit(-1);
> +}
> +
> +static void run(void)
> +{
> +	int res = unshare(CLONE_NEWPID);
> +
> +	if (res == -1) {
> +		tst_res(TCONF, "unshare syscall error");

Only failures caused by lack of kernel support should yield TCONF here.

I guess that we may map the errno == EINVAL to TCONF here, the rest
should map to TBROK. Also you should print errno here with TCONF |
TERRNO.

And ideally we should add SAFE_UNSHARE() into include/tst_safe_macros.h.

> +		exit(-1);
> +	}
> +
> +	pid_t pid = SAFE_FORK();
> +
> +	if (pid == 0)
> +		test_ns_get_parent();
> +	else {
> +		int status;
> +
> +		wait(&status);
> +		if (status < 0)
> +			tst_res(TFAIL, "call to ioctl succeded");

There is no need to propagate results from the child, you call
tst_res() there after all.

We can as well just do exit(0) in the child and be done with the test,
the child will be waited for in the test library.

> +	}
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.forks_child = 1,
> +	.min_kver = "4.9",

We are likely missing .needs_root here, or does the test run fine
under unpriviledged user?

> +};
> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
> new file mode 100644
> index 000000000..7feacd626
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_PARENT request.
> + *
> + * Tries to get namespace parent for UTS namespace.

This description should include what is expected to happen, i.e. we
expected EINVAL and why so.

> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_PARENT
> +#define NSIO	0xb7
> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
> +#endif
> +
> +static void run(void)
> +{
> +	int fd, parent_fd;
> +	char my_namespace[20];
> +
> +	sprintf(my_namespace, "/proc/self/ns/uts");
> +	fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +	parent_fd = ioctl(fd, NS_GET_PARENT);
> +	if (parent_fd == -1) {
> +		if (errno == EINVAL)
> +			tst_res(TPASS, "NS_GET_PARENT fails with EINVAL");
> +		else
> +			tst_res(TFAIL, "unexpected error %u", errno);
> +	} else {
> +		tst_res(TFAIL, "call to ioctl succeded");
> +		SAFE_CLOSE(parent_fd);
> +	}
> +	SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.min_kver = "4.9",
> +};

All the comments from the previous test apply here as well.

> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns03.c b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c
> new file mode 100644
> index 000000000..3d4e92872
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_PARENT request.
> + *
> + * Tries to get parent of initial namespace.

Again a bit more verbose description wouldn't harm.

> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_PARENT
> +#define NSIO	0xb7
> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
> +#endif
> +
> +static void run(void)
> +{
> +	int fd, parent_fd;
> +	char my_namespace[20];
> +
> +	sprintf(my_namespace, "/proc/self/ns/pid");
> +	fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +	parent_fd = ioctl(fd, NS_GET_PARENT);
> +	if (parent_fd == -1) {
> +		if (errno == EPERM)
> +			tst_res(TPASS, "NS_GET_PARENT of initial user fails");
> +		else
> +			tst_res(TFAIL, "unexpected error %u", errno);
> +	} else {
> +		tst_res(TFAIL, "call to ioctl succeded");
> +		SAFE_CLOSE(parent_fd);
> +	}
> +	SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.min_kver = "4.9",
> +};

Also this is very similar to the first test, maybe it would make more
sense to merge these two into one test and run the run function twice,
once from the initial namespace and once after the unshare call.

> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
> new file mode 100644
> index 000000000..c61360611
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
> @@ -0,0 +1,65 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_OWNER_UID request.
> + *
> + * Fails attempting request for UTS namespace.

Here as well, better explanation.

> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_OWNER_UID
> +#define NSIO    0xb7
> +#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
> +#endif
> +
> +static void run(void)
> +{
> +	int fd, owner_fd;
> +	char my_namespace[20];
> +
> +	sprintf(my_namespace, "/proc/self/ns/uts");
> +	fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +	uid_t uid;
> +
> +	owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid);
> +	if (owner_fd == -1) {
> +		if (errno == EINVAL)
> +			tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace");
> +		else
> +			tst_res(TFAIL, "unexpected error %u", errno);
> +	} else {
> +		tst_res(TFAIL, "call to ioctl succeded");
> +		SAFE_CLOSE(owner_fd);
> +	}
> +	SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.min_kver = "4.11",
> +};

The rest of the comments apply here as well.

> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
> new file mode 100644
> index 000000000..987012394
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
> @@ -0,0 +1,63 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_USERNS request.
> + *
> + * Fails attempting request for out of scope namespace.

Here as well, slightly better description.

> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_USERNS
> +#define NSIO    0xb7
> +#define NS_GET_USERNS	   _IO(NSIO, 0x1)
> +#endif
> +
> +static void run(void)
> +{
> +	int fd, parent_fd;
> +	char my_namespace[20];
> +
> +	sprintf(my_namespace, "/proc/self/ns/user");
> +	fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +	parent_fd = ioctl(fd, NS_GET_USERNS);
> +	if (parent_fd == -1) {
> +		if (errno == EPERM)
> +			tst_res(TPASS, "NS_GET_USERNS fails with EPERM");
> +		else
> +			tst_res(TFAIL, "unexpected error %u", errno);
> +	} else {
> +		tst_res(TFAIL, "call to ioctl succeded");
> +		SAFE_CLOSE(parent_fd);
> +	}
> +	SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.min_kver = "4.9",
> +};

And the rest of the comments apply as well.

> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
> new file mode 100644
> index 000000000..9a0eb93f6
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_PARENT request.
> + *
> + * Child process should have a new namespace.

You should elaborate here _what_ we are testing here. It's not clear
what the test does based on this sentence. Especially you should
describe why we decided to check this based on inodes of the file
descriptors.

> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sched.h>
> +#include <sys/stat.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_PARENT
> +#define NSIO	0xb7
> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
> +#endif
> +
> +static void run(void)
> +{
> +	int res = unshare(CLONE_NEWPID);
> +
> +	if (res < 0) {
> +		tst_res(TCONF, "unshare error");
> +		exit(0);
> +	}
> +	pid_t pid = SAFE_FORK();
> +
> +	if (pid == 0) {
> +		exit(0);
> +	} else {

There is no point in running the rest of the code in the else branch as
the main branch calls exit(0);

> +		char my_namespace[20], child_namespace[20];
> +
> +		sprintf(my_namespace, "/proc/self/ns/pid");

Again no need to print the constant string into a buffer.

> +		sprintf(child_namespace, "/proc/%i/ns/pid", pid);
> +		int my_fd, child_fd, parent_fd;
> +
> +		my_fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +		child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
> +		parent_fd = ioctl(child_fd, NS_GET_PARENT);

Use SAFE_IOCTL() here.

> +		struct stat my_stat, child_stat, parent_stat;
> +
> +		fstat(my_fd, &my_stat);
> +		fstat(child_fd, &child_stat);
> +		fstat(parent_fd, &parent_stat);

And SAFE_FSTAT() here.

> +		if (my_stat.st_ino != parent_stat.st_ino)
> +			tst_res(TFAIL, "parents have different inodes");
> +		else if (parent_stat.st_ino == child_stat.st_ino)
> +			tst_res(TFAIL, "child and parent have same inode");
> +		else
> +			tst_res(TPASS, "child and parent are consistent");
> +
> +		SAFE_CLOSE(my_fd);
> +		SAFE_CLOSE(child_fd);
> +		SAFE_CLOSE(parent_fd);
> +	}
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.forks_child = 1,
> +	.min_kver = "4.9",
> +};
> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
> new file mode 100644
> index 000000000..a743bb1c8
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
> @@ -0,0 +1,83 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_USERNS request.
> + *
> + * Child process should have a new namespace.

Here as well.

> + */
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sched.h>
> +#include <sys/stat.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_USERNS
> +#define NSIO	0xb7
> +#define NS_GET_USERNS   _IO(NSIO, 0x1)
> +#endif
> +
> +#define STACK_SIZE (1024 * 1024)
> +
> +static char child_stack[STACK_SIZE];
> +
> +static int child(void *arg)
> +{
> +	return 0;
> +}
> +
> +static void run(void)
> +{
> +	pid_t pid = ltp_clone(CLONE_NEWUSER, &child, 0,
> +		STACK_SIZE, child_stack);
> +
> +	char my_namespace[20], child_namespace[20];
> +
> +	sprintf(my_namespace, "/proc/self/ns/user");
> +	sprintf(child_namespace, "/proc/%i/ns/user", pid);
> +	int my_fd, child_fd, parent_fd;
> +
> +	my_fd = SAFE_OPEN(my_namespace, O_RDONLY);
> +	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);

Isn't this racy? What happens if the child() function returns before we
happen to open this file?

> +	parent_fd = ioctl(child_fd, NS_GET_USERNS);
> +
> +	struct stat my_stat, child_stat, parent_stat;
> +
> +	fstat(my_fd, &my_stat);
> +	fstat(child_fd, &child_stat);
> +	fstat(parent_fd, &parent_stat);
> +	if (my_stat.st_ino != parent_stat.st_ino)
> +		tst_res(TFAIL, "parents have different inodes");
> +	else if (parent_stat.st_ino == child_stat.st_ino)
> +		tst_res(TFAIL, "child and parent have same inode");
> +	else
> +		tst_res(TPASS, "child and parent are consistent");
> +	SAFE_CLOSE(my_fd);
> +	SAFE_CLOSE(parent_fd);
> +	SAFE_CLOSE(child_fd);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.forks_child = 1,
> +	.min_kver = "4.9",
> +};

The rest of the comments apply as well.

> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns08.c b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
> new file mode 100644
> index 000000000..dcb2f11f4
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_* request for file descriptors
> + * that aren't namespaces.
> + *
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/wait.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +
> +#ifndef NS_GET_USERNS
> +#define NSIO	0xb7
> +#define NS_GET_USERNS	   _IO(NSIO, 0x1)
> +#define NS_GET_PARENT	   _IO(NSIO, 0x2)
> +#define NS_GET_NSTYPE	   _IO(NSIO, 0x3)
> +#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
> +#endif
> +
> +static int requests[] = {NS_GET_PARENT, NS_GET_USERNS,
> +	NS_GET_OWNER_UID, NS_GET_NSTYPE};
> +
> +static void test_request(unsigned int n)
> +{
> +	int request = requests[n];
> +	int fd, ns_fd;
> +
> +	char *path = tst_get_tmpdir();

This leaks memory, also there is no need to pass the global path to
SAFE_OPEN below, it should work just fine with "." because the test PWD
is set to the temporary directory before this function is executed.

> +	fd = SAFE_OPEN(path, O_RDONLY);
> +	ns_fd = ioctl(fd, request);
> +	if (ns_fd == -1) {
> +		if (errno == ENOTTY)
> +			tst_res(TPASS, "request failed with ENOTTY");
> +		else
> +			tst_res(TFAIL, "unexpected error %u", errno);

Here as well use the TERRNO flag.

> +	} else {
> +		tst_res(TFAIL, "request succes for invalid fd");
> +		SAFE_CLOSE(ns_fd);
> +	}
> +	SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.tcnt = ARRAY_SIZE(requests),
> +	.test = test_request,
> +	.needs_tmpdir = 1,
> +	.min_kver = "4.11",
> +};

Generally these tests looks good, but needs a few adjustments.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v2] Test ioctl syscall for NS_GET_* requests
  2019-03-04 16:16 ` Cyril Hrubis
@ 2019-03-11  7:25   ` Federico Bonfiglio
  2019-03-18 14:22     ` Cyril Hrubis
  2019-03-18 15:30     ` Cyril Hrubis
  0 siblings, 2 replies; 16+ messages in thread
From: Federico Bonfiglio @ 2019-03-11  7:25 UTC (permalink / raw)
  To: ltp

---
Thanks Cyril for your review. I hope this one is better, also I could't use 
SAFE_IOCTL because compilations fails this way:

ioctl_ns06.c: In function 'run':
ioctl_ns06.c:46:13: error: void value not ignored as it ought to be
   parent_fd = SAFE_IOCTL(child_fd, NS_GET_PARENT);
             ^
<builtin>: recipe for target 'ioctl_ns06' failed
make: *** [ioctl_ns06] Error 1

I need the return value since it's the process pid. Am I doing somthing wrong
with this safe call?

 include/lapi/ioctl_ns.h                      | 29 +++++++++++
 include/tst_safe_macros.h                    |  4 ++
 lib/tst_safe_macros.c                        | 17 +++++++
 runtest/syscalls                             |  8 +++
 testcases/kernel/syscalls/ioctl/.gitignore   |  7 +++
 testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 59 ++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 43 ++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 44 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 42 ++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 72 +++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 73 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns08.c | 51 +++++++++++++++++++
 12 files changed, 449 insertions(+)
 create mode 100644 include/lapi/ioctl_ns.h
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns08.c

diff --git a/include/lapi/ioctl_ns.h b/include/lapi/ioctl_ns.h
new file mode 100644
index 000000000..ebaf43a24
--- /dev/null
+++ b/include/lapi/ioctl_ns.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+#ifndef __IOCTL_NS_H__
+#define __IOCTL_NS_H__
+
+#ifndef _IO
+#define _IO			volatile
+#endif
+#ifndef NSIO
+#define NSIO	0xb7
+#endif
+#ifndef NS_GET_PARENT
+#define NS_GET_PARENT		_IO(NSIO, 0x2)
+#endif
+#ifndef NS_GET_OWNER_UID
+#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
+#endif
+#ifndef NS_GET_USERNS
+#define NS_GET_USERNS		_IO(NSIO, 0x1)
+#endif
+#ifndef NS_GET_NSTYPE
+#define NS_GET_NSTYPE		_IO(NSIO, 0x3)
+#endif
+
+
+#endif /* __IOCTL_NS_H__ */
diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index d31762f4a..b63e7493a 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -526,4 +526,8 @@ int safe_personality(const char *filename, unsigned int lineno,
 	}							\
 	} while (0)
 
+void safe_unshare(const char *file, const int lineno, int flags);
+#define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags))
+
+
 #endif /* SAFE_MACROS_H__ */
diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c
index c375030a4..761d1d3dd 100644
--- a/lib/tst_safe_macros.c
+++ b/lib/tst_safe_macros.c
@@ -18,6 +18,7 @@
 #define _GNU_SOURCE
 #include <unistd.h>
 #include <errno.h>
+#include <sched.h>
 #include "config.h"
 #ifdef HAVE_SYS_FANOTIFY_H
 # include <sys/fanotify.h>
@@ -197,3 +198,19 @@ int safe_chroot(const char *file, const int lineno, const char *path)
 
 	return rval;
 }
+
+void safe_unshare(const char *file, const int lineno, int flags)
+{
+	int res;
+
+	res = unshare(flags);
+	if (res == -1) {
+		if (errno == EINVAL) {
+			tst_brk_(file, lineno, TCONF,
+				 "unshare(%d) failed", flags);
+		} else {
+			tst_brk_(file, lineno, TBROK | TERRNO,
+				 "dup(%d) failed", flags);
+		}
+	}
+}
diff --git a/runtest/syscalls b/runtest/syscalls
index 978a56a07..f8fa2dfc4 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -500,6 +500,14 @@ ioctl06      ioctl06
 
 ioctl07      ioctl07
 
+ioctl_ns01 ioctl_ns01
+ioctl_ns02 ioctl_ns02
+ioctl_ns04 ioctl_ns04
+ioctl_ns05 ioctl_ns05
+ioctl_ns06 ioctl_ns06
+ioctl_ns07 ioctl_ns07
+ioctl_ns08 ioctl_ns08
+
 inotify_init1_01 inotify_init1_01
 inotify_init1_02 inotify_init1_02
 
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 79516a17c..57d6a58fa 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -5,3 +5,10 @@
 /ioctl05
 /ioctl06
 /ioctl07
+/ioctl_ns01
+/ioctl_ns02
+/ioctl_ns04
+/ioctl_ns05
+/ioctl_ns06
+/ioctl_ns07
+/ioctl_ns08
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
new file mode 100644
index 000000000..88f3fb043
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Parent process tries to get parent of initial namespace, which should
+ * fail with EPERM because it has no parent.
+ *
+ * Child process has a new pid namespace, which should make the call fail
+ * with EPERM error.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void test_ns_get_parent(void)
+{
+	int exists, fd, parent_fd;
+
+	exists = access("/proc/self/ns/pid", F_OK);
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+	fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_PARENT fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static void run(void)
+{
+	test_ns_get_parent();
+	SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0)
+		test_ns_get_parent();
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
new file mode 100644
index 000000000..420e1708f
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Tries to get namespace parent for UTS namespace, which
+ * should make the call fail with EINVAL, being a nonhierarchical
+ * namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void run(void)
+{
+	int exists, fd, parent_fd;
+
+	exists = access("/proc/self/ns/uts", F_OK);
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_PARENT fails with EINVAL");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
new file mode 100644
index 000000000..a4465ef1e
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_OWNER_UID request.
+ *
+ * Calls ioctl for a UTS namespace, which isn't a user namespace.
+ * This should make the call fail with EINVAL.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void run(void)
+{
+	int exists, fd, owner_fd;
+
+	exists = access("/proc/self/ns/uts", F_OK);
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	uid_t uid;
+
+	owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid);
+	if (owner_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.11",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
new file mode 100644
index 000000000..c12f345e7
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * Owning user namespace of process calling ioctl is out of scope,
+ * which should make the call fail with EPERM.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void run(void)
+{
+	int exists, fd, parent_fd;
+
+	exists = access("/proc/self/ns/user", F_OK);
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+	fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_USERNS);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_USERNS fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
new file mode 100644
index 000000000..6fd6f758d
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * After the call to unshare with the CLONE_NEWPID flag,
+ * next new child is created in a new pid namespace. That's checked by
+ * comparing its /proc/self/ns/pid symlink and the parent's one.
+ * Also child thinks its pid is 1.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void run(void)
+{
+	SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0) {
+		if (getpid() != 1)
+			tst_res(TFAIL, "child should think its pid is 1");
+		else
+			tst_res(TPASS, "child thinks its pid is 1");
+		TST_CHECKPOINT_WAIT(0);
+	} else {
+		char child_namespace[20];
+		int exists_1, exists_2, my_fd, child_fd, parent_fd;
+
+		sprintf(child_namespace, "/proc/%i/ns/pid", pid);
+		exists_1 = access("/proc/self/ns/pid", F_OK);
+		exists_2 = access(child_namespace, F_OK);
+		if (exists_1 < 0 || exists_2 < 0)
+			tst_res(TCONF, "namespace not available");
+		my_fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+		child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+		parent_fd = ioctl(child_fd, NS_GET_PARENT);
+
+		struct stat my_stat, child_stat, parent_stat;
+
+		SAFE_FSTAT(my_fd, &my_stat);
+		SAFE_FSTAT(child_fd, &child_stat);
+		SAFE_FSTAT(parent_fd, &parent_stat);
+		if (my_stat.st_ino != parent_stat.st_ino)
+			tst_res(TFAIL, "parents have different inodes");
+		else if (parent_stat.st_ino == child_stat.st_ino)
+			tst_res(TFAIL, "child and parent have same inode");
+		else
+			tst_res(TPASS, "child and parent are consistent");
+		SAFE_CLOSE(my_fd);
+		SAFE_CLOSE(child_fd);
+		SAFE_CLOSE(parent_fd);
+		TST_CHECKPOINT_WAKE(0);
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
new file mode 100644
index 000000000..88efb41a4
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * After the call to clone with the CLONE_NEWUSER flag,
+ * child is created in a new user namespace. That's checked by
+ * comparing its /proc/self/ns/user symlink and the parent's one,
+ * which should be different.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static int child(void *arg)
+{
+	TST_CHECKPOINT_WAIT(0);
+	return 0;
+}
+
+static void run(void)
+{
+	pid_t pid = ltp_clone(CLONE_NEWUSER, &child, 0,
+		STACK_SIZE, child_stack);
+	char child_namespace[20];
+
+	sprintf(child_namespace, "/proc/%i/ns/user", pid);
+	int exists_1, exists_2, my_fd, child_fd, parent_fd;
+
+	exists_1 = access("/proc/self/ns/user", F_OK);
+	exists_2 = access(child_namespace, F_OK);
+	if (exists_1 < 0 || exists_2 < 0)
+		tst_res(TCONF, "namespace not available");
+	my_fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+	parent_fd = ioctl(child_fd, NS_GET_USERNS);
+
+	struct stat my_stat, child_stat, parent_stat;
+
+	SAFE_FSTAT(my_fd, &my_stat);
+	SAFE_FSTAT(child_fd, &child_stat);
+	SAFE_FSTAT(parent_fd, &parent_stat);
+	if (my_stat.st_ino != parent_stat.st_ino)
+		tst_res(TFAIL, "parents have different inodes");
+	else if (parent_stat.st_ino == child_stat.st_ino)
+		tst_res(TFAIL, "child and parent have same inode");
+	else
+		tst_res(TPASS, "child and parent are consistent");
+	SAFE_CLOSE(my_fd);
+	SAFE_CLOSE(parent_fd);
+	SAFE_CLOSE(child_fd);
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns08.c b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
new file mode 100644
index 000000000..bc2026213
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_* request for file descriptors
+ * that aren't namespaces.
+ *
+ * Calling ioctl with test directory's file descriptor
+ * should make the call fail with ENOTTY.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static int requests[] = {NS_GET_PARENT, NS_GET_USERNS,
+	NS_GET_OWNER_UID, NS_GET_NSTYPE};
+
+static void test_request(unsigned int n)
+{
+	int request = requests[n];
+	int exists, fd, ns_fd;
+
+	exists = access(".", F_OK);
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+	fd = SAFE_OPEN(".", O_RDONLY);
+	ns_fd = ioctl(fd, request);
+	if (ns_fd == -1) {
+		if (errno == ENOTTY)
+			tst_res(TPASS, "request failed with ENOTTY");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		tst_res(TFAIL, "request success for invalid fd");
+		SAFE_CLOSE(ns_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(requests),
+	.test = test_request,
+	.needs_tmpdir = 1,
+	.min_kver = "4.11",
+};
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v2] Test ioctl syscall for NS_GET_* requests
  2019-03-11  7:25   ` [LTP] [PATCH v2] " Federico Bonfiglio
@ 2019-03-18 14:22     ` Cyril Hrubis
  2019-03-18 15:30     ` Cyril Hrubis
  1 sibling, 0 replies; 16+ messages in thread
From: Cyril Hrubis @ 2019-03-18 14:22 UTC (permalink / raw)
  To: ltp

Hi!
> Thanks Cyril for your review. I hope this one is better, also I could't use 
> SAFE_IOCTL because compilations fails this way:
> 
> ioctl_ns06.c: In function 'run':
> ioctl_ns06.c:46:13: error: void value not ignored as it ought to be
>    parent_fd = SAFE_IOCTL(child_fd, NS_GET_PARENT);
>              ^
> <builtin>: recipe for target 'ioctl_ns06' failed
> make: *** [ioctl_ns06] Error 1
> 
> I need the return value since it's the process pid. Am I doing somthing wrong
> with this safe call?

There is actually a bug in the macro, this patch should fix it:

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index b63e7493a..04aedb39a 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -221,7 +221,7 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid);
        ({int tst_ret_ = ioctl(fd, request, ##__VA_ARGS__);  \
          tst_ret_ < 0 ?                                     \
           tst_brk(TBROK | TERRNO,                           \
-                   "ioctl(%i,%s,...) failed", fd, #request) \
+                   "ioctl(%i,%s,...) failed", fd, #request), 0 \
         : tst_ret_;})

I will send a patch fixing that.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v2] Test ioctl syscall for NS_GET_* requests
  2019-03-11  7:25   ` [LTP] [PATCH v2] " Federico Bonfiglio
  2019-03-18 14:22     ` Cyril Hrubis
@ 2019-03-18 15:30     ` Cyril Hrubis
  2019-03-19 18:09       ` [LTP] [PATCH v3] " Federico Bonfiglio
  1 sibling, 1 reply; 16+ messages in thread
From: Cyril Hrubis @ 2019-03-18 15:30 UTC (permalink / raw)
  To: ltp

Hi!
>  include/lapi/ioctl_ns.h                      | 29 +++++++++++
>  include/tst_safe_macros.h                    |  4 ++
>  lib/tst_safe_macros.c                        | 17 +++++++

Ideally unrelated changes should be each in separate commits, i.e. one
for ioctl_ns.h and one for safe macros, but that is no big issue.

>  runtest/syscalls                             |  8 +++
>  testcases/kernel/syscalls/ioctl/.gitignore   |  7 +++
>  testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 59 ++++++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 43 ++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 44 +++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 42 ++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 72 +++++++++++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 73 ++++++++++++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns08.c | 51 +++++++++++++++++++
>  12 files changed, 449 insertions(+)
>  create mode 100644 include/lapi/ioctl_ns.h
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns08.c
> 
> diff --git a/include/lapi/ioctl_ns.h b/include/lapi/ioctl_ns.h
> new file mode 100644
> index 000000000..ebaf43a24
> --- /dev/null
> +++ b/include/lapi/ioctl_ns.h
> @@ -0,0 +1,29 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + */
> +
> +#ifndef __IOCTL_NS_H__
> +#define __IOCTL_NS_H__

All identifiers starting with underscore are resevered for libc and
kernel headers.

> +#ifndef _IO
> +#define _IO			volatile
> +#endif

This is obviously nonsense, the _IO() definition you are looking for
packs the parameters into an integer with bitshifts and or. See
include/uapi/asm-generic/ioctl.h

It looks like it should be safe enough to include the header here, i.e.
#include <asm-generic/ioctl.h> as there does not seem to be any other
(glibc) header defining the _IO* macros.

> +#ifndef NSIO
> +#define NSIO	0xb7
> +#endif
> +#ifndef NS_GET_PARENT
> +#define NS_GET_PARENT		_IO(NSIO, 0x2)
> +#endif
> +#ifndef NS_GET_OWNER_UID
> +#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
> +#endif
> +#ifndef NS_GET_USERNS
> +#define NS_GET_USERNS		_IO(NSIO, 0x1)
> +#endif
> +#ifndef NS_GET_NSTYPE
> +#define NS_GET_NSTYPE		_IO(NSIO, 0x3)
> +#endif
> +
> +
> +#endif /* __IOCTL_NS_H__ */
> diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
> index d31762f4a..b63e7493a 100644
> --- a/include/tst_safe_macros.h
> +++ b/include/tst_safe_macros.h
> @@ -526,4 +526,8 @@ int safe_personality(const char *filename, unsigned int lineno,
>  	}							\
>  	} while (0)
>  
> +void safe_unshare(const char *file, const int lineno, int flags);
> +#define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags))
> +
> +
>  #endif /* SAFE_MACROS_H__ */
> diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c
> index c375030a4..761d1d3dd 100644
> --- a/lib/tst_safe_macros.c
> +++ b/lib/tst_safe_macros.c
> @@ -18,6 +18,7 @@
>  #define _GNU_SOURCE
>  #include <unistd.h>
>  #include <errno.h>
> +#include <sched.h>
>  #include "config.h"
>  #ifdef HAVE_SYS_FANOTIFY_H
>  # include <sys/fanotify.h>
> @@ -197,3 +198,19 @@ int safe_chroot(const char *file, const int lineno, const char *path)
>  
>  	return rval;
>  }
> +
> +void safe_unshare(const char *file, const int lineno, int flags)
> +{
> +	int res;
> +
> +	res = unshare(flags);
> +	if (res == -1) {
> +		if (errno == EINVAL) {
> +			tst_brk_(file, lineno, TCONF,
> +				 "unshare(%d) failed", flags);
                                               ^
					       This should be rather
					       "unsupported"
					       and I would have added
					       the TERRNO flag as well
					       so that the user sees the
					       errno that lead to this
> +		} else {
> +			tst_brk_(file, lineno, TBROK | TERRNO,
> +				 "dup(%d) failed", flags);
                                   ^
				   Copy&paste error I guess
> +		}
> +	}
> +}
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 978a56a07..f8fa2dfc4 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -500,6 +500,14 @@ ioctl06      ioctl06
>  
>  ioctl07      ioctl07
>  
> +ioctl_ns01 ioctl_ns01
> +ioctl_ns02 ioctl_ns02
> +ioctl_ns04 ioctl_ns04
> +ioctl_ns05 ioctl_ns05
> +ioctl_ns06 ioctl_ns06
> +ioctl_ns07 ioctl_ns07
> +ioctl_ns08 ioctl_ns08
> +
>  inotify_init1_01 inotify_init1_01
>  inotify_init1_02 inotify_init1_02
>  
> diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
> index 79516a17c..57d6a58fa 100644
> --- a/testcases/kernel/syscalls/ioctl/.gitignore
> +++ b/testcases/kernel/syscalls/ioctl/.gitignore
> @@ -5,3 +5,10 @@
>  /ioctl05
>  /ioctl06
>  /ioctl07
> +/ioctl_ns01
> +/ioctl_ns02
> +/ioctl_ns04
> +/ioctl_ns05
> +/ioctl_ns06
> +/ioctl_ns07
> +/ioctl_ns08
> diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
> new file mode 100644
> index 000000000..88f3fb043
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
> @@ -0,0 +1,59 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
> + */
> +
> +/*
> + * Test ioctl_ns with NS_GET_PARENT request.
> + *
> + * Parent process tries to get parent of initial namespace, which should
> + * fail with EPERM because it has no parent.
> + *
> + * Child process has a new pid namespace, which should make the call fail
> + * with EPERM error.
> + *
> + */
> +#define _GNU_SOURCE
> +
> +#include <errno.h>
> +#include <sched.h>
> +#include "tst_test.h"
> +#include "lapi/ioctl_ns.h"
> +
> +static void test_ns_get_parent(void)
> +{
> +	int exists, fd, parent_fd;
> +
> +	exists = access("/proc/self/ns/pid", F_OK);
> +	if (exists < 0)
> +		tst_res(TCONF, "namespace not available");

Can we do this check in test setup?

Or do we actually have to check after the unshare as well?

(and the same applies to most of these testcases)


The rest looks good.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v3] Test ioctl syscall for NS_GET_* requests
  2019-03-18 15:30     ` Cyril Hrubis
@ 2019-03-19 18:09       ` Federico Bonfiglio
  2019-03-26 19:20         ` Cyril Hrubis
  0 siblings, 1 reply; 16+ messages in thread
From: Federico Bonfiglio @ 2019-03-19 18:09 UTC (permalink / raw)
  To: ltp

---
Hi Cyril, thanks for your patience. From what I understood, all the /proc/self/ns/* files exist if the kernel is compiled with namespaces. So only one of them has to be checked for each test, making additional checks for other processes namespaces symlinks redundant. If this is true, here's the updated patch, otherwise I'll add all the other checks for child processes. 

I also changed the TCONF message in ioctl_ns08.c from "namespace not available" to "can't access current directory" since "." isn't a namespace, and we are trying to open a file that's not a namespace.

 include/lapi/ioctl_ns.h                      | 28 ++++++++++
 include/tst_safe_macros.h                    |  4 ++
 lib/tst_safe_macros.c                        | 17 ++++++
 runtest/syscalls                             |  8 +++
 testcases/kernel/syscalls/ioctl/.gitignore   |  7 +++
 testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 65 +++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 49 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 50 ++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 48 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 77 +++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 78 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns08.c | 57 ++++++++++++++++++++
 12 files changed, 488 insertions(+)
 create mode 100644 include/lapi/ioctl_ns.h
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns08.c

diff --git a/include/lapi/ioctl_ns.h b/include/lapi/ioctl_ns.h
new file mode 100644
index 000000000..2fb4f4cfb
--- /dev/null
+++ b/include/lapi/ioctl_ns.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+#ifndef IOCTL_NS_H__
+#define IOCTL_NS_H__
+
+#include <asm-generic/ioctl.h>
+
+#ifndef NSIO
+#define NSIO	0xb7
+#endif
+#ifndef NS_GET_PARENT
+#define NS_GET_PARENT		_IO(NSIO, 0x2)
+#endif
+#ifndef NS_GET_OWNER_UID
+#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
+#endif
+#ifndef NS_GET_USERNS
+#define NS_GET_USERNS		_IO(NSIO, 0x1)
+#endif
+#ifndef NS_GET_NSTYPE
+#define NS_GET_NSTYPE		_IO(NSIO, 0x3)
+#endif
+
+
+#endif /* IOCTL_NS_H__ */
diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index 5e85abc9c..04aedb39a 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -526,4 +526,8 @@ int safe_personality(const char *filename, unsigned int lineno,
 	}							\
 	} while (0)
 
+void safe_unshare(const char *file, const int lineno, int flags);
+#define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags))
+
+
 #endif /* SAFE_MACROS_H__ */
diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c
index c375030a4..9480ca910 100644
--- a/lib/tst_safe_macros.c
+++ b/lib/tst_safe_macros.c
@@ -18,6 +18,7 @@
 #define _GNU_SOURCE
 #include <unistd.h>
 #include <errno.h>
+#include <sched.h>
 #include "config.h"
 #ifdef HAVE_SYS_FANOTIFY_H
 # include <sys/fanotify.h>
@@ -197,3 +198,19 @@ int safe_chroot(const char *file, const int lineno, const char *path)
 
 	return rval;
 }
+
+void safe_unshare(const char *file, const int lineno, int flags)
+{
+	int res;
+
+	res = unshare(flags);
+	if (res == -1) {
+		if (errno == EINVAL) {
+			tst_brk_(file, lineno, TCONF | TERRNO,
+				 "unshare(%d) unsupported", flags);
+		} else {
+			tst_brk_(file, lineno, TBROK | TERRNO,
+				 "unshare(%d) unsupported", flags);
+		}
+	}
+}
diff --git a/runtest/syscalls b/runtest/syscalls
index 03b613c07..0a022254e 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -500,6 +500,14 @@ ioctl06      ioctl06
 
 ioctl07      ioctl07
 
+ioctl_ns01 ioctl_ns01
+ioctl_ns02 ioctl_ns02
+ioctl_ns04 ioctl_ns04
+ioctl_ns05 ioctl_ns05
+ioctl_ns06 ioctl_ns06
+ioctl_ns07 ioctl_ns07
+ioctl_ns08 ioctl_ns08
+
 inotify_init1_01 inotify_init1_01
 inotify_init1_02 inotify_init1_02
 
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 79516a17c..57d6a58fa 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -5,3 +5,10 @@
 /ioctl05
 /ioctl06
 /ioctl07
+/ioctl_ns01
+/ioctl_ns02
+/ioctl_ns04
+/ioctl_ns05
+/ioctl_ns06
+/ioctl_ns07
+/ioctl_ns08
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
new file mode 100644
index 000000000..340cb315f
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Parent process tries to get parent of initial namespace, which should
+ * fail with EPERM because it has no parent.
+ *
+ * Child process has a new pid namespace, which should make the call fail
+ * with EPERM error.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/pid", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void test_ns_get_parent(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_PARENT fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static void run(void)
+{
+	test_ns_get_parent();
+	SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0)
+		test_ns_get_parent();
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
new file mode 100644
index 000000000..4f5cb1427
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Tries to get namespace parent for UTS namespace, which
+ * should make the call fail with EINVAL, being a nonhierarchical
+ * namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/uts", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_PARENT fails with EINVAL");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
new file mode 100644
index 000000000..2e19cff3a
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_OWNER_UID request.
+ *
+ * Calls ioctl for a UTS namespace, which isn't a user namespace.
+ * This should make the call fail with EINVAL.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/uts", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, owner_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	uid_t uid;
+
+	owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid);
+	if (owner_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.11",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
new file mode 100644
index 000000000..b9181cb3d
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * Owning user namespace of process calling ioctl is out of scope,
+ * which should make the call fail with EPERM.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/user", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_USERNS);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_USERNS fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
new file mode 100644
index 000000000..ae377b095
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * After the call to unshare with the CLONE_NEWPID flag,
+ * next new child is created in a new pid namespace. That's checked by
+ * comparing its /proc/self/ns/pid symlink and the parent's one.
+ * Also child thinks its pid is 1.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/pid", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0) {
+		if (getpid() != 1)
+			tst_res(TFAIL, "child should think its pid is 1");
+		else
+			tst_res(TPASS, "child thinks its pid is 1");
+		TST_CHECKPOINT_WAIT(0);
+	} else {
+		char child_namespace[20];
+		int my_fd, child_fd, parent_fd;
+
+		sprintf(child_namespace, "/proc/%i/ns/pid", pid);
+		my_fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+		child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+		parent_fd = SAFE_IOCTL(child_fd, NS_GET_PARENT);
+
+		struct stat my_stat, child_stat, parent_stat;
+
+		SAFE_FSTAT(my_fd, &my_stat);
+		SAFE_FSTAT(child_fd, &child_stat);
+		SAFE_FSTAT(parent_fd, &parent_stat);
+		if (my_stat.st_ino != parent_stat.st_ino)
+			tst_res(TFAIL, "parents have different inodes");
+		else if (parent_stat.st_ino == child_stat.st_ino)
+			tst_res(TFAIL, "child and parent have same inode");
+		else
+			tst_res(TPASS, "child and parent are consistent");
+		SAFE_CLOSE(my_fd);
+		SAFE_CLOSE(child_fd);
+		SAFE_CLOSE(parent_fd);
+		TST_CHECKPOINT_WAKE(0);
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
new file mode 100644
index 000000000..f077a3bb7
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * After the call to clone with the CLONE_NEWUSER flag,
+ * child is created in a new user namespace. That's checked by
+ * comparing its /proc/self/ns/user symlink and the parent's one,
+ * which should be different.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/user", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static int child(void *arg)
+{
+	TST_CHECKPOINT_WAIT(0);
+	return 0;
+}
+
+static void run(void)
+{
+	pid_t pid = ltp_clone(CLONE_NEWUSER, &child, 0,
+		STACK_SIZE, child_stack);
+	char child_namespace[20];
+
+	sprintf(child_namespace, "/proc/%i/ns/user", pid);
+	int my_fd, child_fd, parent_fd;
+
+	my_fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+	parent_fd = SAFE_IOCTL(child_fd, NS_GET_USERNS);
+
+	struct stat my_stat, child_stat, parent_stat;
+
+	SAFE_FSTAT(my_fd, &my_stat);
+	SAFE_FSTAT(child_fd, &child_stat);
+	SAFE_FSTAT(parent_fd, &parent_stat);
+	if (my_stat.st_ino != parent_stat.st_ino)
+		tst_res(TFAIL, "parents have different inodes");
+	else if (parent_stat.st_ino == child_stat.st_ino)
+		tst_res(TFAIL, "child and parent have same inode");
+	else
+		tst_res(TPASS, "child and parent are consistent");
+	SAFE_CLOSE(my_fd);
+	SAFE_CLOSE(parent_fd);
+	SAFE_CLOSE(child_fd);
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns08.c b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
new file mode 100644
index 000000000..ebed0f5f0
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_* request for file descriptors
+ * that aren't namespaces.
+ *
+ * Calling ioctl with test directory's file descriptor
+ * should make the call fail with ENOTTY.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static int requests[] = {NS_GET_PARENT, NS_GET_USERNS,
+	NS_GET_OWNER_UID, NS_GET_NSTYPE};
+
+static void setup(void)
+{
+	int exists = access(".", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "can't access current directory");
+}
+
+static void test_request(unsigned int n)
+{
+	int request = requests[n];
+	int fd, ns_fd;
+
+	fd = SAFE_OPEN(".", O_RDONLY);
+	ns_fd = ioctl(fd, request);
+	if (ns_fd == -1) {
+		if (errno == ENOTTY)
+			tst_res(TPASS, "request failed with ENOTTY");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		tst_res(TFAIL, "request success for invalid fd");
+		SAFE_CLOSE(ns_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(requests),
+	.test = test_request,
+	.needs_tmpdir = 1,
+	.min_kver = "4.11",
+	.setup = setup
+};
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v3] Test ioctl syscall for NS_GET_* requests
  2019-03-19 18:09       ` [LTP] [PATCH v3] " Federico Bonfiglio
@ 2019-03-26 19:20         ` Cyril Hrubis
  2019-03-28 20:22           ` [LTP] [PATCH v4 1/2] include/SAFE_UNSHARE() macro added Federico Bonfiglio
  2019-03-28 20:22           ` [LTP] [PATCH v4 2/2] Test ioctl syscall for NS_GET_* requests Federico Bonfiglio
  0 siblings, 2 replies; 16+ messages in thread
From: Cyril Hrubis @ 2019-03-26 19:20 UTC (permalink / raw)
  To: ltp

Hi!
> Hi Cyril, thanks for your patience. From what I understood, all the
> /proc/self/ns/* files exist if the kernel is compiled with namespaces.
> So only one of them has to be checked for each test, making additional
> checks for other processes namespaces symlinks redundant. If this is
> true, here's the updated patch, otherwise I'll add all the other
> checks for child processes.

This version looks very good, two minor comments below.

> I also changed the TCONF message in ioctl_ns08.c from "namespace not
> available" to "can't access current directory" since "." isn't a
> namespace, and we are trying to open a file that's not a namespace.

I would have just dropped the check for availability of ".", there is no
point of making sure that "." is a correct directory as it's higly
unlikely that the check will fail.

>  include/lapi/ioctl_ns.h                      | 28 ++++++++++
>  include/tst_safe_macros.h                    |  4 ++
>  lib/tst_safe_macros.c                        | 17 ++++++
>  runtest/syscalls                             |  8 +++
>  testcases/kernel/syscalls/ioctl/.gitignore   |  7 +++
>  testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 65 +++++++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 49 +++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 50 ++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 48 +++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 77 +++++++++++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 78 ++++++++++++++++++++++++++++
>  testcases/kernel/syscalls/ioctl/ioctl_ns08.c | 57 ++++++++++++++++++++
>  12 files changed, 488 insertions(+)
>  create mode 100644 include/lapi/ioctl_ns.h
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c
>  create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns08.c

Can we please split this patch and add the safe macro in a separate
patch?

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v4 1/2] include/SAFE_UNSHARE() macro added
  2019-03-26 19:20         ` Cyril Hrubis
@ 2019-03-28 20:22           ` Federico Bonfiglio
  2019-04-03 15:19             ` Cyril Hrubis
  2019-03-28 20:22           ` [LTP] [PATCH v4 2/2] Test ioctl syscall for NS_GET_* requests Federico Bonfiglio
  1 sibling, 1 reply; 16+ messages in thread
From: Federico Bonfiglio @ 2019-03-28 20:22 UTC (permalink / raw)
  To: ltp

---
Hi Cyril, thanks again for your review. Here the updated patches, I removed the "." check and split them.
I left the include/lapi/ioctl_ns.h in the testcases patch since it doesn't have to do with SAFE_UNSHARE.
However let me know if it belongs here instead

 include/tst_safe_macros.h |  4 ++++
 lib/tst_safe_macros.c     | 17 +++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index 5e85abc9c..04aedb39a 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -526,4 +526,8 @@ int safe_personality(const char *filename, unsigned int lineno,
 	}							\
 	} while (0)
 
+void safe_unshare(const char *file, const int lineno, int flags);
+#define SAFE_UNSHARE(flags) safe_unshare(__FILE__, __LINE__, (flags))
+
+
 #endif /* SAFE_MACROS_H__ */
diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c
index c375030a4..9480ca910 100644
--- a/lib/tst_safe_macros.c
+++ b/lib/tst_safe_macros.c
@@ -18,6 +18,7 @@
 #define _GNU_SOURCE
 #include <unistd.h>
 #include <errno.h>
+#include <sched.h>
 #include "config.h"
 #ifdef HAVE_SYS_FANOTIFY_H
 # include <sys/fanotify.h>
@@ -197,3 +198,19 @@ int safe_chroot(const char *file, const int lineno, const char *path)
 
 	return rval;
 }
+
+void safe_unshare(const char *file, const int lineno, int flags)
+{
+	int res;
+
+	res = unshare(flags);
+	if (res == -1) {
+		if (errno == EINVAL) {
+			tst_brk_(file, lineno, TCONF | TERRNO,
+				 "unshare(%d) unsupported", flags);
+		} else {
+			tst_brk_(file, lineno, TBROK | TERRNO,
+				 "unshare(%d) unsupported", flags);
+		}
+	}
+}
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v4 2/2] Test ioctl syscall for NS_GET_* requests
  2019-03-26 19:20         ` Cyril Hrubis
  2019-03-28 20:22           ` [LTP] [PATCH v4 1/2] include/SAFE_UNSHARE() macro added Federico Bonfiglio
@ 2019-03-28 20:22           ` Federico Bonfiglio
  2019-04-03 15:22             ` Cyril Hrubis
  1 sibling, 1 reply; 16+ messages in thread
From: Federico Bonfiglio @ 2019-03-28 20:22 UTC (permalink / raw)
  To: ltp

---
 include/lapi/ioctl_ns.h                      | 28 ++++++++++
 runtest/syscalls                             |  8 +++
 testcases/kernel/syscalls/ioctl/.gitignore   |  7 +++
 testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 65 +++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 49 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 50 ++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 48 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 77 +++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 78 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns08.c | 48 +++++++++++++++++
 10 files changed, 458 insertions(+)
 create mode 100644 include/lapi/ioctl_ns.h
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns08.c

diff --git a/include/lapi/ioctl_ns.h b/include/lapi/ioctl_ns.h
new file mode 100644
index 000000000..2fb4f4cfb
--- /dev/null
+++ b/include/lapi/ioctl_ns.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+#ifndef IOCTL_NS_H__
+#define IOCTL_NS_H__
+
+#include <asm-generic/ioctl.h>
+
+#ifndef NSIO
+#define NSIO	0xb7
+#endif
+#ifndef NS_GET_PARENT
+#define NS_GET_PARENT		_IO(NSIO, 0x2)
+#endif
+#ifndef NS_GET_OWNER_UID
+#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
+#endif
+#ifndef NS_GET_USERNS
+#define NS_GET_USERNS		_IO(NSIO, 0x1)
+#endif
+#ifndef NS_GET_NSTYPE
+#define NS_GET_NSTYPE		_IO(NSIO, 0x3)
+#endif
+
+
+#endif /* IOCTL_NS_H__ */
diff --git a/runtest/syscalls b/runtest/syscalls
index cf8189ebd..58df02bf1 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -504,6 +504,14 @@ ioctl06      ioctl06
 ioctl07      ioctl07
 ioctl08      ioctl08
 
+ioctl_ns01 ioctl_ns01
+ioctl_ns02 ioctl_ns02
+ioctl_ns04 ioctl_ns04
+ioctl_ns05 ioctl_ns05
+ioctl_ns06 ioctl_ns06
+ioctl_ns07 ioctl_ns07
+ioctl_ns08 ioctl_ns08
+
 inotify_init1_01 inotify_init1_01
 inotify_init1_02 inotify_init1_02
 
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 4d480a0ed..53a2d7b7b 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -6,3 +6,10 @@
 /ioctl06
 /ioctl07
 /ioctl08
+/ioctl_ns01
+/ioctl_ns02
+/ioctl_ns04
+/ioctl_ns05
+/ioctl_ns06
+/ioctl_ns07
+/ioctl_ns08
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
new file mode 100644
index 000000000..340cb315f
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Parent process tries to get parent of initial namespace, which should
+ * fail with EPERM because it has no parent.
+ *
+ * Child process has a new pid namespace, which should make the call fail
+ * with EPERM error.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/pid", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void test_ns_get_parent(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_PARENT fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static void run(void)
+{
+	test_ns_get_parent();
+	SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0)
+		test_ns_get_parent();
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
new file mode 100644
index 000000000..4f5cb1427
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Tries to get namespace parent for UTS namespace, which
+ * should make the call fail with EINVAL, being a nonhierarchical
+ * namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/uts", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_PARENT fails with EINVAL");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
new file mode 100644
index 000000000..2e19cff3a
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_OWNER_UID request.
+ *
+ * Calls ioctl for a UTS namespace, which isn't a user namespace.
+ * This should make the call fail with EINVAL.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/uts", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, owner_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	uid_t uid;
+
+	owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid);
+	if (owner_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.11",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
new file mode 100644
index 000000000..b9181cb3d
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * Owning user namespace of process calling ioctl is out of scope,
+ * which should make the call fail with EPERM.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/user", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_USERNS);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_USERNS fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
new file mode 100644
index 000000000..ae377b095
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * After the call to unshare with the CLONE_NEWPID flag,
+ * next new child is created in a new pid namespace. That's checked by
+ * comparing its /proc/self/ns/pid symlink and the parent's one.
+ * Also child thinks its pid is 1.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/pid", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	SAFE_UNSHARE(CLONE_NEWPID);
+
+	pid_t pid = SAFE_FORK();
+
+	if (pid == 0) {
+		if (getpid() != 1)
+			tst_res(TFAIL, "child should think its pid is 1");
+		else
+			tst_res(TPASS, "child thinks its pid is 1");
+		TST_CHECKPOINT_WAIT(0);
+	} else {
+		char child_namespace[20];
+		int my_fd, child_fd, parent_fd;
+
+		sprintf(child_namespace, "/proc/%i/ns/pid", pid);
+		my_fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+		child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+		parent_fd = SAFE_IOCTL(child_fd, NS_GET_PARENT);
+
+		struct stat my_stat, child_stat, parent_stat;
+
+		SAFE_FSTAT(my_fd, &my_stat);
+		SAFE_FSTAT(child_fd, &child_stat);
+		SAFE_FSTAT(parent_fd, &parent_stat);
+		if (my_stat.st_ino != parent_stat.st_ino)
+			tst_res(TFAIL, "parents have different inodes");
+		else if (parent_stat.st_ino == child_stat.st_ino)
+			tst_res(TFAIL, "child and parent have same inode");
+		else
+			tst_res(TPASS, "child and parent are consistent");
+		SAFE_CLOSE(my_fd);
+		SAFE_CLOSE(child_fd);
+		SAFE_CLOSE(parent_fd);
+		TST_CHECKPOINT_WAKE(0);
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
new file mode 100644
index 000000000..f077a3bb7
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * After the call to clone with the CLONE_NEWUSER flag,
+ * child is created in a new user namespace. That's checked by
+ * comparing its /proc/self/ns/user symlink and the parent's one,
+ * which should be different.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/user", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static int child(void *arg)
+{
+	TST_CHECKPOINT_WAIT(0);
+	return 0;
+}
+
+static void run(void)
+{
+	pid_t pid = ltp_clone(CLONE_NEWUSER, &child, 0,
+		STACK_SIZE, child_stack);
+	char child_namespace[20];
+
+	sprintf(child_namespace, "/proc/%i/ns/user", pid);
+	int my_fd, child_fd, parent_fd;
+
+	my_fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+	parent_fd = SAFE_IOCTL(child_fd, NS_GET_USERNS);
+
+	struct stat my_stat, child_stat, parent_stat;
+
+	SAFE_FSTAT(my_fd, &my_stat);
+	SAFE_FSTAT(child_fd, &child_stat);
+	SAFE_FSTAT(parent_fd, &parent_stat);
+	if (my_stat.st_ino != parent_stat.st_ino)
+		tst_res(TFAIL, "parents have different inodes");
+	else if (parent_stat.st_ino == child_stat.st_ino)
+		tst_res(TFAIL, "child and parent have same inode");
+	else
+		tst_res(TPASS, "child and parent are consistent");
+	SAFE_CLOSE(my_fd);
+	SAFE_CLOSE(parent_fd);
+	SAFE_CLOSE(child_fd);
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns08.c b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
new file mode 100644
index 000000000..06cf70a17
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns08.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_* request for file descriptors
+ * that aren't namespaces.
+ *
+ * Calling ioctl with test directory's file descriptor
+ * should make the call fail with ENOTTY.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static int requests[] = {NS_GET_PARENT, NS_GET_USERNS,
+	NS_GET_OWNER_UID, NS_GET_NSTYPE};
+
+static void test_request(unsigned int n)
+{
+	int request = requests[n];
+	int fd, ns_fd;
+
+	fd = SAFE_OPEN(".", O_RDONLY);
+	ns_fd = ioctl(fd, request);
+	if (ns_fd == -1) {
+		if (errno == ENOTTY)
+			tst_res(TPASS, "request failed with ENOTTY");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		tst_res(TFAIL, "request success for invalid fd");
+		SAFE_CLOSE(ns_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(requests),
+	.test = test_request,
+	.needs_tmpdir = 1,
+	.min_kver = "4.11"
+};
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v4 1/2] include/SAFE_UNSHARE() macro added
  2019-03-28 20:22           ` [LTP] [PATCH v4 1/2] include/SAFE_UNSHARE() macro added Federico Bonfiglio
@ 2019-04-03 15:19             ` Cyril Hrubis
  0 siblings, 0 replies; 16+ messages in thread
From: Cyril Hrubis @ 2019-04-03 15:19 UTC (permalink / raw)
  To: ltp

Hi!
Pushed with minor changes:

* Added missing Signed-off-by: lines to the patch description

* Changed the tst_brk_() message on failure
  (both were saying unsupported which is not true)

Thanks.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v4 2/2] Test ioctl syscall for NS_GET_* requests
  2019-03-28 20:22           ` [LTP] [PATCH v4 2/2] Test ioctl syscall for NS_GET_* requests Federico Bonfiglio
@ 2019-04-03 15:22             ` Cyril Hrubis
  2019-04-11 19:25               ` [LTP] [PATCH v5] " Federico Bonfiglio
  0 siblings, 1 reply; 16+ messages in thread
From: Cyril Hrubis @ 2019-04-03 15:22 UTC (permalink / raw)
  To: ltp

Hi!
This is nearly done, the only outstanding problem (minus the missing
Signed-off-by line) is that tests number 01 and 06 does not work with
-i 2 option that causes the test to be executed more than once. The
obvious fix would be moving the unshare call to the test setup()
function instead.

Also why have you skipped test 03? We do have 02 and then 04.

Other than that the rest is done and ready.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v5] Test ioctl syscall for NS_GET_* requests
  2019-04-03 15:22             ` Cyril Hrubis
@ 2019-04-11 19:25               ` Federico Bonfiglio
  2019-04-12 14:33                 ` Cyril Hrubis
  0 siblings, 1 reply; 16+ messages in thread
From: Federico Bonfiglio @ 2019-04-11 19:25 UTC (permalink / raw)
  To: ltp

Signed-off-by: Federico Bonfiglio <fedebonfi95@gmail.com>
---
Hi Cyril,

the missing test number 3 resulted from merging two other tests in a previous patch version. I numbered subsequent tests in this patch to fill the gap.

About the unshare call, I removed it entirely since placing it in the setup() caused: 

ioctl_ns05.c:35: BROK: fork() failed: ENOMEM

This seems to originate from the fact that unsharing in setup didn't make the testing framework reap forked processes correctly, since every forked test run after the setup thinks to have pid 0. So when it checks if the pid is different from the initial pid (also 0) it finds them equal. This is of course as I understood the problem, and being a beginner with the framework I'm not entirely sure.

To solve the issue I did what I was doing in ioctl_ns06.c (ex number 7), directly calling clone() and not unshare() and then fork().

Let me know if you like this solution, and thanks again

 include/lapi/ioctl_ns.h                      | 28 ++++++++++
 runtest/syscalls                             |  8 +++
 testcases/kernel/syscalls/ioctl/.gitignore   |  7 +++
 testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 72 ++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 49 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns03.c | 50 +++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 48 ++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 82 ++++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 78 ++++++++++++++++++++++++++
 testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 48 ++++++++++++++++
 10 files changed, 470 insertions(+)
 create mode 100644 include/lapi/ioctl_ns.h
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns01.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns02.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns03.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns04.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns05.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns06.c
 create mode 100644 testcases/kernel/syscalls/ioctl/ioctl_ns07.c

diff --git a/include/lapi/ioctl_ns.h b/include/lapi/ioctl_ns.h
new file mode 100644
index 000000000..2fb4f4cfb
--- /dev/null
+++ b/include/lapi/ioctl_ns.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+#ifndef IOCTL_NS_H__
+#define IOCTL_NS_H__
+
+#include <asm-generic/ioctl.h>
+
+#ifndef NSIO
+#define NSIO	0xb7
+#endif
+#ifndef NS_GET_PARENT
+#define NS_GET_PARENT		_IO(NSIO, 0x2)
+#endif
+#ifndef NS_GET_OWNER_UID
+#define NS_GET_OWNER_UID	_IO(NSIO, 0x4)
+#endif
+#ifndef NS_GET_USERNS
+#define NS_GET_USERNS		_IO(NSIO, 0x1)
+#endif
+#ifndef NS_GET_NSTYPE
+#define NS_GET_NSTYPE		_IO(NSIO, 0x3)
+#endif
+
+
+#endif /* IOCTL_NS_H__ */
diff --git a/runtest/syscalls b/runtest/syscalls
index e8fe9785a..5267c4d93 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -504,6 +504,14 @@ ioctl06      ioctl06
 ioctl07      ioctl07
 ioctl08      ioctl08
 
+ioctl_ns01 ioctl_ns01
+ioctl_ns02 ioctl_ns02
+ioctl_ns03 ioctl_ns03
+ioctl_ns04 ioctl_ns04
+ioctl_ns05 ioctl_ns05
+ioctl_ns06 ioctl_ns06
+ioctl_ns07 ioctl_ns07
+
 inotify_init1_01 inotify_init1_01
 inotify_init1_02 inotify_init1_02
 
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 4d480a0ed..2551ffb7f 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -6,3 +6,10 @@
 /ioctl06
 /ioctl07
 /ioctl08
+/ioctl_ns01
+/ioctl_ns02
+/ioctl_ns03
+/ioctl_ns04
+/ioctl_ns05
+/ioctl_ns06
+/ioctl_ns07
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
new file mode 100644
index 000000000..59b215f2b
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Parent process tries to get parent of initial namespace, which should
+ * fail with EPERM because it has no parent.
+ *
+ * Child process has a new pid namespace, which should make the call fail
+ * with EPERM error.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/pid", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void test_ns_get_parent(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_PARENT fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static int child(void *arg)
+{
+	test_ns_get_parent();
+	return 0;
+}
+
+static void run(void)
+{
+	test_ns_get_parent();
+
+	ltp_clone(CLONE_NEWPID, &child, 0,
+		STACK_SIZE, child_stack);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
new file mode 100644
index 000000000..4f5cb1427
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * Tries to get namespace parent for UTS namespace, which
+ * should make the call fail with EINVAL, being a nonhierarchical
+ * namespace.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/uts", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_PARENT);
+	if (parent_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_PARENT fails with EINVAL");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns03.c b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c
new file mode 100644
index 000000000..2e19cff3a
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_OWNER_UID request.
+ *
+ * Calls ioctl for a UTS namespace, which isn't a user namespace.
+ * This should make the call fail with EINVAL.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/uts", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, owner_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/uts", O_RDONLY);
+	uid_t uid;
+
+	owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid);
+	if (owner_fd == -1) {
+		if (errno == EINVAL)
+			tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.11",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
new file mode 100644
index 000000000..b9181cb3d
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * Owning user namespace of process calling ioctl is out of scope,
+ * which should make the call fail with EPERM.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/user", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static void run(void)
+{
+	int fd, parent_fd;
+
+	fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	parent_fd = ioctl(fd, NS_GET_USERNS);
+	if (parent_fd == -1) {
+		if (errno == EPERM)
+			tst_res(TPASS, "NS_GET_USERNS fails with EPERM");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		SAFE_CLOSE(fd);
+		tst_res(TFAIL, "call to ioctl succeded");
+	}
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
new file mode 100644
index 000000000..5d89c03b0
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_PARENT request.
+ *
+ * After the call to unshare with the CLONE_NEWPID flag,
+ * next new child is created in a new pid namespace. That's checked by
+ * comparing its /proc/self/ns/pid symlink and the parent's one.
+ * Also child thinks its pid is 1.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/pid", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static int child(void *arg)
+{
+	if (getpid() != 1)
+		tst_res(TFAIL, "child should think its pid is 1");
+	else
+		tst_res(TPASS, "child thinks its pid is 1");
+	TST_CHECKPOINT_WAIT(0);
+	return 0;
+}
+
+static void run(void)
+{
+	pid_t pid = ltp_clone(CLONE_NEWPID, &child, 0,
+		STACK_SIZE, child_stack);
+
+	char child_namespace[20];
+	int my_fd, child_fd, parent_fd;
+
+	sprintf(child_namespace, "/proc/%i/ns/pid", pid);
+	my_fd = SAFE_OPEN("/proc/self/ns/pid", O_RDONLY);
+	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+	parent_fd = SAFE_IOCTL(child_fd, NS_GET_PARENT);
+
+	struct stat my_stat, child_stat, parent_stat;
+
+	SAFE_FSTAT(my_fd, &my_stat);
+	SAFE_FSTAT(child_fd, &child_stat);
+	SAFE_FSTAT(parent_fd, &parent_stat);
+	if (my_stat.st_ino != parent_stat.st_ino)
+		tst_res(TFAIL, "parents have different inodes");
+	else if (parent_stat.st_ino == child_stat.st_ino)
+		tst_res(TFAIL, "child and parent have same inode");
+	else
+		tst_res(TPASS, "child and parent are consistent");
+	SAFE_CLOSE(my_fd);
+	SAFE_CLOSE(child_fd);
+	SAFE_CLOSE(parent_fd);
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
new file mode 100644
index 000000000..f077a3bb7
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_USERNS request.
+ *
+ * After the call to clone with the CLONE_NEWUSER flag,
+ * child is created in a new user namespace. That's checked by
+ * comparing its /proc/self/ns/user symlink and the parent's one,
+ * which should be different.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <sched.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+#define STACK_SIZE (1024 * 1024)
+
+static char child_stack[STACK_SIZE];
+
+static void setup(void)
+{
+	int exists = access("/proc/self/ns/user", F_OK);
+
+	if (exists < 0)
+		tst_res(TCONF, "namespace not available");
+}
+
+static int child(void *arg)
+{
+	TST_CHECKPOINT_WAIT(0);
+	return 0;
+}
+
+static void run(void)
+{
+	pid_t pid = ltp_clone(CLONE_NEWUSER, &child, 0,
+		STACK_SIZE, child_stack);
+	char child_namespace[20];
+
+	sprintf(child_namespace, "/proc/%i/ns/user", pid);
+	int my_fd, child_fd, parent_fd;
+
+	my_fd = SAFE_OPEN("/proc/self/ns/user", O_RDONLY);
+	child_fd = SAFE_OPEN(child_namespace, O_RDONLY);
+	parent_fd = SAFE_IOCTL(child_fd, NS_GET_USERNS);
+
+	struct stat my_stat, child_stat, parent_stat;
+
+	SAFE_FSTAT(my_fd, &my_stat);
+	SAFE_FSTAT(child_fd, &child_stat);
+	SAFE_FSTAT(parent_fd, &parent_stat);
+	if (my_stat.st_ino != parent_stat.st_ino)
+		tst_res(TFAIL, "parents have different inodes");
+	else if (parent_stat.st_ino == child_stat.st_ino)
+		tst_res(TFAIL, "child and parent have same inode");
+	else
+		tst_res(TPASS, "child and parent are consistent");
+	SAFE_CLOSE(my_fd);
+	SAFE_CLOSE(parent_fd);
+	SAFE_CLOSE(child_fd);
+	TST_CHECKPOINT_WAKE(0);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.forks_child = 1,
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.min_kver = "4.9",
+	.setup = setup
+};
diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
new file mode 100644
index 000000000..06cf70a17
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com
+ */
+
+/*
+ * Test ioctl_ns with NS_GET_* request for file descriptors
+ * that aren't namespaces.
+ *
+ * Calling ioctl with test directory's file descriptor
+ * should make the call fail with ENOTTY.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include "tst_test.h"
+#include "lapi/ioctl_ns.h"
+
+static int requests[] = {NS_GET_PARENT, NS_GET_USERNS,
+	NS_GET_OWNER_UID, NS_GET_NSTYPE};
+
+static void test_request(unsigned int n)
+{
+	int request = requests[n];
+	int fd, ns_fd;
+
+	fd = SAFE_OPEN(".", O_RDONLY);
+	ns_fd = ioctl(fd, request);
+	if (ns_fd == -1) {
+		if (errno == ENOTTY)
+			tst_res(TPASS, "request failed with ENOTTY");
+		else
+			tst_res(TFAIL | TERRNO, "unexpected ioctl error");
+	} else {
+		tst_res(TFAIL, "request success for invalid fd");
+		SAFE_CLOSE(ns_fd);
+	}
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.tcnt = ARRAY_SIZE(requests),
+	.test = test_request,
+	.needs_tmpdir = 1,
+	.min_kver = "4.11"
+};
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] [PATCH v5] Test ioctl syscall for NS_GET_* requests
  2019-04-11 19:25               ` [LTP] [PATCH v5] " Federico Bonfiglio
@ 2019-04-12 14:33                 ` Cyril Hrubis
  2019-05-06 10:14                   ` [LTP] NS_* ioctl commands fail in 32bit compat mode (-m32) Richard Palethorpe
  0 siblings, 1 reply; 16+ messages in thread
From: Cyril Hrubis @ 2019-04-12 14:33 UTC (permalink / raw)
  To: ltp

Hi!
> About the unshare call, I removed it entirely since placing it in the setup() caused: 
> 
> ioctl_ns05.c:35: BROK: fork() failed: ENOMEM
> 
> This seems to originate from the fact that unsharing in setup didn't make the testing framework reap forked processes correctly, since every forked test run after the setup thinks to have pid 0. So when it checks if the pid is different from the initial pid (also 0) it finds them equal. This is of course as I understood the problem, and being a beginner with the framework I'm not entirely sure.
> 
> To solve the issue I did what I was doing in ioctl_ns06.c (ex number 7), directly calling clone() and not unshare() and then fork().
> 
> Let me know if you like this solution, and thanks again

Applied with a minor change, thanks.

The comment in ioctl_ns05.c was speaking about unshare so I changed it to:

diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
index 5d89c03b0..add6980bb 100644
--- a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
+++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c
@@ -6,10 +6,9 @@
 /*
  * Test ioctl_ns with NS_GET_PARENT request.
  *
- * After the call to unshare with the CLONE_NEWPID flag,
- * next new child is created in a new pid namespace. That's checked by
- * comparing its /proc/self/ns/pid symlink and the parent's one.
- * Also child thinks its pid is 1.
+ * Child cloned with the CLONE_NEWPID flag is created in a new pid namespace.
+ * That's checked by comparing its /proc/self/ns/pid symlink and the parent's
+ * one. Also child thinks its pid is 1.
  *
  */
 #define _GNU_SOURCE


-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [LTP] NS_* ioctl commands fail in 32bit compat mode (-m32)
  2019-04-12 14:33                 ` Cyril Hrubis
@ 2019-05-06 10:14                   ` Richard Palethorpe
  2019-05-06 10:39                     ` Richard Palethorpe
  0 siblings, 1 reply; 16+ messages in thread
From: Richard Palethorpe @ 2019-05-06 10:14 UTC (permalink / raw)
  To: ltp


Hello Federico,

All the tests fail with something similar to:
ioctl_ns01.c:45: FAIL: unexpected ioctl error: ENOTTY

when compiled with the -m32 flag on at least SUSE kernel 4.20 and
4.12.

Do you know if this feature is expected to work in 32bit compat mode?
Maybe the size of the arguments should be different when using 32bit mode?

--
Thank you,
Richard.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] NS_* ioctl commands fail in 32bit compat mode (-m32)
  2019-05-06 10:14                   ` [LTP] NS_* ioctl commands fail in 32bit compat mode (-m32) Richard Palethorpe
@ 2019-05-06 10:39                     ` Richard Palethorpe
  2019-05-13  9:00                       ` Cyril Hrubis
  0 siblings, 1 reply; 16+ messages in thread
From: Richard Palethorpe @ 2019-05-06 10:39 UTC (permalink / raw)
  To: ltp


Richard Palethorpe <rpalethorpe@suse.de> writes:

> Hello Federico,
>
> All the tests fail with something similar to:
> ioctl_ns01.c:45: FAIL: unexpected ioctl error: ENOTTY
>
> when compiled with the -m32 flag on at least SUSE kernel 4.20 and
> 4.12.
>
> Do you know if this feature is expected to work in 32bit compat mode?
> Maybe the size of the arguments should be different when using 32bit mode?

FYI, it seems the size of the argument and value are the same on both 32bit
and 64bit mode in user space.

-- 
Thank you,
Richard.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [LTP] NS_* ioctl commands fail in 32bit compat mode (-m32)
  2019-05-06 10:39                     ` Richard Palethorpe
@ 2019-05-13  9:00                       ` Cyril Hrubis
  0 siblings, 0 replies; 16+ messages in thread
From: Cyril Hrubis @ 2019-05-13  9:00 UTC (permalink / raw)
  To: ltp

Hi!
> > All the tests fail with something similar to:
> > ioctl_ns01.c:45: FAIL: unexpected ioctl error: ENOTTY
> >
> > when compiled with the -m32 flag on at least SUSE kernel 4.20 and
> > 4.12.
> >
> > Do you know if this feature is expected to work in 32bit compat mode?
> > Maybe the size of the arguments should be different when using 32bit mode?
> 
> FYI, it seems the size of the argument and value are the same on both 32bit
> and 64bit mode in user space.

Most likely these calls were not implemented for 32bit compat mode
because nobody needs them there. I guess that the best solution would be
just report TCONF on ENOTTY.

Also it would be nice to have this sorted before the upcomming release.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2019-05-13  9:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-24 20:29 [LTP] [PATCH v1] Test ioctl syscall for NS_GET_* requests YourName
2019-03-04 16:16 ` Cyril Hrubis
2019-03-11  7:25   ` [LTP] [PATCH v2] " Federico Bonfiglio
2019-03-18 14:22     ` Cyril Hrubis
2019-03-18 15:30     ` Cyril Hrubis
2019-03-19 18:09       ` [LTP] [PATCH v3] " Federico Bonfiglio
2019-03-26 19:20         ` Cyril Hrubis
2019-03-28 20:22           ` [LTP] [PATCH v4 1/2] include/SAFE_UNSHARE() macro added Federico Bonfiglio
2019-04-03 15:19             ` Cyril Hrubis
2019-03-28 20:22           ` [LTP] [PATCH v4 2/2] Test ioctl syscall for NS_GET_* requests Federico Bonfiglio
2019-04-03 15:22             ` Cyril Hrubis
2019-04-11 19:25               ` [LTP] [PATCH v5] " Federico Bonfiglio
2019-04-12 14:33                 ` Cyril Hrubis
2019-05-06 10:14                   ` [LTP] NS_* ioctl commands fail in 32bit compat mode (-m32) Richard Palethorpe
2019-05-06 10:39                     ` Richard Palethorpe
2019-05-13  9:00                       ` Cyril Hrubis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.