summaryrefslogtreecommitdiff
path: root/nsmount.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2023-10-12 19:07:02 +0200
committerAnton Khirnov <anton@khirnov.net>2023-10-12 19:10:07 +0200
commitb877c3546f5e523df641e3d237cde34c31265c51 (patch)
treeb917a5eb899359d0e5a3542dee7a9a16584140e1 /nsmount.c
parentdc52f123745748ee61e894fe36eeca1788fc4ed8 (diff)
targets: remove TargetSSHLXCLVM
It is complex and fragile and has been replaced by idmapping/TargetSSHLVM/strip_mountpoint=True. Also drop nsmount.c, which was to be used with this target.
Diffstat (limited to 'nsmount.c')
-rw-r--r--nsmount.c233
1 files changed, 0 insertions, 233 deletions
diff --git a/nsmount.c b/nsmount.c
deleted file mode 100644
index 9d1533a..0000000
--- a/nsmount.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/**
- * nsmount - mount a block device into a mount/pid namespace
- * Copyright (C) 2019 Anton Khirnov <anton@khirnov.net>
- *
- * nsmount 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 3 of the License, or
- * (at your option) any later version.
- *
- * nsmount 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 nsmount. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#define _XOPEN_SOURCE 700
-#define _GNU_SOURCE
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/mount.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-enum {
- OP_MOUNT,
- OP_UMOUNT,
-};
-
-static void print_usage(int argc, const char * const *argv)
-{
- fprintf(stderr,
- "%s: mount/unmount a block device in a mount/PID namespace\n\n"
- "Usage:\n"
- " %s m <PID> <mountpoint> <blkdev_path> <fstype>\n"
- " %s u <PID> <mountpoint>\n\n"
- " <PID>: PID (in the namespace in which this program is executed)"
- " of the process whose namespaces are to be entered into\n"
- " <mountpoint>: path (in the destination mount namespace) to be mounted"
- " or unmounted\n"
- " <blkdev_path>: path (in the namespace in which this program is executed)"
- " to the block device that shall be mounted\n"
- " <fstype>: type of the filesystem to be mounted\n",
- argv[0], argv[0], argv[0]);
-}
-
-int main(int argc, const char * const *argv)
-{
- char pathbuf[128];
- int blockdev_fd = -1, pidns_fd = -1, mountns_fd = -1;
- const char *blockdev, *mountpoint, *fstype;
- pid_t tgt_pid, child_pid;
- int op;
- int ret;
-
- /* parse the commandline */
- if (argc < 2) {
- print_usage(argc, argv);
- return 1;
- }
-
- if (argv[1][0] == 'm') {
- op = OP_MOUNT;
- if (argc < 6) {
- print_usage(argc, argv);
- return 1;
- }
- } else if (argv[1][0] == 'u') {
- op = OP_UMOUNT;
- if (argc < 4) {
- print_usage(argc, argv);
- return 1;
- }
- } else {
- fprintf(stderr, "Invalid operation: %s\n",
- argv[1]);
- print_usage(argc, argv);
- return 1;
- }
-
- tgt_pid = strtol(argv[2], NULL, 0);
- mountpoint = argv[3];
- if (op == OP_MOUNT) {
- blockdev = argv[4];
- fstype = argv[5];
- }
-
- /* open the files */
- if (op == OP_MOUNT) {
- blockdev_fd = open(blockdev, O_RDONLY);
- if (blockdev_fd == -1) {
- fprintf(stderr, "Error opening %s: %s\n",
- blockdev, strerror(errno));
- return 2;
- }
- }
-
- ret = snprintf(pathbuf, sizeof(pathbuf), "/proc/%d/ns/pid",
- tgt_pid);
- if (ret < 0 || ret >= sizeof(pathbuf)) {
- fprintf(stderr, "Error constructing the PID namespace path\n");
- ret = 2;
- goto finish;
- }
-
- pidns_fd = open(pathbuf, O_RDONLY | O_CLOEXEC);
- if (pidns_fd == -1) {
- fprintf(stderr, "Error opening %s: %s\n",
- pathbuf, strerror(errno));
- ret = 2;
- goto finish;
- }
-
- ret = snprintf(pathbuf, sizeof(pathbuf), "/proc/%d/ns/mnt",
- tgt_pid);
- if (ret < 0 || ret >= sizeof(pathbuf)) {
- fprintf(stderr, "Error constructing the mount namespace path\n");
- ret = 2;
- goto finish;
- }
-
- mountns_fd = open(pathbuf, O_RDONLY | O_CLOEXEC);
- if (mountns_fd == -1) {
- fprintf(stderr, "Error opening %s: %s\n",
- pathbuf, strerror(errno));
- ret = 2;
- goto finish;
- }
-
- /* enter the namespaces */
- ret = setns(pidns_fd, CLONE_NEWPID);
- if (ret == -1) {
- fprintf(stderr, "Error entering the PID namespace: %s\n",
- strerror(errno));
- ret = 3;
- goto finish;
- }
-
- ret = setns(mountns_fd, CLONE_NEWNS);
- if (ret == -1) {
- fprintf(stderr, "Error entering the mount namespace: %s\n",
- strerror(errno));
- ret = 3;
- goto finish;
- }
-
- /* fork to actually enter the PID namespace */
- child_pid = fork();
- if (child_pid == -1) {
- fprintf(stderr, "fork() failed: %s\n",
- strerror(errno));
- ret = 4;
- goto finish;
- }
-
- if (child_pid) {
- /* we are the parent */
- ret = wait(NULL);
- if (ret == -1) {
- fprintf(stderr, "Error waiting for the child: %s\n",
- strerror(errno));
- ret = 4;
- goto finish;
- }
- } else {
- /* we are the child */
- if (op == OP_MOUNT) {
- /* we use /proc/self/fd to mount the device
- * Since the container controls its own filesystem hierarchy, it
- * could trick us into mounting an arbitrary node located in the
- * filesystem. This is not considered a major security problem,
- * since
- * - the container should not have access to mknod() or nodes that
- * it is not meant to read
- * - we mount the filesystem read-only, with nosuid flag
- * - since the container will typically live in its own user
- * namespace, it will not have the right permissions to access a
- * filesystem that is not intended for it
- *
- * Ideally, there would be something like a mountfd() syscall that
- * would allow mounting an fd.
- */
- ret = snprintf(pathbuf, sizeof(pathbuf),
- "/proc/self/fd/%d", blockdev_fd);
- if (ret < 0 || ret >= sizeof(pathbuf)) {
- fprintf(stderr, "Error constructing the mount path\n");
- ret = 4;
- goto finish;
- }
-
- ret = mount(pathbuf, mountpoint, fstype, MS_RDONLY | MS_NOSUID, NULL);
- if (ret == -1) {
- fprintf(stderr, "mount(%s, %s) failed: %s\n",
- pathbuf, mountpoint, strerror(errno));
- ret = 5;
- goto finish;
- }
- } else if (op == OP_UMOUNT) {
- /**
- * As above, a malicious container can trick us into unmounting a
- * filesystem in its tree. This should not cause any issues other
- * than disrupting the container (which a compromised container can
- * already do without our help).
- */
- ret = umount(mountpoint);
- if (ret == -1) {
- fprintf(stderr, "umount() failed: %s\n", strerror(errno));
- ret = 5;
- goto finish;
- }
- }
- }
-
- ret = 0;
-finish:
- if (blockdev_fd >= 0)
- close(blockdev_fd);
- if (pidns_fd >= 0)
- close(pidns_fd);
- if (mountns_fd >= 0)
- close(mountns_fd);
-
- return ret;
-}