ioperm.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * ioperm.c - Test case for ioperm(2)
  4. * Copyright (c) 2015 Andrew Lutomirski
  5. */
  6. #define _GNU_SOURCE
  7. #include <err.h>
  8. #include <stdio.h>
  9. #include <stdint.h>
  10. #include <signal.h>
  11. #include <setjmp.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <errno.h>
  15. #include <unistd.h>
  16. #include <sys/types.h>
  17. #include <sys/wait.h>
  18. #include <stdbool.h>
  19. #include <sched.h>
  20. #include <sys/io.h>
  21. static int nerrs = 0;
  22. static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
  23. int flags)
  24. {
  25. struct sigaction sa;
  26. memset(&sa, 0, sizeof(sa));
  27. sa.sa_sigaction = handler;
  28. sa.sa_flags = SA_SIGINFO | flags;
  29. sigemptyset(&sa.sa_mask);
  30. if (sigaction(sig, &sa, 0))
  31. err(1, "sigaction");
  32. }
  33. static void clearhandler(int sig)
  34. {
  35. struct sigaction sa;
  36. memset(&sa, 0, sizeof(sa));
  37. sa.sa_handler = SIG_DFL;
  38. sigemptyset(&sa.sa_mask);
  39. if (sigaction(sig, &sa, 0))
  40. err(1, "sigaction");
  41. }
  42. static jmp_buf jmpbuf;
  43. static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
  44. {
  45. siglongjmp(jmpbuf, 1);
  46. }
  47. static bool try_outb(unsigned short port)
  48. {
  49. sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
  50. if (sigsetjmp(jmpbuf, 1) != 0) {
  51. return false;
  52. } else {
  53. asm volatile ("outb %%al, %w[port]"
  54. : : [port] "Nd" (port), "a" (0));
  55. return true;
  56. }
  57. clearhandler(SIGSEGV);
  58. }
  59. static void expect_ok(unsigned short port)
  60. {
  61. if (!try_outb(port)) {
  62. printf("[FAIL]\toutb to 0x%02hx failed\n", port);
  63. exit(1);
  64. }
  65. printf("[OK]\toutb to 0x%02hx worked\n", port);
  66. }
  67. static void expect_gp(unsigned short port)
  68. {
  69. if (try_outb(port)) {
  70. printf("[FAIL]\toutb to 0x%02hx worked\n", port);
  71. exit(1);
  72. }
  73. printf("[OK]\toutb to 0x%02hx failed\n", port);
  74. }
  75. int main(void)
  76. {
  77. cpu_set_t cpuset;
  78. CPU_ZERO(&cpuset);
  79. CPU_SET(0, &cpuset);
  80. if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
  81. err(1, "sched_setaffinity to CPU 0");
  82. expect_gp(0x80);
  83. expect_gp(0xed);
  84. /*
  85. * Probe for ioperm support. Note that clearing ioperm bits
  86. * works even as nonroot.
  87. */
  88. printf("[RUN]\tenable 0x80\n");
  89. if (ioperm(0x80, 1, 1) != 0) {
  90. printf("[OK]\tioperm(0x80, 1, 1) failed (%d) -- try running as root\n",
  91. errno);
  92. return 0;
  93. }
  94. expect_ok(0x80);
  95. expect_gp(0xed);
  96. printf("[RUN]\tdisable 0x80\n");
  97. if (ioperm(0x80, 1, 0) != 0) {
  98. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  99. return 1;
  100. }
  101. expect_gp(0x80);
  102. expect_gp(0xed);
  103. /* Make sure that fork() preserves ioperm. */
  104. if (ioperm(0x80, 1, 1) != 0) {
  105. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  106. return 1;
  107. }
  108. pid_t child = fork();
  109. if (child == -1)
  110. err(1, "fork");
  111. if (child == 0) {
  112. printf("[RUN]\tchild: check that we inherited permissions\n");
  113. expect_ok(0x80);
  114. expect_gp(0xed);
  115. return 0;
  116. } else {
  117. int status;
  118. if (waitpid(child, &status, 0) != child ||
  119. !WIFEXITED(status)) {
  120. printf("[FAIL]\tChild died\n");
  121. nerrs++;
  122. } else if (WEXITSTATUS(status) != 0) {
  123. printf("[FAIL]\tChild failed\n");
  124. nerrs++;
  125. } else {
  126. printf("[OK]\tChild succeeded\n");
  127. }
  128. }
  129. /* Test the capability checks. */
  130. printf("\tDrop privileges\n");
  131. if (setresuid(1, 1, 1) != 0) {
  132. printf("[WARN]\tDropping privileges failed\n");
  133. return 0;
  134. }
  135. printf("[RUN]\tdisable 0x80\n");
  136. if (ioperm(0x80, 1, 0) != 0) {
  137. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  138. return 1;
  139. }
  140. printf("[OK]\tit worked\n");
  141. printf("[RUN]\tenable 0x80 again\n");
  142. if (ioperm(0x80, 1, 1) == 0) {
  143. printf("[FAIL]\tit succeeded but should have failed.\n");
  144. return 1;
  145. }
  146. printf("[OK]\tit failed\n");
  147. return 0;
  148. }