File Index
Files and directories
Sign in
FILE

pidfd_bind_mount.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/pidfd/pidfd_bind_mount.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2// Copyright (c) 2024 Christian Brauner <brauner@kernel.org>
  3
  4#define _GNU_SOURCE
  5#include <fcntl.h>
  6#include <limits.h>
  7#include <sched.h>
  8#include <stdio.h>
  9#include <string.h>
 10#include <linux/fs.h>
 11#include <sys/ioctl.h>
 12#include <sys/stat.h>
 13#include <sys/mount.h>
 14#include <unistd.h>
 15
 16#include "pidfd.h"
 17#include "kselftest_harness.h"
 18#include "../filesystems/wrappers.h"
 19
 20FIXTURE(pidfd_bind_mount) {
 21	char template[PATH_MAX];
 22	int fd_tmp;
 23	int pidfd;
 24	struct stat st1;
 25	struct stat st2;
 26	__u32 gen1;
 27	__u32 gen2;
 28	bool must_unmount;
 29};
 30
 31FIXTURE_SETUP(pidfd_bind_mount)
 32{
 33	self->fd_tmp = -EBADF;
 34	self->must_unmount = false;
 35	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
 36	ASSERT_LE(snprintf(self->template, PATH_MAX, "%s", P_tmpdir "/pidfd_bind_mount_XXXXXX"), PATH_MAX);
 37	self->fd_tmp = mkstemp(self->template);
 38	ASSERT_GE(self->fd_tmp, 0);
 39	self->pidfd = sys_pidfd_open(getpid(), 0);
 40	ASSERT_GE(self->pidfd, 0);
 41	ASSERT_GE(fstat(self->pidfd, &self->st1), 0);
 42	ASSERT_EQ(ioctl(self->pidfd, FS_IOC_GETVERSION, &self->gen1), 0);
 43}
 44
 45FIXTURE_TEARDOWN(pidfd_bind_mount)
 46{
 47	ASSERT_EQ(close(self->fd_tmp), 0);
 48	if (self->must_unmount)
 49		ASSERT_EQ(umount2(self->template, 0), 0);
 50	ASSERT_EQ(unlink(self->template), 0);
 51}
 52
 53/*
 54 * Test that a detached mount can be created for a pidfd and then
 55 * attached to the filesystem hierarchy.
 56 */
 57TEST_F(pidfd_bind_mount, bind_mount)
 58{
 59	int fd_tree;
 60
 61	fd_tree = sys_open_tree(self->pidfd, "", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH);
 62	ASSERT_GE(fd_tree, 0);
 63
 64	ASSERT_EQ(move_mount(fd_tree, "", self->fd_tmp, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
 65	self->must_unmount = true;
 66
 67	ASSERT_EQ(close(fd_tree), 0);
 68}
 69
 70/* Test that a pidfd can be reopened through procfs. */
 71TEST_F(pidfd_bind_mount, reopen)
 72{
 73	int pidfd;
 74	char proc_path[PATH_MAX];
 75
 76	sprintf(proc_path, "/proc/self/fd/%d", self->pidfd);
 77	pidfd = open(proc_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
 78	ASSERT_GE(pidfd, 0);
 79
 80	ASSERT_GE(fstat(self->pidfd, &self->st2), 0);
 81	ASSERT_EQ(ioctl(self->pidfd, FS_IOC_GETVERSION, &self->gen2), 0);
 82
 83	ASSERT_TRUE(self->st1.st_dev == self->st2.st_dev && self->st1.st_ino == self->st2.st_ino);
 84	ASSERT_TRUE(self->gen1 == self->gen2);
 85
 86	ASSERT_EQ(close(pidfd), 0);
 87}
 88
 89/*
 90 * Test that a detached mount can be created for a pidfd and then
 91 * attached to the filesystem hierarchy and reopened.
 92 */
 93TEST_F(pidfd_bind_mount, bind_mount_reopen)
 94{
 95	int fd_tree, fd_pidfd_mnt;
 96
 97	fd_tree = sys_open_tree(self->pidfd, "", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH);
 98	ASSERT_GE(fd_tree, 0);
 99
100	ASSERT_EQ(move_mount(fd_tree, "", self->fd_tmp, "", MOVE_MOUNT_F_EMPTY_PATH | MOVE_MOUNT_T_EMPTY_PATH), 0);
101	self->must_unmount = true;
102
103	fd_pidfd_mnt = openat(-EBADF, self->template, O_RDONLY | O_NOCTTY | O_CLOEXEC);
104	ASSERT_GE(fd_pidfd_mnt, 0);
105
106	ASSERT_GE(fstat(fd_tree, &self->st2), 0);
107	ASSERT_EQ(ioctl(fd_pidfd_mnt, FS_IOC_GETVERSION, &self->gen2), 0);
108
109	ASSERT_TRUE(self->st1.st_dev == self->st2.st_dev && self->st1.st_ino == self->st2.st_ino);
110	ASSERT_TRUE(self->gen1 == self->gen2);
111
112	ASSERT_EQ(close(fd_tree), 0);
113	ASSERT_EQ(close(fd_pidfd_mnt), 0);
114}
115
116TEST_HARNESS_MAIN
~/ Read-only file preview.