| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- //
- // Copyright 2026 Aarav Ravindra Kharade
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- /*
- * ArkOS Init (PID 1)
- * ------------------
- * The first userspace process, responsible for:
- *
- * 1. Mounting essential filesystems (devtmpfs, proc, sysfs)
- * 2. Setting up console I/O (stdin, stdout, stderr)
- * 3. Mounting tmpfs for /tmp, /run (with security flags)
- * 4. Setting a safe umask
- * 5. Verifying the OS runtime signature (Verified Boot)
- * 6. Launching arkrt (the ArkOS Runtime Daemon) as PID 2
- * 7. Waiting forever (PID 1 must never exit)
- *
- * Security:
- * - /tmp is mounted with noexec,nosuid to prevent privilege escalation
- * - Verified Boot checks SHA256(KEY + arkrt) against signature.bin
- * - Console output is suppressed for kernel messages after boot
- *
- * This file is compiled with: gcc -static -DARK_KEY="..." init.c sha256.c
- */
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/mount.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include "../../vendor/verify/sha256.h"
- /* Verified Boot signing key (injected at compile time by the build system) */
- #ifndef ARK_KEY
- #define ARK_KEY "UNKNOWN_KEY"
- #endif
- /* ── Kernel Panic Handler ──────────────────────────────────────── */
- /**
- * Displays a kernel panic message and halts the system.
- * Called when Verified Boot fails or a critical error occurs.
- * This function never returns.
- */
- void trigger_kernel_panic(const char *msg) {
- printf("\n");
- printf("======================================================\n");
- printf(" KERNEL PANIC \n");
- printf(" Please reboot your computer. \n");
- printf("======================================================\n");
- printf("VFS: Unable to mount root fs on unknown-block(0,0)\n");
- printf("ArkOS Verified Boot: %s\n", msg);
- fflush(stdout);
- /* Halt forever — PID 1 must never exit */
- while (1) {
- sleep(1);
- }
- }
- /* ── Verified Boot ─────────────────────────────────────────────── */
- /**
- * Verifies the integrity of the arkrt binary using HMAC-SHA256.
- *
- * Algorithm:
- * 1. Read the expected signature from /signature.bin (64-char hex)
- * 2. Read the entire /arkrt binary into memory
- * 3. Compute SHA256(ARK_KEY + arkrt_bytes)
- * 4. Compare computed hash against the expected signature
- *
- * Returns 1 on success, calls trigger_kernel_panic() on failure.
- */
- int verify_os_signature(void) {
- /* Read the expected signature (64 hex characters) */
- int sig_fd = open("/signature.bin", O_RDONLY);
- if (sig_fd < 0) {
- trigger_kernel_panic("Missing signature.bin!");
- return 0;
- }
- char expected_sig[65] = {0};
- read(sig_fd, expected_sig, 64);
- close(sig_fd);
- /* Read the arkrt binary */
- int os_fd = open("/arkrt", O_RDONLY);
- if (os_fd < 0) {
- trigger_kernel_panic("Missing /arkrt OS binary!");
- return 0;
- }
- struct stat st;
- fstat(os_fd, &st);
- uint8_t *os_data = malloc(st.st_size);
- if (!os_data) {
- trigger_kernel_panic("Out of memory during verification!");
- return 0;
- }
- /* Read entire binary (handle partial reads) */
- size_t total_read = 0;
- while (total_read < (size_t)st.st_size) {
- ssize_t r = read(os_fd, os_data + total_read, st.st_size - total_read);
- if (r <= 0)
- break;
- total_read += r;
- }
- close(os_fd);
- /* Compute SHA256(KEY + binary_data) */
- SHA256_CTX ctx;
- sha256_init(&ctx);
- sha256_update(&ctx, (const uint8_t *)ARK_KEY, strlen(ARK_KEY));
- sha256_update(&ctx, os_data, st.st_size);
- uint8_t hash[32];
- sha256_final(&ctx, hash);
- free(os_data);
- /* Convert binary hash to hex string for comparison */
- char computed_sig[65] = {0};
- for (int i = 0; i < 32; i++) {
- sprintf(&computed_sig[i * 2], "%02x", hash[i]);
- }
- /* Constant-time comparison would be better, but this is boot-time only */
- if (strncmp(expected_sig, computed_sig, 64) != 0) {
- printf("Expected: %s\n", expected_sig);
- printf("Computed: %s\n", computed_sig);
- trigger_kernel_panic(
- "Signature mismatch! System may be compromised.");
- return 0;
- }
- return 1;
- }
- /* ── Main ──────────────────────────────────────────────────────── */
- int main(void) {
- /*
- * Phase 1: Mount essential kernel filesystems
- * These must be available before anything else can work.
- */
- mkdir("/dev", 0755);
- mkdir("/proc", 0755);
- mkdir("/sys", 0755);
- mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
- mount("proc", "/proc", "proc", 0, NULL);
- mount("sysfs", "/sys", "sysfs", 0, NULL);
- /*
- * Phase 2: Set up console I/O
- * Redirect stdin/stdout/stderr to /dev/console so print() works.
- */
- int fd = open("/dev/console", O_RDWR);
- if (fd >= 0) {
- dup2(fd, 0); /* stdin */
- dup2(fd, 1); /* stdout */
- dup2(fd, 2); /* stderr */
- if (fd > 2)
- close(fd);
- }
- /*
- * Phase 3: Security setup
- * - Set umask to 022 (files: 644, dirs: 755 by default)
- * - Mount /tmp with noexec,nosuid to prevent privilege escalation
- * - Mount /dev/shm for POSIX shared memory
- * - Create /run for PID files
- */
- umask(0022);
- mkdir("/tmp", 01777);
- mount("tmpfs", "/tmp", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
- "size=64m,mode=1777");
- mkdir("/dev/shm", 01777);
- mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_NODEV, "size=64m");
- mkdir("/run", 0755);
- mount("tmpfs", "/run", "tmpfs", MS_NOSUID | MS_NODEV, "size=8m");
- mkdir("/var", 0755);
- mkdir("/var/log", 0755);
- mkdir("/etc", 0755);
- /*
- * Phase 4: Hide kernel boot messages and prepare display
- * - Set terminal to KD_GRAPHICS to prevent fbcon from interfering
- * - Set terminal background to black
- * - Clear the screen
- * - Hide the cursor
- * This prevents the white flash between kernel boot and splash screen.
- */
- int tty_fd = open("/dev/tty0", O_RDWR);
- if (tty_fd >= 0) {
- /* Clear screen and hide cursor on the physical display */
- write(tty_fd, "\033[0;40m\033[2J\033[H\033[?25l", 20);
- ioctl(tty_fd, 0x4B3A, 1); /* KDSETMODE, KD_GRAPHICS */
- close(tty_fd);
- }
- /*
- * Phase 5: Verified Boot
- * Compute HMAC-SHA256 of the arkrt binary and compare against
- * the pre-signed signature. Panics if verification fails.
- */
- verify_os_signature();
- /*
- * Phase 6: Launch the ArkOS Runtime Daemon (arkrt)
- * arkrt becomes PID 2 and manages all system services.
- * Its stdout/stderr go to /dev/ttyS0 (serial console for debugging).
- */
- pid_t pid = fork();
- if (pid == 0) {
- /* Child process — redirect to serial console for debug output */
- int sfd = open("/dev/ttyS0", O_RDWR);
- if (sfd >= 0) {
- dup2(sfd, 0);
- dup2(sfd, 1);
- dup2(sfd, 2);
- if (sfd > 2)
- close(sfd);
- }
- char *argv[] = {"/arkrt", NULL};
- char *envp[] = {"PATH=/bin:/usr/bin:/sbin:/system",
- "HOME=/", "TERM=linux", NULL};
- execve("/arkrt", argv, envp);
- /* execve only returns on failure */
- printf("init: FATAL — execve(/arkrt) failed!\n");
- _exit(1);
- }
- /*
- * Phase 7: PID 1 wait loop
- * PID 1 must NEVER exit — if it does, the kernel panics.
- * We wait for arkrt to exit, then hang.
- */
- int status;
- waitpid(pid, &status, 0);
- printf("init: arkrt exited (status=%d). System halted.\n", status);
- while (1) {
- sleep(1);
- }
- return 0;
- }
|