]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
Merge tag 'AT_EXECVE_CHECK-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Jan 2025 04:34:42 +0000 (20:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Jan 2025 04:34:42 +0000 (20:34 -0800)
Pull AT_EXECVE_CHECK from Kees Cook:

 - Implement AT_EXECVE_CHECK flag to execveat(2) (Mickaël Salaün)

 - Implement EXEC_RESTRICT_FILE and EXEC_DENY_INTERACTIVE securebits
   (Mickaël Salaün)

 - Add selftests and samples for AT_EXECVE_CHECK (Mickaël Salaün)

* tag 'AT_EXECVE_CHECK-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  ima: instantiate the bprm_creds_for_exec() hook
  samples/check-exec: Add an enlighten "inc" interpreter and 28 tests
  selftests: ktap_helpers: Fix uninitialized variable
  samples/check-exec: Add set-exec
  selftests/landlock: Add tests for execveat + AT_EXECVE_CHECK
  selftests/exec: Add 32 tests for AT_EXECVE_CHECK and exec securebits
  security: Add EXEC_RESTRICT_FILE and EXEC_DENY_INTERACTIVE securebits
  exec: Add a new AT_EXECVE_CHECK flag to execveat(2)

1  2 
fs/exec.c
include/linux/binfmts.h
security/security.c
tools/testing/selftests/kselftest/ktap_helpers.sh
tools/testing/selftests/landlock/fs_test.c

diff --cc fs/exec.c
Simple merge
index 3305c849abd66a4ddfd8d7c83ea6ff4dee2b75ad,8ff0eb3644a1eaa7b1ae8a9ebc65468b6b99aa14..60d674af3080a2ad7ba1605ea0d90daf4d1d47fb
@@@ -43,8 -43,11 +43,13 @@@ struct linux_binprm 
                 * original userspace.
                 */
                point_of_no_return:1,
-               comm_from_dentry:1;
 +              /* Set when "comm" must come from the dentry. */
++              comm_from_dentry:1,
+               /*
+                * Set by user space to check executability according to the
+                * caller's environment.
+                */
+               is_check:1;
        struct file *executable; /* Executable to pass to the interpreter */
        struct file *interpreter;
        struct file *file;
Simple merge
index 8ac9aaf38eaa8c9be0fcbeb6ea3adec8c6a4801c,cd66901be612b5a44bec44e194faecb2ac4f9983..2af86bd796bab61e4ce097f801b1fb9c34580a8a
@@@ -2027,10 -2041,14 +2047,14 @@@ TEST_F_FORK(layout1, execute
                create_ruleset(_metadata, rules[0].access, rules);
  
        ASSERT_LE(0, ruleset_fd);
 -      copy_binary(_metadata, file1_s1d1);
 -      copy_binary(_metadata, file1_s1d2);
 -      copy_binary(_metadata, file1_s1d3);
 +      copy_file(_metadata, bin_true, file1_s1d1);
 +      copy_file(_metadata, bin_true, file1_s1d2);
 +      copy_file(_metadata, bin_true, file1_s1d3);
  
+       /* Checks before file1_s1d1 being denied. */
+       test_execute(_metadata, 0, file1_s1d1);
+       test_check_exec(_metadata, 0, file1_s1d1);
        enforce_ruleset(_metadata, ruleset_fd);
        ASSERT_EQ(0, close(ruleset_fd));
  
        ASSERT_EQ(0, test_open(dir_s1d3, O_RDONLY));
        ASSERT_EQ(0, test_open(file1_s1d3, O_RDONLY));
        test_execute(_metadata, 0, file1_s1d3);
+       test_check_exec(_metadata, 0, file1_s1d3);
  }
  
 +TEST_F_FORK(layout1, umount_sandboxer)
 +{
 +      int pipe_child[2], pipe_parent[2];
 +      char buf_parent;
 +      pid_t child;
 +      int status;
 +
 +      copy_file(_metadata, bin_sandbox_and_launch, file1_s3d3);
 +      ASSERT_EQ(0, pipe2(pipe_child, 0));
 +      ASSERT_EQ(0, pipe2(pipe_parent, 0));
 +
 +      child = fork();
 +      ASSERT_LE(0, child);
 +      if (child == 0) {
 +              char pipe_child_str[12], pipe_parent_str[12];
 +              char *const argv[] = { (char *)file1_s3d3,
 +                                     (char *)bin_wait_pipe, pipe_child_str,
 +                                     pipe_parent_str, NULL };
 +
 +              /* Passes the pipe FDs to the executed binary and its child. */
 +              EXPECT_EQ(0, close(pipe_child[0]));
 +              EXPECT_EQ(0, close(pipe_parent[1]));
 +              snprintf(pipe_child_str, sizeof(pipe_child_str), "%d",
 +                       pipe_child[1]);
 +              snprintf(pipe_parent_str, sizeof(pipe_parent_str), "%d",
 +                       pipe_parent[0]);
 +
 +              /*
 +               * We need bin_sandbox_and_launch (copied inside the mount as
 +               * file1_s3d3) to execute bin_wait_pipe (outside the mount) to
 +               * make sure the mount point will not be EBUSY because of
 +               * file1_s3d3 being in use.  This avoids a potential race
 +               * condition between the following read() and umount() calls.
 +               */
 +              ASSERT_EQ(0, execve(argv[0], argv, NULL))
 +              {
 +                      TH_LOG("Failed to execute \"%s\": %s", argv[0],
 +                             strerror(errno));
 +              };
 +              _exit(1);
 +              return;
 +      }
 +
 +      EXPECT_EQ(0, close(pipe_child[1]));
 +      EXPECT_EQ(0, close(pipe_parent[0]));
 +
 +      /* Waits for the child to sandbox itself. */
 +      EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
 +
 +      /* Tests that the sandboxer is tied to its mount point. */
 +      set_cap(_metadata, CAP_SYS_ADMIN);
 +      EXPECT_EQ(-1, umount(dir_s3d2));
 +      EXPECT_EQ(EBUSY, errno);
 +      clear_cap(_metadata, CAP_SYS_ADMIN);
 +
 +      /* Signals the child to launch a grandchild. */
 +      EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
 +
 +      /* Waits for the grandchild. */
 +      EXPECT_EQ(1, read(pipe_child[0], &buf_parent, 1));
 +
 +      /* Tests that the domain's sandboxer is not tied to its mount point. */
 +      set_cap(_metadata, CAP_SYS_ADMIN);
 +      EXPECT_EQ(0, umount(dir_s3d2))
 +      {
 +              TH_LOG("Failed to umount \"%s\": %s", dir_s3d2,
 +                     strerror(errno));
 +      };
 +      clear_cap(_metadata, CAP_SYS_ADMIN);
 +
 +      /* Signals the grandchild to terminate. */
 +      EXPECT_EQ(1, write(pipe_parent[1], ".", 1));
 +      ASSERT_EQ(child, waitpid(child, &status, 0));
 +      ASSERT_EQ(1, WIFEXITED(status));
 +      ASSERT_EQ(0, WEXITSTATUS(status));
 +}
 +
  TEST_F_FORK(layout1, link)
  {
        const struct rule layer1[] = {