Files
nt-lite/code/user/system/init/init.c
T

422 lines
17 KiB
C

// Init service manager. The kernel bootstraps only init; init starts and supervises user-mode system services.
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <ntlite/exception.h>
#include <ntlite/process_loader.h>
#include <ntlite/resource.h>
#include <ntlite/security.h>
#include <ntlite/service_control.h>
#include <ntlite/syscall.h>
#define INIT_SERVICE_READY_TIMEOUT_MS 5000u
#define INIT_SERVICE_STOP_TIMEOUT_MS 5000u
typedef struct INIT_RESOURCE_SERVICE {
SYS_HANDLE Process;
SYS_HANDLE ControlEndpoint;
SYS_HANDLE AdminListener;
} INIT_RESOURCE_SERVICE;
// Writes one string through the privileged kernel debug channel.
static void debug_print(const char* text) {
SYS_PRINT_DEBUG_REQUEST request = { sizeof(request), SysSvFromCstr(text) };
(void)SysPrintDebug(&request);
}
// Writes one status value in hexadecimal without pulling in a formatting runtime.
static void debug_status(KSTATUS status) {
static const char digits[] = "0123456789ABCDEF";
char buffer[11] = "0x00000000";
for (uint32_t i = 0; i < 8; ++i)
buffer[2 + i] = digits[(status >> ((7u - i) * 4u)) & 0xFu];
debug_print(buffer);
}
// Exits init without relying on a compiler runtime return path.
static void exit_now(int code) {
for (;;) SysExitProcess(code);
}
// Derives the least-privileged security context required by RSSRV.
static KSTATUS derive_resource_service_context(SYS_HANDLE* contextOut) {
if (!contextOut) return NTLSTATUS_INVALID_PARAMETER;
*contextOut = SYS_HANDLE_INVALID;
SYS_DERIVE_SECURITY_CONTEXT_REQUEST request;
memset(&request, 0, sizeof(request));
request.Size = sizeof(request);
request.SourceContext = SYS_SECURITY_CONTEXT_CURRENT;
request.EffectivePrivileges = SYS_PRIV_SYSTEM_SERVICE_REGISTER;
request.DelegablePrivileges = 0;
request.ServiceClaims = SYS_SERVICE_CLAIM_RESOURCE;
request.DelegableServiceClaims = 0;
request.Flags = SYS_SECURITY_CONTEXT_FLAG_NONE;
request.ContextHandleOut = contextOut;
return SysDeriveSecurityContext(&request);
}
// Creates one private Port listener used only between init and a managed service.
static KSTATUS create_control_listener(SYS_HANDLE* listenerOut) {
SYS_CREATE_PORT_REQUEST request;
memset(&request, 0, sizeof(request));
request.Size = sizeof(request);
request.Flags = SYS_PORT_FLAG_NONE;
request.Backlog = 1;
request.HandleOut = listenerOut;
return SysCreatePort(&request);
}
// Connects init to the private control listener delegated to the child.
static KSTATUS connect_control_listener(SYS_HANDLE listener, SYS_HANDLE* endpointOut) {
SYS_CONNECT_PORT_REQUEST request;
memset(&request, 0, sizeof(request));
request.Size = sizeof(request);
request.ListenerHandle = listener;
request.Flags = SYS_PORT_CONNECT_FLAG_NONE;
request.EndpointHandleOut = endpointOut;
return SysConnectPort(&request);
}
// Waits for RSSRV readiness and receives its private administrative namespace listener.
static KSTATUS wait_resource_service_ready(SYS_HANDLE controlEndpoint, SYS_HANDLE* adminListenerOut) {
if (!adminListenerOut) return NTLSTATUS_INVALID_PARAMETER;
*adminListenerOut = SYS_HANDLE_INVALID;
NTL_SERVICE_CONTROL_MESSAGE message;
SYS_PORT_MESSAGE_INFO info;
SYS_HANDLE adminListener = SYS_HANDLE_INVALID;
memset(&message, 0, sizeof(message));
memset(&info, 0, sizeof(info));
info.Size = sizeof(info);
SYS_RECEIVE_PORT_REQUEST receive;
memset(&receive, 0, sizeof(receive));
receive.Size = sizeof(receive);
receive.EndpointHandle = controlEndpoint;
receive.Flags = SYS_PORT_FLAG_NONE;
receive.Payload = &message;
receive.PayloadCapacity = sizeof(message);
receive.HandlesOut = &adminListener;
receive.HandleCapacity = 1;
receive.InfoOut = &info;
receive.TimeoutMilliseconds = INIT_SERVICE_READY_TIMEOUT_MS;
KSTATUS status = SysReceivePort(&receive);
if (!KSUCCESS(status)) return status;
if (info.Type != SYS_PORT_MESSAGE_NOTIFICATION || info.PayloadLength != sizeof(message) ||
info.HandleCount != 1 || adminListener == SYS_HANDLE_INVALID ||
message.Size != sizeof(message) || message.Version != NTL_SERVICE_CONTROL_VERSION ||
message.Operation != NTL_SERVICE_CONTROL_READY ||
message.Flags != NTL_SERVICE_READY_FLAG_RESOURCE_ADMIN_LISTENER ||
!KSUCCESS(message.Status)) {
if (adminListener != SYS_HANDLE_INVALID) (void)SysCloseHandle(adminListener);
return NTLSTATUS_FAILURE;
}
*adminListenerOut = adminListener;
return NTLSTATUS_SUCCESS;
}
// Verifies private namespace administration and public /SystemRoot lookup before declaring RSSRV usable.
static KSTATUS verify_resource_service(SYS_HANDLE adminListener, SYS_HANDLE namespaceVolume) {
SYS_HANDLE admin = SYS_HANDLE_INVALID;
KSTATUS status = NtlResourceConnectListener(adminListener, &admin);
if (!KSUCCESS(status)) return status;
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
status = NtlResourceQuery(admin, SYS_SV_LITERAL("/SystemRoot"), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_VOLUME) {
(void)NtlResourceClose(admin);
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
}
// Exercise capability-based administration without leaving a bootstrap-only namespace entry behind.
status = NtlResourceBind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"),
NTL_RESOURCE_KIND_VOLUME, namespaceVolume,
SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN,
SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN);
if (!KSUCCESS(status)) {
(void)NtlResourceClose(admin);
return status;
}
SYS_HANDLE publicSession = SYS_HANDLE_INVALID;
status = NtlResourceConnect(&publicSession);
if (!KSUCCESS(status)) {
(void)NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
(void)NtlResourceClose(admin);
return status;
}
SYS_HANDLE volume = SYS_HANDLE_INVALID;
status = NtlResourceLookup(publicSession, SYS_SV_LITERAL("/SystemRoot"),
SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN, &volume);
if (KSUCCESS(status)) (void)SysCloseHandle(volume);
if (!KSUCCESS(status)) {
(void)NtlResourceClose(publicSession);
(void)NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
(void)NtlResourceClose(admin);
return status;
}
kind = NTL_RESOURCE_KIND_INVALID;
status = NtlResourceQuery(publicSession, SYS_SV_LITERAL("/Init/BootstrapProbe"), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_VOLUME) {
(void)NtlResourceClose(publicSession);
(void)NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
(void)NtlResourceClose(admin);
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
}
status = NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
if (KSUCCESS(status)) {
kind = NTL_RESOURCE_KIND_INVALID;
KSTATUS queryStatus = NtlResourceQuery(publicSession, SYS_SV_LITERAL("/Init/BootstrapProbe"), &kind);
if (queryStatus != NTLSTATUS_NOT_FOUND) status = NTLSTATUS_FAILURE;
}
(void)NtlResourceClose(publicSession);
(void)NtlResourceClose(admin);
return status;
}
// Tears down retained parent-side service handles without sending a stop message.
static void close_resource_service(INIT_RESOURCE_SERVICE* service) {
if (!service) return;
if (service->ControlEndpoint != SYS_HANDLE_INVALID) {
(void)SysDisconnectPort(service->ControlEndpoint);
(void)SysCloseHandle(service->ControlEndpoint);
}
if (service->AdminListener != SYS_HANDLE_INVALID)
(void)SysCloseHandle(service->AdminListener);
if (service->Process != SYS_HANDLE_INVALID)
(void)SysCloseHandle(service->Process);
service->Process = SYS_HANDLE_INVALID;
service->ControlEndpoint = SYS_HANDLE_INVALID;
service->AdminListener = SYS_HANDLE_INVALID;
}
// Starts one restricted, import-free RSSRV instance through the userspace process loader.
static KSTATUS start_resource_service(SYS_HANDLE systemVolume,
SYS_HANDLE namespaceVolume,
SYS_HANDLE volumeManager,
SYS_HANDLE resourceContext,
INIT_RESOURCE_SERVICE* serviceOut) {
if (!serviceOut) return NTLSTATUS_INVALID_PARAMETER;
memset(serviceOut, 0, sizeof(*serviceOut));
SYS_HANDLE controlListener = SYS_HANDLE_INVALID;
KSTATUS status = create_control_listener(&controlListener);
if (!KSUCCESS(status)) return status;
NTL_PROCESS_STARTUP_CAPABILITY startup[3];
memset(startup, 0, sizeof(startup));
startup[0].Tag = SYS_STARTUP_CAP_SYSTEM_VOLUME_NAMESPACE;
startup[0].SourceHandle = namespaceVolume;
startup[0].DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_TRANSFER |
SYS_VOLUME_RIGHT_OPEN | SYS_VOLUME_RIGHT_MODIFY;
startup[0].DuplicateFlags = SYS_DUPLICATE_HANDLE_FLAG_NONE;
startup[1].Tag = SYS_STARTUP_CAP_SERVICE_CONTROL;
startup[1].SourceHandle = controlListener;
startup[1].DesiredRights = SYS_RIGHT_QUERY | SYS_PORT_RIGHT_ACCEPT;
startup[1].DuplicateFlags = SYS_DUPLICATE_HANDLE_FLAG_NONE;
startup[2].Tag = SYS_STARTUP_CAP_VOLUME_MANAGER;
startup[2].SourceHandle = volumeManager;
startup[2].DesiredRights = SYS_RIGHT_QUERY |
SYS_VOLUME_MANAGER_RIGHT_ENUMERATE | SYS_VOLUME_MANAGER_RIGHT_OPEN |
SYS_VOLUME_MANAGER_RIGHT_WAIT;
startup[2].DuplicateFlags = SYS_DUPLICATE_HANDLE_FLAG_NONE;
SYS_HANDLE process = SYS_HANDLE_INVALID;
NTL_CREATE_PROCESS_AT_REQUEST create;
memset(&create, 0, sizeof(create));
create.Size = sizeof(create);
create.Flags = NTL_PROCESS_LOAD_FLAG_NONE;
create.RootHandle = systemVolume;
create.Path = SYS_SV_LITERAL("system/rssrv.exe");
create.CommandLine = SYS_SV_LITERAL("system/rssrv.exe");
create.SecurityContext = resourceContext;
create.ModuleRootHandle = systemVolume;
create.ModuleDirectory = SYS_SV_LITERAL("system");
create.ResolveModuleName = NtlResolveModuleNameIdentity;
create.ResolveContext = (void*)0;
create.StartupCapabilities = startup;
create.StartupCapabilityCount = 3;
create.ProcessHandleOut = &process;
status = NtlCreateProcessAt(&create);
if (!KSUCCESS(status)) {
(void)SysCloseHandle(controlListener);
return status;
}
SYS_HANDLE controlEndpoint = SYS_HANDLE_INVALID;
status = connect_control_listener(controlListener, &controlEndpoint);
(void)SysCloseHandle(controlListener);
if (!KSUCCESS(status)) {
(void)SysKillProcess(process, 1);
(void)SysCloseHandle(process);
return status;
}
SYS_HANDLE adminListener = SYS_HANDLE_INVALID;
status = wait_resource_service_ready(controlEndpoint, &adminListener);
if (KSUCCESS(status))
status = verify_resource_service(adminListener, namespaceVolume);
if (!KSUCCESS(status)) {
if (adminListener != SYS_HANDLE_INVALID) (void)SysCloseHandle(adminListener);
(void)SysDisconnectPort(controlEndpoint);
(void)SysCloseHandle(controlEndpoint);
(void)SysKillProcess(process, 1);
(void)SysCloseHandle(process);
return status;
}
serviceOut->Process = process;
serviceOut->ControlEndpoint = controlEndpoint;
serviceOut->AdminListener = adminListener;
return NTLSTATUS_SUCCESS;
}
// Requests graceful RSSRV shutdown, falling back to process termination if it stops responding.
static void stop_resource_service(INIT_RESOURCE_SERVICE* service) {
if (!service || service->Process == SYS_HANDLE_INVALID) return;
NTL_SERVICE_CONTROL_MESSAGE message;
memset(&message, 0, sizeof(message));
message.Size = sizeof(message);
message.Version = NTL_SERVICE_CONTROL_VERSION;
message.Operation = NTL_SERVICE_CONTROL_STOP;
SYS_SEND_PORT_REQUEST send;
memset(&send, 0, sizeof(send));
send.Size = sizeof(send);
send.EndpointHandle = service->ControlEndpoint;
send.Flags = SYS_PORT_FLAG_NONE;
send.Payload = &message;
send.PayloadLength = sizeof(message);
send.TimeoutMilliseconds = INIT_SERVICE_STOP_TIMEOUT_MS;
(void)SysSendPort(&send);
KSTATUS status = SysWaitSingle(service->Process, SYS_WAIT_FLAG_NONE, INIT_SERVICE_STOP_TIMEOUT_MS);
if (!KSUCCESS(status)) {
(void)SysKillProcess(service->Process, 1);
(void)SysWait(service->Process, SYS_WAIT_FLAG_NONE);
}
close_resource_service(service);
}
// Starts the configured native session child directly beneath the system-volume capability.
static KSTATUS start_configured_child(SYS_HANDLE systemVolume, SYS_STRING_VIEW path, SYS_HANDLE* processOut) {
NTL_CREATE_PROCESS_AT_REQUEST create;
memset(&create, 0, sizeof(create));
create.Size = sizeof(create);
create.Flags = NTL_PROCESS_LOAD_FLAG_NONE;
create.RootHandle = systemVolume;
create.Path = path;
create.CommandLine = path;
create.SecurityContext = SYS_SECURITY_CONTEXT_CURRENT;
create.ModuleRootHandle = systemVolume;
create.ModuleDirectory = SYS_SV_LITERAL("system");
create.ResolveModuleName = NtlResolveSystemModuleName;
create.ProcessHandleOut = processOut;
return NtlCreateProcessAt(&create);
}
// Initializes init state and supervises RSSRV plus the configured session process.
void _start(void) {
KSTATUS status = NtlInitializeExceptionRuntime();
if (!KSUCCESS(status)) exit_now((int)status);
SYS_HANDLE systemVolume = SysGetStartupCapability(SYS_STARTUP_CAP_SYSTEM_VOLUME);
SYS_HANDLE namespaceVolume = SysGetStartupCapability(SYS_STARTUP_CAP_SYSTEM_VOLUME_NAMESPACE);
SYS_HANDLE volumeManager = SysGetStartupCapability(SYS_STARTUP_CAP_VOLUME_MANAGER);
if (systemVolume == SYS_HANDLE_INVALID || namespaceVolume == SYS_HANDLE_INVALID ||
volumeManager == SYS_HANDLE_INVALID) {
debug_print("[init] FATAL: bootstrap storage capability missing\n");
exit_now(1);
}
SYS_HANDLE resourceContext = SYS_HANDLE_INVALID;
status = derive_resource_service_context(&resourceContext);
if (!KSUCCESS(status)) {
debug_print("[init] FATAL: cannot derive RSSRV security context: ");
debug_status(status);
debug_print("\n");
exit_now(1);
}
SYS_STRING_VIEW childPath = SysGetPeb()->CommandLine;
if (!childPath.Data || childPath.Length == 0) {
debug_print("[init] FATAL: no configured session process\n");
exit_now(1);
}
for (;;) {
INIT_RESOURCE_SERVICE resourceService;
status = start_resource_service(systemVolume, namespaceVolume, volumeManager, resourceContext, &resourceService);
if (!KSUCCESS(status)) {
debug_print("[init] FATAL: RSSRV startup failed: ");
debug_status(status);
debug_print("\n");
exit_now(1);
}
debug_print("[init] RSSRV ready\n");
for (;;) {
SYS_HANDLE child = SYS_HANDLE_INVALID;
status = start_configured_child(systemVolume, childPath, &child);
if (!KSUCCESS(status)) {
debug_print("[init] FATAL: failed to start configured child: ");
debug_status(status);
debug_print("\n");
stop_resource_service(&resourceService);
exit_now(1);
}
debug_print("[init] session process started\n");
SYS_HANDLE waits[2] = { resourceService.Process, child };
uint32_t signaled = 0;
SYS_WAIT_MANY_REQUEST wait;
memset(&wait, 0, sizeof(wait));
wait.Size = sizeof(wait);
wait.Flags = SYS_WAIT_FLAG_NONE;
wait.Handles = waits;
wait.Count = 2;
wait.SignaledIndexOut = &signaled;
wait.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
status = SysWaitMany(&wait);
if (!KSUCCESS(status)) {
(void)SysKillProcess(child, 1);
(void)SysCloseHandle(child);
stop_resource_service(&resourceService);
debug_print("[init] FATAL: service wait failed\n");
exit_now(1);
}
if (signaled == 0) {
int32_t serviceExit = -1;
(void)SysGetProcessExitCode(resourceService.Process, &serviceExit);
debug_print("[init] RSSRV exited unexpectedly; restarting service plane\n");
(void)SysKillProcess(child, 1);
(void)SysWait(child, SYS_WAIT_FLAG_NONE);
(void)SysCloseHandle(child);
close_resource_service(&resourceService);
break;
}
int32_t exitCode = -1;
status = SysGetProcessExitCode(child, &exitCode);
(void)SysCloseHandle(child);
if (!KSUCCESS(status)) exitCode = 1;
if (exitCode == 0) {
stop_resource_service(&resourceService);
debug_print("[init] done\n");
(void)SysCloseHandle(resourceContext);
exit_now(0);
}
debug_print("[init] session process crashed; restarting\n");
}
}
}