check-exec.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Test execveat(2) with AT_EXECVE_CHECK, and prctl(2) with
  4. * SECBIT_EXEC_RESTRICT_FILE, SECBIT_EXEC_DENY_INTERACTIVE, and their locked
  5. * counterparts.
  6. *
  7. * Copyright © 2018-2020 ANSSI
  8. * Copyright © 2024 Microsoft Corporation
  9. *
  10. * Author: Mickaël Salaün <mic@digikod.net>
  11. */
  12. #include <asm-generic/unistd.h>
  13. #include <errno.h>
  14. #include <fcntl.h>
  15. #include <linux/prctl.h>
  16. #include <linux/securebits.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <sys/capability.h>
  20. #include <sys/mount.h>
  21. #include <sys/prctl.h>
  22. #include <sys/socket.h>
  23. #include <sys/stat.h>
  24. #include <sys/syscall.h>
  25. #include <sys/sysmacros.h>
  26. #include <unistd.h>
  27. /* Defines AT_EXECVE_CHECK without type conflicts. */
  28. #define _ASM_GENERIC_FCNTL_H
  29. #include <linux/fcntl.h>
  30. #include "kselftest_harness.h"
  31. static int sys_execveat(int dirfd, const char *pathname, char *const argv[],
  32. char *const envp[], int flags)
  33. {
  34. return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
  35. }
  36. static void drop_privileges(struct __test_metadata *const _metadata)
  37. {
  38. const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
  39. cap_t cap_p;
  40. if ((cap_get_secbits() & noroot) != noroot)
  41. EXPECT_EQ(0, cap_set_secbits(noroot));
  42. cap_p = cap_get_proc();
  43. EXPECT_NE(NULL, cap_p);
  44. EXPECT_NE(-1, cap_clear(cap_p));
  45. /*
  46. * Drops everything, especially CAP_SETPCAP, CAP_DAC_OVERRIDE, and
  47. * CAP_DAC_READ_SEARCH.
  48. */
  49. EXPECT_NE(-1, cap_set_proc(cap_p));
  50. EXPECT_NE(-1, cap_free(cap_p));
  51. }
  52. static int test_secbits_set(const unsigned int secbits)
  53. {
  54. int err;
  55. err = prctl(PR_SET_SECUREBITS, secbits);
  56. if (err)
  57. return errno;
  58. return 0;
  59. }
  60. FIXTURE(access)
  61. {
  62. int memfd, pipefd;
  63. int pipe_fds[2], socket_fds[2];
  64. };
  65. FIXTURE_VARIANT(access)
  66. {
  67. const bool mount_exec;
  68. const bool file_exec;
  69. };
  70. /* clang-format off */
  71. FIXTURE_VARIANT_ADD(access, mount_exec_file_exec) {
  72. /* clang-format on */
  73. .mount_exec = true,
  74. .file_exec = true,
  75. };
  76. /* clang-format off */
  77. FIXTURE_VARIANT_ADD(access, mount_exec_file_noexec) {
  78. /* clang-format on */
  79. .mount_exec = true,
  80. .file_exec = false,
  81. };
  82. /* clang-format off */
  83. FIXTURE_VARIANT_ADD(access, mount_noexec_file_exec) {
  84. /* clang-format on */
  85. .mount_exec = false,
  86. .file_exec = true,
  87. };
  88. /* clang-format off */
  89. FIXTURE_VARIANT_ADD(access, mount_noexec_file_noexec) {
  90. /* clang-format on */
  91. .mount_exec = false,
  92. .file_exec = false,
  93. };
  94. static const char binary_path[] = "./false";
  95. static const char workdir_path[] = "./test-mount";
  96. static const char reg_file_path[] = "./test-mount/regular_file";
  97. static const char dir_path[] = "./test-mount/directory";
  98. static const char block_dev_path[] = "./test-mount/block_device";
  99. static const char char_dev_path[] = "./test-mount/character_device";
  100. static const char fifo_path[] = "./test-mount/fifo";
  101. FIXTURE_SETUP(access)
  102. {
  103. int procfd_path_size;
  104. static const char path_template[] = "/proc/self/fd/%d";
  105. char procfd_path[sizeof(path_template) + 10];
  106. /* Makes sure we are not already restricted nor locked. */
  107. EXPECT_EQ(0, test_secbits_set(0));
  108. /*
  109. * Cleans previous workspace if any error previously happened (don't
  110. * check errors).
  111. */
  112. umount(workdir_path);
  113. rmdir(workdir_path);
  114. /* Creates a clean mount point. */
  115. ASSERT_EQ(0, mkdir(workdir_path, 00700));
  116. ASSERT_EQ(0, mount("test", workdir_path, "tmpfs",
  117. MS_MGC_VAL | (variant->mount_exec ? 0 : MS_NOEXEC),
  118. "mode=0700,size=9m"));
  119. /* Creates a regular file. */
  120. ASSERT_EQ(0, mknod(reg_file_path,
  121. S_IFREG | (variant->file_exec ? 0700 : 0600), 0));
  122. /* Creates a directory. */
  123. ASSERT_EQ(0, mkdir(dir_path, variant->file_exec ? 0700 : 0600));
  124. /* Creates a character device: /dev/null. */
  125. ASSERT_EQ(0, mknod(char_dev_path, S_IFCHR | 0400, makedev(1, 3)));
  126. /* Creates a block device: /dev/loop0 */
  127. ASSERT_EQ(0, mknod(block_dev_path, S_IFBLK | 0400, makedev(7, 0)));
  128. /* Creates a fifo. */
  129. ASSERT_EQ(0, mknod(fifo_path, S_IFIFO | 0600, 0));
  130. /* Creates a regular file without user mount point. */
  131. self->memfd = memfd_create("test-exec-probe", MFD_CLOEXEC);
  132. ASSERT_LE(0, self->memfd);
  133. /* Sets mode, which must be ignored by the exec check. */
  134. ASSERT_EQ(0, fchmod(self->memfd, variant->file_exec ? 0700 : 0600));
  135. /* Creates a pipefs file descriptor. */
  136. ASSERT_EQ(0, pipe(self->pipe_fds));
  137. procfd_path_size = snprintf(procfd_path, sizeof(procfd_path),
  138. path_template, self->pipe_fds[0]);
  139. ASSERT_LT(procfd_path_size, sizeof(procfd_path));
  140. self->pipefd = open(procfd_path, O_RDWR | O_CLOEXEC);
  141. ASSERT_LE(0, self->pipefd);
  142. ASSERT_EQ(0, fchmod(self->pipefd, variant->file_exec ? 0700 : 0600));
  143. /* Creates a socket file descriptor. */
  144. ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0,
  145. self->socket_fds));
  146. }
  147. FIXTURE_TEARDOWN_PARENT(access)
  148. {
  149. /* There is no need to unlink the test files. */
  150. EXPECT_EQ(0, umount(workdir_path));
  151. EXPECT_EQ(0, rmdir(workdir_path));
  152. }
  153. static void fill_exec_fd(struct __test_metadata *_metadata, const int fd_out)
  154. {
  155. char buf[1024];
  156. size_t len;
  157. int fd_in;
  158. fd_in = open(binary_path, O_CLOEXEC | O_RDONLY);
  159. ASSERT_LE(0, fd_in);
  160. /* Cannot use copy_file_range(2) because of EXDEV. */
  161. len = read(fd_in, buf, sizeof(buf));
  162. EXPECT_LE(0, len);
  163. while (len > 0) {
  164. EXPECT_EQ(len, write(fd_out, buf, len))
  165. {
  166. TH_LOG("Failed to write: %s (%d)", strerror(errno),
  167. errno);
  168. }
  169. len = read(fd_in, buf, sizeof(buf));
  170. EXPECT_LE(0, len);
  171. }
  172. EXPECT_EQ(0, close(fd_in));
  173. }
  174. static void fill_exec_path(struct __test_metadata *_metadata,
  175. const char *const path)
  176. {
  177. int fd_out;
  178. fd_out = open(path, O_CLOEXEC | O_WRONLY);
  179. ASSERT_LE(0, fd_out)
  180. {
  181. TH_LOG("Failed to open %s: %s", path, strerror(errno));
  182. }
  183. fill_exec_fd(_metadata, fd_out);
  184. EXPECT_EQ(0, close(fd_out));
  185. }
  186. static void test_exec_fd(struct __test_metadata *_metadata, const int fd,
  187. const int err_code)
  188. {
  189. char *const argv[] = { "", NULL };
  190. int access_ret, access_errno;
  191. /*
  192. * If we really execute fd, filled with the "false" binary, the current
  193. * thread will exits with an error, which will be interpreted by the
  194. * test framework as an error. With AT_EXECVE_CHECK, we only check a
  195. * potential successful execution.
  196. */
  197. access_ret = sys_execveat(fd, "", argv, NULL,
  198. AT_EMPTY_PATH | AT_EXECVE_CHECK);
  199. access_errno = errno;
  200. if (err_code) {
  201. EXPECT_EQ(-1, access_ret);
  202. EXPECT_EQ(err_code, access_errno)
  203. {
  204. TH_LOG("Wrong error for execveat(2): %s (%d)",
  205. strerror(access_errno), errno);
  206. }
  207. } else {
  208. EXPECT_EQ(0, access_ret)
  209. {
  210. TH_LOG("Access denied: %s", strerror(access_errno));
  211. }
  212. }
  213. }
  214. static void test_exec_path(struct __test_metadata *_metadata,
  215. const char *const path, const int err_code)
  216. {
  217. int flags = O_CLOEXEC;
  218. int fd;
  219. /* Do not block on pipes. */
  220. if (path == fifo_path)
  221. flags |= O_NONBLOCK;
  222. fd = open(path, flags | O_RDONLY);
  223. ASSERT_LE(0, fd)
  224. {
  225. TH_LOG("Failed to open %s: %s", path, strerror(errno));
  226. }
  227. test_exec_fd(_metadata, fd, err_code);
  228. EXPECT_EQ(0, close(fd));
  229. }
  230. /* Tests that we don't get ENOEXEC. */
  231. TEST_F(access, regular_file_empty)
  232. {
  233. const int exec = variant->mount_exec && variant->file_exec;
  234. test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
  235. drop_privileges(_metadata);
  236. test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
  237. }
  238. TEST_F(access, regular_file_elf)
  239. {
  240. const int exec = variant->mount_exec && variant->file_exec;
  241. fill_exec_path(_metadata, reg_file_path);
  242. test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
  243. drop_privileges(_metadata);
  244. test_exec_path(_metadata, reg_file_path, exec ? 0 : EACCES);
  245. }
  246. /* Tests that we don't get ENOEXEC. */
  247. TEST_F(access, memfd_empty)
  248. {
  249. const int exec = variant->file_exec;
  250. test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
  251. drop_privileges(_metadata);
  252. test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
  253. }
  254. TEST_F(access, memfd_elf)
  255. {
  256. const int exec = variant->file_exec;
  257. fill_exec_fd(_metadata, self->memfd);
  258. test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
  259. drop_privileges(_metadata);
  260. test_exec_fd(_metadata, self->memfd, exec ? 0 : EACCES);
  261. }
  262. TEST_F(access, non_regular_files)
  263. {
  264. test_exec_path(_metadata, dir_path, EACCES);
  265. test_exec_path(_metadata, block_dev_path, EACCES);
  266. test_exec_path(_metadata, char_dev_path, EACCES);
  267. test_exec_path(_metadata, fifo_path, EACCES);
  268. test_exec_fd(_metadata, self->socket_fds[0], EACCES);
  269. test_exec_fd(_metadata, self->pipefd, EACCES);
  270. }
  271. /* clang-format off */
  272. FIXTURE(secbits) {};
  273. /* clang-format on */
  274. FIXTURE_VARIANT(secbits)
  275. {
  276. const bool is_privileged;
  277. const int error;
  278. };
  279. /* clang-format off */
  280. FIXTURE_VARIANT_ADD(secbits, priv) {
  281. /* clang-format on */
  282. .is_privileged = true,
  283. .error = 0,
  284. };
  285. /* clang-format off */
  286. FIXTURE_VARIANT_ADD(secbits, unpriv) {
  287. /* clang-format on */
  288. .is_privileged = false,
  289. .error = EPERM,
  290. };
  291. FIXTURE_SETUP(secbits)
  292. {
  293. /* Makes sure no exec bits are set. */
  294. EXPECT_EQ(0, test_secbits_set(0));
  295. EXPECT_EQ(0, prctl(PR_GET_SECUREBITS));
  296. if (!variant->is_privileged)
  297. drop_privileges(_metadata);
  298. }
  299. FIXTURE_TEARDOWN(secbits)
  300. {
  301. }
  302. TEST_F(secbits, legacy)
  303. {
  304. EXPECT_EQ(variant->error, test_secbits_set(0));
  305. }
  306. #define CHILD(...) \
  307. do { \
  308. pid_t child = vfork(); \
  309. EXPECT_LE(0, child); \
  310. if (child == 0) { \
  311. __VA_ARGS__; \
  312. _exit(0); \
  313. } \
  314. } while (0)
  315. TEST_F(secbits, exec)
  316. {
  317. unsigned int secbits = prctl(PR_GET_SECUREBITS);
  318. secbits |= SECBIT_EXEC_RESTRICT_FILE;
  319. EXPECT_EQ(0, test_secbits_set(secbits));
  320. EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS));
  321. CHILD(EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS)));
  322. secbits |= SECBIT_EXEC_DENY_INTERACTIVE;
  323. EXPECT_EQ(0, test_secbits_set(secbits));
  324. EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS));
  325. CHILD(EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS)));
  326. secbits &= ~(SECBIT_EXEC_RESTRICT_FILE | SECBIT_EXEC_DENY_INTERACTIVE);
  327. EXPECT_EQ(0, test_secbits_set(secbits));
  328. EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS));
  329. CHILD(EXPECT_EQ(secbits, prctl(PR_GET_SECUREBITS)));
  330. }
  331. TEST_F(secbits, check_locked_set)
  332. {
  333. unsigned int secbits = prctl(PR_GET_SECUREBITS);
  334. secbits |= SECBIT_EXEC_RESTRICT_FILE;
  335. EXPECT_EQ(0, test_secbits_set(secbits));
  336. secbits |= SECBIT_EXEC_RESTRICT_FILE_LOCKED;
  337. EXPECT_EQ(0, test_secbits_set(secbits));
  338. /* Checks lock set but unchanged. */
  339. EXPECT_EQ(variant->error, test_secbits_set(secbits));
  340. CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
  341. secbits &= ~SECBIT_EXEC_RESTRICT_FILE;
  342. EXPECT_EQ(EPERM, test_secbits_set(0));
  343. CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
  344. }
  345. TEST_F(secbits, check_locked_unset)
  346. {
  347. unsigned int secbits = prctl(PR_GET_SECUREBITS);
  348. secbits |= SECBIT_EXEC_RESTRICT_FILE_LOCKED;
  349. EXPECT_EQ(0, test_secbits_set(secbits));
  350. /* Checks lock unset but unchanged. */
  351. EXPECT_EQ(variant->error, test_secbits_set(secbits));
  352. CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
  353. secbits &= ~SECBIT_EXEC_RESTRICT_FILE;
  354. EXPECT_EQ(EPERM, test_secbits_set(0));
  355. CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
  356. }
  357. TEST_F(secbits, restrict_locked_set)
  358. {
  359. unsigned int secbits = prctl(PR_GET_SECUREBITS);
  360. secbits |= SECBIT_EXEC_DENY_INTERACTIVE;
  361. EXPECT_EQ(0, test_secbits_set(secbits));
  362. secbits |= SECBIT_EXEC_DENY_INTERACTIVE_LOCKED;
  363. EXPECT_EQ(0, test_secbits_set(secbits));
  364. /* Checks lock set but unchanged. */
  365. EXPECT_EQ(variant->error, test_secbits_set(secbits));
  366. CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
  367. secbits &= ~SECBIT_EXEC_DENY_INTERACTIVE;
  368. EXPECT_EQ(EPERM, test_secbits_set(0));
  369. CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
  370. }
  371. TEST_F(secbits, restrict_locked_unset)
  372. {
  373. unsigned int secbits = prctl(PR_GET_SECUREBITS);
  374. secbits |= SECBIT_EXEC_DENY_INTERACTIVE_LOCKED;
  375. EXPECT_EQ(0, test_secbits_set(secbits));
  376. /* Checks lock unset but unchanged. */
  377. EXPECT_EQ(variant->error, test_secbits_set(secbits));
  378. CHILD(EXPECT_EQ(variant->error, test_secbits_set(secbits)));
  379. secbits &= ~SECBIT_EXEC_DENY_INTERACTIVE;
  380. EXPECT_EQ(EPERM, test_secbits_set(0));
  381. CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
  382. }
  383. TEST_HARNESS_MAIN