1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Write in a pipe, wait, sandbox itself, test sandboxing, and wait again. 4 * 5 * Used by audit_exec.flags from audit_test.c 6 * 7 * Copyright © 2024-2025 Microsoft Corporation 8 */ 9 10 #define _GNU_SOURCE 11 #include <fcntl.h> 12 #include <linux/landlock.h> 13 #include <linux/prctl.h> 14 #include <signal.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <sys/prctl.h> 18 #include <unistd.h> 19 20 #include "wrappers.h" 21 22 static int sync_with(int pipe_child, int pipe_parent) 23 { 24 char buf; 25 26 /* Signals that we are waiting. */ 27 if (write(pipe_child, ".", 1) != 1) { 28 perror("Failed to write to first argument"); 29 return 1; 30 } 31 32 /* Waits for the parent do its test. */ 33 if (read(pipe_parent, &buf, 1) != 1) { 34 perror("Failed to write to the second argument"); 35 return 1; 36 } 37 38 return 0; 39 } 40 41 int main(int argc, char *argv[]) 42 { 43 const struct landlock_ruleset_attr layer2 = { 44 .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR, 45 }; 46 const struct landlock_ruleset_attr layer3 = { 47 .scoped = LANDLOCK_SCOPE_SIGNAL, 48 }; 49 int err, pipe_child, pipe_parent, ruleset_fd; 50 51 /* The first argument must be the file descriptor number of a pipe. */ 52 if (argc != 3) { 53 fprintf(stderr, "Wrong number of arguments (not two)\n"); 54 return 1; 55 } 56 57 pipe_child = atoi(argv[1]); 58 pipe_parent = atoi(argv[2]); 59 /* PR_SET_NO_NEW_PRIVS already set by parent. */ 60 61 /* First step to test parent's layer1. */ 62 err = sync_with(pipe_child, pipe_parent); 63 if (err) 64 return err; 65 66 /* Tries to send a signal, denied by layer1. */ 67 if (!kill(getppid(), 0)) { 68 fprintf(stderr, "Successfully sent a signal to the parent"); 69 return 1; 70 } 71 72 /* Second step to test parent's layer1 and our layer2. */ 73 err = sync_with(pipe_child, pipe_parent); 74 if (err) 75 return err; 76 77 ruleset_fd = landlock_create_ruleset(&layer2, sizeof(layer2), 0); 78 if (ruleset_fd < 0) { 79 perror("Failed to create the layer2 ruleset"); 80 return 1; 81 } 82 83 if (landlock_restrict_self(ruleset_fd, 0)) { 84 perror("Failed to restrict self"); 85 return 1; 86 } 87 close(ruleset_fd); 88 89 /* Tries to send a signal, denied by layer1. */ 90 if (!kill(getppid(), 0)) { 91 fprintf(stderr, "Successfully sent a signal to the parent"); 92 return 1; 93 } 94 95 /* Tries to open ., denied by layer2. */ 96 if (open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC) >= 0) { 97 fprintf(stderr, "Successfully opened /"); 98 return 1; 99 } 100 101 /* Third step to test our layer2 and layer3. */ 102 err = sync_with(pipe_child, pipe_parent); 103 if (err) 104 return err; 105 106 ruleset_fd = landlock_create_ruleset(&layer3, sizeof(layer3), 0); 107 if (ruleset_fd < 0) { 108 perror("Failed to create the layer3 ruleset"); 109 return 1; 110 } 111 112 if (landlock_restrict_self(ruleset_fd, 0)) { 113 perror("Failed to restrict self"); 114 return 1; 115 } 116 close(ruleset_fd); 117 118 /* Tries to open ., denied by layer2. */ 119 if (open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC) >= 0) { 120 fprintf(stderr, "Successfully opened /"); 121 return 1; 122 } 123 124 /* Tries to send a signal, denied by layer3. */ 125 if (!kill(getppid(), 0)) { 126 fprintf(stderr, "Successfully sent a signal to the parent"); 127 return 1; 128 } 129 130 return 0; 131 } 132