Added privilidges
This commit is contained in:
@@ -36,6 +36,7 @@ void task_init(BootInfo *Boot)
|
||||
for (i = 0; i < TASK_MAX; i++) {
|
||||
tasks[i].state = TASK_STATE_FREE;
|
||||
tasks[i].pid = 0;
|
||||
tasks[i].privilege = TASK_PRIV_USER;
|
||||
tasks[i].saved_rsp = 0;
|
||||
tasks[i].stack_base = 0;
|
||||
tasks[i].stack_pages = 0;
|
||||
@@ -51,9 +52,10 @@ void task_init(BootInfo *Boot)
|
||||
* allocate one. Its saved_rsp will be filled in during the
|
||||
* first context_switch call in task_yield().
|
||||
*/
|
||||
tasks[0].pid = next_pid++;
|
||||
tasks[0].state = TASK_STATE_RUNNING;
|
||||
tasks[0].switches = 1;
|
||||
tasks[0].pid = next_pid++;
|
||||
tasks[0].state = TASK_STATE_RUNNING;
|
||||
tasks[0].privilege = TASK_PRIV_KERNEL;
|
||||
tasks[0].switches = 1;
|
||||
wstrcpy16(tasks[0].name, L"core", TASK_NAME_LEN);
|
||||
|
||||
current_task = &tasks[0];
|
||||
@@ -66,22 +68,26 @@ void task_init(BootInfo *Boot)
|
||||
|
||||
Important points:
|
||||
|
||||
- Task 0 represents the **kernel core thread**, which uses the boot-time stack provided by the loader.
|
||||
- Task 0 represents the **kernel core thread**, which uses the boot-time stack provided by the loader. It receives `TASK_PRIV_KERNEL` privilege.
|
||||
- No stack is allocated for task 0; its `saved_rsp` is populated the first time a context switch occurs.
|
||||
- All other PCBs begin in `TASK_STATE_FREE`.
|
||||
- All other PCBs begin in `TASK_STATE_FREE` with `TASK_PRIV_USER`.
|
||||
|
||||
---
|
||||
|
||||
## Task creation and stack layout
|
||||
|
||||
New tasks are created via `task_create`, which:
|
||||
New tasks are created via `task_create_with_priv` (or its wrapper `task_create`), which:
|
||||
|
||||
1. Finds a free PCB slot.
|
||||
2. Allocates a stack from the PMM.
|
||||
3. Sets up an initial stack frame so that `context_switch` can "return" into a C trampoline function.
|
||||
1. Checks that the caller is not escalating privilege beyond its own level.
|
||||
2. Finds a free PCB slot.
|
||||
3. Allocates a stack from the PMM.
|
||||
4. Sets up an initial stack frame so that `context_switch` can "return" into a C trampoline function.
|
||||
|
||||
```121:197:/home/lochlan/Documents/Coding/c/os/task.c
|
||||
Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||
```121:211:/home/lochlan/Documents/Coding/c/os/task.c
|
||||
Task *task_create_with_priv(const CHAR16 *name,
|
||||
TaskEntryFn entry,
|
||||
void *arg,
|
||||
TaskPrivilege privilege)
|
||||
{
|
||||
Task *t = NULL;
|
||||
UINTN i;
|
||||
@@ -89,6 +95,14 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||
UINT64 *sp;
|
||||
...
|
||||
|
||||
/* Subsystem-level privilege enforcement: prevent privilege escalation. */
|
||||
{
|
||||
Task *caller = task_current();
|
||||
if (caller != NULL && privilege > task_get_privilege(caller)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find a free PCB slot */
|
||||
for (i = 0; i < TASK_MAX; i++) {
|
||||
if (tasks[i].state == TASK_STATE_FREE) {
|
||||
@@ -107,6 +121,7 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||
/* Fill in the PCB */
|
||||
t->pid = next_pid++;
|
||||
t->state = TASK_STATE_READY;
|
||||
t->privilege = privilege;
|
||||
t->entry = entry;
|
||||
t->arg = arg;
|
||||
t->switches = 0;
|
||||
@@ -154,6 +169,19 @@ Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||
}
|
||||
```
|
||||
|
||||
The convenience wrapper `task_create` inherits the calling task's privilege level:
|
||||
|
||||
```213:220:/home/lochlan/Documents/Coding/c/os/task.c
|
||||
Task *task_create(const CHAR16 *name, TaskEntryFn entry, void *arg)
|
||||
{
|
||||
/* Inherit privilege from the calling task (kernel if no task context). */
|
||||
Task *caller = task_current();
|
||||
TaskPrivilege priv = (caller != NULL) ? task_get_privilege(caller)
|
||||
: TASK_PRIV_KERNEL;
|
||||
return task_create_with_priv(name, entry, arg, priv);
|
||||
}
|
||||
```
|
||||
|
||||
The effective stack layout (low to high addresses) after `task_create` is:
|
||||
|
||||
- Saved `flags`, `r15`, `r14`, `r13`, `r12`, `rbx`, `rbp` (pushed by `context_switch` semantics).
|
||||
@@ -367,7 +395,7 @@ Because the scheduler is cooperative, this **busy-wait** loop is benign: it yiel
|
||||
Example usage from the Starling Terminal:
|
||||
|
||||
```135:140:/home/lochlan/Documents/Coding/c/os/kernel.c
|
||||
Task *cmd_task = execute_command(Boot, line);
|
||||
Task *cmd_task = execute_command(Boot, line, shell_priv);
|
||||
|
||||
/* If a command task was spawned, wait for it to finish. */
|
||||
if (cmd_task != NULL) {
|
||||
@@ -379,25 +407,34 @@ if (cmd_task != NULL) {
|
||||
|
||||
## Task inspection (`ps` and `tasktest`)
|
||||
|
||||
The `ps` command uses `task_print_list` to show current tasks:
|
||||
The `ps` command uses `task_print_list` to show current tasks. Access requires at least `TASK_PRIV_DRIVER`:
|
||||
|
||||
```366:389:/home/lochlan/Documents/Coding/c/os/task.c
|
||||
```407:439:/home/lochlan/Documents/Coding/c/os/task.c
|
||||
void task_print_list(BootInfo *Boot)
|
||||
{
|
||||
UINTN i;
|
||||
Task *caller;
|
||||
|
||||
/* Subsystem-level privilege enforcement: task list requires DRIVER. */
|
||||
caller = task_current();
|
||||
if (caller != NULL && task_get_privilege(caller) < TASK_PRIV_DRIVER) {
|
||||
SAFE_PRINT(Boot, L"Permission denied: task list requires driver privilege.\n\r");
|
||||
return;
|
||||
}
|
||||
|
||||
SAFE_PRINT(Boot, L"\n\r");
|
||||
SAFE_PRINT(Boot, L" PID STATE SWITCHES NAME\n\r");
|
||||
SAFE_PRINT(Boot, L" --- ---------- -------- ----\n\r");
|
||||
SAFE_PRINT(Boot, L" PID STATE PRIV SWITCHES NAME\n\r");
|
||||
SAFE_PRINT(Boot, L" --- ---------- ---- -------- ----\n\r");
|
||||
|
||||
for (i = 0; i < TASK_MAX; i++) {
|
||||
if (tasks[i].state == TASK_STATE_FREE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SAFE_PRINT(Boot, L" %3d %-10s %8d %s\n\r",
|
||||
SAFE_PRINT(Boot, L" %3d %-10s %4d %8d %s\n\r",
|
||||
tasks[i].pid,
|
||||
state_str(tasks[i].state),
|
||||
(INT32)tasks[i].privilege,
|
||||
tasks[i].switches,
|
||||
tasks[i].name);
|
||||
}
|
||||
@@ -444,3 +481,28 @@ Each worker task:
|
||||
|
||||
This demonstrates how cooperative tasks interleave output and how `task_yield` drives scheduling.
|
||||
|
||||
---
|
||||
|
||||
## Privilege system
|
||||
|
||||
Each task carries a `TaskPrivilege` level defined in `task.h`:
|
||||
|
||||
```47:52:/home/lochlan/Documents/Coding/c/os/task.h
|
||||
typedef enum {
|
||||
TASK_PRIV_USER = 0,
|
||||
TASK_PRIV_DRIVER = 1,
|
||||
TASK_PRIV_KERNEL = 2,
|
||||
} TaskPrivilege;
|
||||
```
|
||||
|
||||
All tasks still execute in CPU ring 0; this is a **software-only** hierarchy used for access control decisions:
|
||||
|
||||
- `task_create_with_priv` prevents a caller from creating a task with a higher privilege than its own.
|
||||
- Subsystem functions like `memory_print_stats`, `task_print_list`, and `request_shutdown` check the calling task's privilege before proceeding.
|
||||
- The `kusr` command (`commands.c`) temporarily elevates a task to `TASK_PRIV_KERNEL` to run a privileged sub-command, then restores the original level.
|
||||
|
||||
Accessors:
|
||||
|
||||
- `task_get_privilege(Task *t)` – returns the task's current privilege level.
|
||||
- `task_set_privilege(Task *t, TaskPrivilege p)` – changes it (no enforcement; callers are responsible).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user