1
0

init.c 8.4 KB

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