ioperm.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. #include "helpers.h"
  22. static int nerrs = 0;
  23. static jmp_buf jmpbuf;
  24. static void sigsegv(int sig, siginfo_t *si, void *ctx_void)
  25. {
  26. siglongjmp(jmpbuf, 1);
  27. }
  28. static bool try_outb(unsigned short port)
  29. {
  30. sethandler(SIGSEGV, sigsegv, SA_RESETHAND);
  31. if (sigsetjmp(jmpbuf, 1) != 0) {
  32. return false;
  33. } else {
  34. asm volatile ("outb %%al, %w[port]"
  35. : : [port] "Nd" (port), "a" (0));
  36. return true;
  37. }
  38. clearhandler(SIGSEGV);
  39. }
  40. static void expect_ok(unsigned short port)
  41. {
  42. if (!try_outb(port)) {
  43. printf("[FAIL]\toutb to 0x%02hx failed\n", port);
  44. exit(1);
  45. }
  46. printf("[OK]\toutb to 0x%02hx worked\n", port);
  47. }
  48. static void expect_gp(unsigned short port)
  49. {
  50. if (try_outb(port)) {
  51. printf("[FAIL]\toutb to 0x%02hx worked\n", port);
  52. exit(1);
  53. }
  54. printf("[OK]\toutb to 0x%02hx failed\n", port);
  55. }
  56. int main(void)
  57. {
  58. cpu_set_t cpuset;
  59. CPU_ZERO(&cpuset);
  60. CPU_SET(0, &cpuset);
  61. if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0)
  62. err(1, "sched_setaffinity to CPU 0");
  63. expect_gp(0x80);
  64. expect_gp(0xed);
  65. /*
  66. * Probe for ioperm support. Note that clearing ioperm bits
  67. * works even as nonroot.
  68. */
  69. printf("[RUN]\tenable 0x80\n");
  70. if (ioperm(0x80, 1, 1) != 0) {
  71. printf("[OK]\tioperm(0x80, 1, 1) failed (%d) -- try running as root\n",
  72. errno);
  73. return 0;
  74. }
  75. expect_ok(0x80);
  76. expect_gp(0xed);
  77. printf("[RUN]\tdisable 0x80\n");
  78. if (ioperm(0x80, 1, 0) != 0) {
  79. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  80. return 1;
  81. }
  82. expect_gp(0x80);
  83. expect_gp(0xed);
  84. /* Make sure that fork() preserves ioperm. */
  85. if (ioperm(0x80, 1, 1) != 0) {
  86. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  87. return 1;
  88. }
  89. pid_t child = fork();
  90. if (child == -1)
  91. err(1, "fork");
  92. if (child == 0) {
  93. printf("[RUN]\tchild: check that we inherited permissions\n");
  94. expect_ok(0x80);
  95. expect_gp(0xed);
  96. printf("[RUN]\tchild: Extend permissions to 0x81\n");
  97. if (ioperm(0x81, 1, 1) != 0) {
  98. printf("[FAIL]\tioperm(0x81, 1, 1) failed (%d)", errno);
  99. return 1;
  100. }
  101. printf("[RUN]\tchild: Drop permissions to 0x80\n");
  102. if (ioperm(0x80, 1, 0) != 0) {
  103. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  104. return 1;
  105. }
  106. expect_gp(0x80);
  107. return 0;
  108. } else {
  109. int status;
  110. if (waitpid(child, &status, 0) != child ||
  111. !WIFEXITED(status)) {
  112. printf("[FAIL]\tChild died\n");
  113. nerrs++;
  114. } else if (WEXITSTATUS(status) != 0) {
  115. printf("[FAIL]\tChild failed\n");
  116. nerrs++;
  117. } else {
  118. printf("[OK]\tChild succeeded\n");
  119. }
  120. }
  121. /* Verify that the child dropping 0x80 did not affect the parent */
  122. printf("\tVerify that unsharing the bitmap worked\n");
  123. expect_ok(0x80);
  124. /* Test the capability checks. */
  125. printf("\tDrop privileges\n");
  126. if (setresuid(1, 1, 1) != 0) {
  127. printf("[WARN]\tDropping privileges failed\n");
  128. return 0;
  129. }
  130. printf("[RUN]\tdisable 0x80\n");
  131. if (ioperm(0x80, 1, 0) != 0) {
  132. printf("[FAIL]\tioperm(0x80, 1, 0) failed (%d)", errno);
  133. return 1;
  134. }
  135. printf("[OK]\tit worked\n");
  136. printf("[RUN]\tenable 0x80 again\n");
  137. if (ioperm(0x80, 1, 1) == 0) {
  138. printf("[FAIL]\tit succeeded but should have failed.\n");
  139. return 1;
  140. }
  141. printf("[OK]\tit failed\n");
  142. return 0;
  143. }