(root)/
util-linux-2.39/
tests/
helpers/
test_enosys.c
       1  /*
       2   * Copyright (C) 2023 Thomas Weißschuh <thomas@t-8ch.de>
       3   *
       4   * This program is free software; you can redistribute it and/or modify
       5   * it under the terms of the GNU General Public License as published by
       6   * the Free Software Foundation; either version 2 of the License, or
       7   * (at your option) any later version.
       8   *
       9   * This program is distributed in the hope that it would be useful,
      10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12   * GNU General Public License for more details.
      13   *
      14   * You should have received a copy of the GNU General Public License along
      15   * with this program; if not, write to the Free Software Foundation, Inc.,
      16   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17   */
      18  
      19  #include <stddef.h>
      20  #include <stdbool.h>
      21  #include <getopt.h>
      22  
      23  #include <linux/unistd.h>
      24  #include <linux/filter.h>
      25  #include <linux/seccomp.h>
      26  #include <linux/audit.h>
      27  #include <sys/prctl.h>
      28  
      29  #include "c.h"
      30  #include "exitcodes.h"
      31  
      32  #if __x86_64__
      33  #    define SECCOMP_ARCH_NATIVE AUDIT_ARCH_X86_64
      34  #elif __i386__
      35  #    define SECCOMP_ARCH_NATIVE AUDIT_ARCH_I386
      36  #elif __arm__
      37  #    define SECCOMP_ARCH_NATIVE AUDIT_ARCH_ARM
      38  #elif __aarch64__
      39  #    define SECCOMP_ARCH_NATIVE AUDIT_ARCH_AARCH64
      40  #elif __riscv
      41  #    if __riscv_xlen == 32
      42  #        define SECCOMP_ARCH_NATIVE AUDIT_ARCH_RISCV32
      43  #    elif __riscv_xlen == 64
      44  #        define SECCOMP_ARCH_NATIVE AUDIT_ARCH_RISCV64
      45  #    endif
      46  #elif __s390__
      47  # 	 define SECCOMP_ARCH_NATIVE AUDIT_ARCH_S390
      48  #elif __s390x__
      49  # 	 define SECCOMP_ARCH_NATIVE AUDIT_ARCH_S390X
      50  #elif __PPC64__
      51  #    if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
      52  # 	 define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PPC64
      53  #    else
      54  # 	 define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PPC64LE
      55  #    endif
      56  #else
      57  #    error Unknown target architecture
      58  #endif
      59  
      60  #define syscall_nr (offsetof(struct seccomp_data, nr))
      61  
      62  struct syscall {
      63  	const char *const name;
      64  	int number;
      65  };
      66  
      67  const struct syscall syscalls[] = {
      68  	{ "move_mount", __NR_move_mount },
      69  	{ "open_tree", __NR_open_tree },
      70  	{ "fsopen", __NR_fsopen },
      71  };
      72  
      73  int main(int argc, char **argv)
      74  {
      75  	int c;
      76  	size_t i;
      77  	bool found;
      78  	static const struct option longopts[] = {
      79  		{ "syscall", required_argument, NULL, 's' },
      80  		{ 0 }
      81  	};
      82  
      83  	bool blocked_syscalls[ARRAY_SIZE(syscalls)] = {};
      84  
      85  	while ((c = getopt_long (argc, argv, "s:", longopts, NULL)) != -1) {
      86  		switch (c) {
      87  		case 's':
      88  			found = 0;
      89  			for (i = 0; i < ARRAY_SIZE(syscalls); i++) {
      90  				if (strcmp(optarg, syscalls[i].name) == 0) {
      91  					blocked_syscalls[i] = true;
      92  					found = 1;
      93  					break;
      94  				}
      95  			}
      96  			if (!found)
      97  				errx(EXIT_FAILURE, "Unknown syscall '%s'", optarg);
      98  			break;
      99  		default:
     100  			errx(EXIT_FAILURE, "Unknown option");
     101  		}
     102  	}
     103  
     104  	if (optind >= argc)
     105  		errx(EXIT_FAILURE, "No executable specified");
     106  
     107  #define N_FILTERS (ARRAY_SIZE(syscalls) + 3)
     108  
     109  	struct sock_filter filter[N_FILTERS] = {
     110  		[0]             = BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_nr),
     111  
     112  		[N_FILTERS - 2] = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
     113  		[N_FILTERS - 1] = BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS),
     114  	};
     115  
     116  	const struct sock_filter nop = BPF_JUMP(BPF_JMP | BPF_JA, 0, 0, 0);
     117  
     118  	for (i = 0; i < ARRAY_SIZE(syscalls); i++) {
     119  		if (blocked_syscalls[i]) {
     120  			const struct sock_filter block = BPF_JUMP(
     121  					BPF_JMP | BPF_JEQ | BPF_K,
     122  					syscalls[i].number,
     123  					N_FILTERS - 3 - i, 0);
     124  			filter[i + 1] = block;
     125  		} else {
     126  			filter[i + 1] = nop;
     127  		}
     128  	}
     129  
     130  	struct sock_fprog prog = {
     131  		.len    = ARRAY_SIZE(filter),
     132  		.filter = filter,
     133  	};
     134  
     135  	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
     136  		err(EXIT_NOTSUPP, "prctl(PR_SET_NO_NEW_PRIVS)");
     137  
     138  	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
     139  		err(EXIT_NOTSUPP, "prctl(PR_SET_SECCOMP)");
     140  
     141  	if (execvp(argv[optind], argv + optind))
     142  		err(EXIT_NOTSUPP, "Could not exec");
     143  }