init.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * ArkOS Init (PID 1)
  3. * ------------------
  4. * The first userspace process, responsible for:
  5. *
  6. * 1. Mounting essential filesystems (devtmpfs, proc, sysfs)
  7. * 2. Setting up console I/O (stdin, stdout, stderr)
  8. * 3. Mounting tmpfs for /tmp, /run (with security flags)
  9. * 4. Setting a safe umask
  10. * 5. Verifying the OS runtime signature (Verified Boot)
  11. * 6. Launching arkrt (the ArkOS Runtime Daemon) as PID 2
  12. * 7. Waiting forever (PID 1 must never exit)
  13. *
  14. * Security:
  15. * - /tmp is mounted with noexec,nosuid to prevent privilege escalation
  16. * - Verified Boot checks SHA256(KEY + arkrt) against signature.bin
  17. * - Console output is suppressed for kernel messages after boot
  18. *
  19. * This file is compiled with: gcc -static -DARK_KEY="..." init.c sha256.c
  20. */
  21. #include <fcntl.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <sys/ioctl.h>
  26. #include <sys/mount.h>
  27. #include <sys/stat.h>
  28. #include <sys/wait.h>
  29. #include <unistd.h>
  30. #include "../../vendor/verify/sha256.h"
  31. /* Verified Boot signing key (injected at compile time by the build system) */
  32. #ifndef ARK_KEY
  33. #define ARK_KEY "UNKNOWN_KEY"
  34. #endif
  35. /* ── Kernel Panic Handler ──────────────────────────────────────── */
  36. /**
  37. * Displays a kernel panic message and halts the system.
  38. * Called when Verified Boot fails or a critical error occurs.
  39. * This function never returns.
  40. */
  41. void trigger_kernel_panic(const char *msg) {
  42. printf("\n");
  43. printf("======================================================\n");
  44. printf(" KERNEL PANIC \n");
  45. printf(" Please reboot your computer. \n");
  46. printf("======================================================\n");
  47. printf("VFS: Unable to mount root fs on unknown-block(0,0)\n");
  48. printf("ArkOS Verified Boot: %s\n", msg);
  49. fflush(stdout);
  50. /* Halt forever — PID 1 must never exit */
  51. while (1) {
  52. sleep(1);
  53. }
  54. }
  55. /* ── Verified Boot ─────────────────────────────────────────────── */
  56. /**
  57. * Verifies the integrity of the arkrt binary using HMAC-SHA256.
  58. *
  59. * Algorithm:
  60. * 1. Read the expected signature from /signature.bin (64-char hex)
  61. * 2. Read the entire /arkrt binary into memory
  62. * 3. Compute SHA256(ARK_KEY + arkrt_bytes)
  63. * 4. Compare computed hash against the expected signature
  64. *
  65. * Returns 1 on success, calls trigger_kernel_panic() on failure.
  66. */
  67. int verify_os_signature(void) {
  68. /* Read the expected signature (64 hex characters) */
  69. int sig_fd = open("/signature.bin", O_RDONLY);
  70. if (sig_fd < 0) {
  71. trigger_kernel_panic("Missing signature.bin!");
  72. return 0;
  73. }
  74. char expected_sig[65] = {0};
  75. read(sig_fd, expected_sig, 64);
  76. close(sig_fd);
  77. /* Read the arkrt binary */
  78. int os_fd = open("/arkrt", O_RDONLY);
  79. if (os_fd < 0) {
  80. trigger_kernel_panic("Missing /arkrt OS binary!");
  81. return 0;
  82. }
  83. struct stat st;
  84. fstat(os_fd, &st);
  85. uint8_t *os_data = malloc(st.st_size);
  86. if (!os_data) {
  87. trigger_kernel_panic("Out of memory during verification!");
  88. return 0;
  89. }
  90. /* Read entire binary (handle partial reads) */
  91. size_t total_read = 0;
  92. while (total_read < (size_t)st.st_size) {
  93. ssize_t r = read(os_fd, os_data + total_read, st.st_size - total_read);
  94. if (r <= 0)
  95. break;
  96. total_read += r;
  97. }
  98. close(os_fd);
  99. /* Compute SHA256(KEY + binary_data) */
  100. SHA256_CTX ctx;
  101. sha256_init(&ctx);
  102. sha256_update(&ctx, (const uint8_t *)ARK_KEY, strlen(ARK_KEY));
  103. sha256_update(&ctx, os_data, st.st_size);
  104. uint8_t hash[32];
  105. sha256_final(&ctx, hash);
  106. free(os_data);
  107. /* Convert binary hash to hex string for comparison */
  108. char computed_sig[65] = {0};
  109. for (int i = 0; i < 32; i++) {
  110. sprintf(&computed_sig[i * 2], "%02x", hash[i]);
  111. }
  112. /* Constant-time comparison would be better, but this is boot-time only */
  113. if (strncmp(expected_sig, computed_sig, 64) != 0) {
  114. printf("Expected: %s\n", expected_sig);
  115. printf("Computed: %s\n", computed_sig);
  116. trigger_kernel_panic(
  117. "Signature mismatch! System may be compromised.");
  118. return 0;
  119. }
  120. return 1;
  121. }
  122. /* ── Main ──────────────────────────────────────────────────────── */
  123. int main(void) {
  124. /*
  125. * Phase 1: Mount essential kernel filesystems
  126. * These must be available before anything else can work.
  127. */
  128. mkdir("/dev", 0755);
  129. mkdir("/proc", 0755);
  130. mkdir("/sys", 0755);
  131. mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
  132. mount("proc", "/proc", "proc", 0, NULL);
  133. mount("sysfs", "/sys", "sysfs", 0, NULL);
  134. /*
  135. * Phase 2: Set up console I/O
  136. * Redirect stdin/stdout/stderr to /dev/console so print() works.
  137. */
  138. int fd = open("/dev/console", O_RDWR);
  139. if (fd >= 0) {
  140. dup2(fd, 0); /* stdin */
  141. dup2(fd, 1); /* stdout */
  142. dup2(fd, 2); /* stderr */
  143. if (fd > 2)
  144. close(fd);
  145. }
  146. /*
  147. * Phase 3: Security setup
  148. * - Set umask to 022 (files: 644, dirs: 755 by default)
  149. * - Mount /tmp with noexec,nosuid to prevent privilege escalation
  150. * - Mount /dev/shm for POSIX shared memory
  151. * - Create /run for PID files
  152. */
  153. umask(0022);
  154. mkdir("/tmp", 01777);
  155. mount("tmpfs", "/tmp", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
  156. "size=64m,mode=1777");
  157. mkdir("/dev/shm", 01777);
  158. mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_NODEV, "size=64m");
  159. mkdir("/run", 0755);
  160. mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV, "size=8m");
  161. mkdir("/var", 0755);
  162. mkdir("/var/log", 0755);
  163. mkdir("/etc", 0755);
  164. /*
  165. * Phase 4: Hide kernel boot messages and prepare display
  166. * - Set terminal to KD_GRAPHICS to prevent fbcon from interfering
  167. * - Set terminal background to black
  168. * - Clear the screen
  169. * - Hide the cursor
  170. * This prevents the white flash between kernel boot and splash screen.
  171. */
  172. int tty_fd = open("/dev/tty0", O_RDWR);
  173. if (tty_fd >= 0) {
  174. /* Clear screen and hide cursor on the physical display */
  175. write(tty_fd, "\033[0;40m\033[2J\033[H\033[?25l", 20);
  176. ioctl(tty_fd, 0x4B3A, 1); /* KDSETMODE, KD_GRAPHICS */
  177. close(tty_fd);
  178. }
  179. /*
  180. * Phase 5: Verified Boot
  181. * Compute HMAC-SHA256 of the arkrt binary and compare against
  182. * the pre-signed signature. Panics if verification fails.
  183. */
  184. verify_os_signature();
  185. /*
  186. * Phase 6: Launch the ArkOS Runtime Daemon (arkrt)
  187. * arkrt becomes PID 2 and manages all system services.
  188. * Its stdout/stderr go to /dev/ttyS0 (serial console for debugging).
  189. */
  190. pid_t pid = fork();
  191. if (pid == 0) {
  192. /* Child process — redirect to serial console for debug output */
  193. int sfd = open("/dev/ttyS0", O_RDWR);
  194. if (sfd >= 0) {
  195. dup2(sfd, 0);
  196. dup2(sfd, 1);
  197. dup2(sfd, 2);
  198. if (sfd > 2)
  199. close(sfd);
  200. }
  201. char *argv[] = {"/arkrt", NULL};
  202. char *envp[] = {"PATH=/bin:/usr/bin:/sbin:/system",
  203. "HOME=/", "TERM=linux", NULL};
  204. execve("/arkrt", argv, envp);
  205. /* execve only returns on failure */
  206. printf("init: FATAL — execve(/arkrt) failed!\n");
  207. _exit(1);
  208. }
  209. /*
  210. * Phase 7: PID 1 wait loop
  211. * PID 1 must NEVER exit — if it does, the kernel panics.
  212. * We wait for arkrt to exit, then hang.
  213. */
  214. int status;
  215. waitpid(pid, &status, 0);
  216. printf("init: arkrt exited (status=%d). System halted.\n", status);
  217. while (1) {
  218. sleep(1);
  219. }
  220. return 0;
  221. }