[LTP] [PATCH v2 1/2] syscalls/pidfd_getfd01: Add basic functional test

Yang Xu xuyang2018.jy@fujitsu.com
Fri Feb 18 11:12:11 CET 2022


The pidfd_getfd() system call allocates a new file descriptor in the calling process.
This new file descriptor is a duplicate of an existing file descriptor, targetfd, in
the process referred to by the PID file descriptor pidfd.

pidfd_getfd was introduced since kernel 5.6 and pidfd_open was introduced since kernel 5.3.
pidfd_getfd is not similar to pidfd_send_signal because it didn't support fd from
/proc/pid directory. So we must check kernel whether support pidfd_open because some linux
distribution backports pidfd_getfd but not backport pidfd_open.

Here we check whether the newfd set close-on-exce flag and use kcmp to check the two fds whether
point to the same open file instead of using fstat to check.

Reviewed-by: Petr Vorel <pvorel@suse.cz>
Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
 runtest/syscalls                              |   2 +
 .../kernel/syscalls/pidfd_getfd/.gitignore    |   1 +
 .../kernel/syscalls/pidfd_getfd/Makefile      |   6 +
 .../syscalls/pidfd_getfd/pidfd_getfd01.c      | 118 ++++++++++++++++++
 4 files changed, 127 insertions(+)
 create mode 100644 testcases/kernel/syscalls/pidfd_getfd/.gitignore
 create mode 100644 testcases/kernel/syscalls/pidfd_getfd/Makefile
 create mode 100644 testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c

diff --git a/runtest/syscalls b/runtest/syscalls
index ce6f89f88..6155712cc 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -951,6 +951,8 @@ pause03 pause03
 personality01 personality01
 personality02 personality02
 
+pidfd_getfd01 pidfd_getfd01
+
 pidfd_open01 pidfd_open01
 pidfd_open02 pidfd_open02
 pidfd_open03 pidfd_open03
diff --git a/testcases/kernel/syscalls/pidfd_getfd/.gitignore b/testcases/kernel/syscalls/pidfd_getfd/.gitignore
new file mode 100644
index 000000000..9328942ac
--- /dev/null
+++ b/testcases/kernel/syscalls/pidfd_getfd/.gitignore
@@ -0,0 +1 @@
+/pidfd_getfd01
diff --git a/testcases/kernel/syscalls/pidfd_getfd/Makefile b/testcases/kernel/syscalls/pidfd_getfd/Makefile
new file mode 100644
index 000000000..5ea7d67db
--- /dev/null
+++ b/testcases/kernel/syscalls/pidfd_getfd/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c b/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c
new file mode 100644
index 000000000..a8d0c9143
--- /dev/null
+++ b/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
+ * Author: Yang Xu <xuyang2018.jy@fujitsu.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Basic pidfd_getfd() test:
+ *
+ * - the close-on-exec flag is set on the file descriptor returned by
+ *   pidfd_getfd
+ * - use kcmp to check whether a file descriptor idx1 in the process pid1
+ *   refers to the same open file description as file descriptor idx2 in
+ *   the process pid2
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "tst_test.h"
+#include "lapi/pidfd_open.h"
+#include "lapi/pidfd_getfd.h"
+#include "lapi/kcmp.h"
+#include "tst_safe_macros.h"
+
+#define TESTFILE "testfile"
+
+static int fds[2] = {-1, -1};
+static int pidfd = -1;
+
+static void do_child(void)
+{
+	int fd;
+
+	SAFE_CLOSE(fds[0]);
+	fd = SAFE_CREAT(TESTFILE, 0644);
+	SAFE_WRITE(1, fds[1], &fd, sizeof(fd));
+	TST_CHECKPOINT_WAIT(0);
+	SAFE_CLOSE(fd);
+	SAFE_CLOSE(fds[1]);
+	exit(0);
+}
+
+static void run(void)
+{
+	int flag, pid, targetfd, remotefd;
+
+	SAFE_PIPE(fds);
+	pid = SAFE_FORK();
+	if (!pid)
+		do_child();
+
+	SAFE_CLOSE(fds[1]);
+	TST_PROCESS_STATE_WAIT(pid, 'S', 0);
+
+	TST_EXP_FD_SILENT(pidfd_open(pid, 0), "pidfd_open(pid, 0)");
+	pidfd = TST_RET;
+	SAFE_READ(1, fds[0], &targetfd, sizeof(targetfd));
+	TST_EXP_FD_SILENT(pidfd_getfd(pidfd, targetfd, 0),
+		"pidfd_getfd(%d, %d , 0)", pidfd, targetfd);
+
+	remotefd = TST_RET;
+	flag = SAFE_FCNTL(remotefd, F_GETFD);
+	if (!(flag & FD_CLOEXEC))
+		tst_res(TFAIL, "pidfd_getfd() didn't set close-on-exec flag");
+
+	TEST(kcmp(getpid(), pid, KCMP_FILE, remotefd, targetfd));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "kcmp failed unexpectedly");
+		goto free;
+	}
+	if (TST_RET < 0 || TST_RET > 3) {
+		tst_res(TFAIL, "kcmp invalid returns value(%d)", (int)TST_RET);
+		goto free;
+	}
+	if (TST_RET != 0) {
+		tst_res(TFAIL, "kcmp returns unexpected value(%d) instead of 0",
+				(int)TST_RET);
+		goto free;
+	}
+
+	tst_res(TPASS, "pidfd_getfd(%d, %d, 0) passed", pidfd, targetfd);
+
+free:
+	TST_CHECKPOINT_WAKE(0);
+	SAFE_CLOSE(remotefd);
+	SAFE_CLOSE(pidfd);
+	SAFE_CLOSE(fds[0]);
+	tst_reap_children();
+}
+
+static void setup(void)
+{
+	pidfd_open_supported();
+	pidfd_getfd_supported();
+}
+
+static void cleanup(void)
+{
+	if (fds[0] > -1)
+		SAFE_CLOSE(fds[0]);
+	if (fds[1] > -1)
+		SAFE_CLOSE(fds[1]);
+	if (pidfd > -1)
+		SAFE_CLOSE(pidfd);
+}
+
+static struct tst_test test = {
+	.needs_root = 1,
+	.needs_checkpoints = 1,
+	.forks_child = 1,
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run,
+};
-- 
2.23.0



More information about the ltp mailing list