# The Ultimate Aim of Kernel Exploitation - Process Credentials

## Overview

Userspace exploitation often has the end goal of code execution. In the case of kernel exploitation, we already have code execution; our aim is to escalate privileges, so that when we spawn a shell (or do anything else) using `execve("/bin/sh", NULL, NULL)` we are dropped as `root`.

To understand this, we have a talk a little about how privileges and credentials work in Linux.

## The cred struct

The [`cred` struct](https://elixir.bootlin.com/linux/v6.1/source/include/linux/cred.h#L110) contains all the permissions a task holds. The ones that we care about are typically these:

```c
struct cred {
	/* ... */
	
	kuid_t		uid;		/* real UID of the task */
	kgid_t		gid;		/* real GID of the task */
	kuid_t		suid;		/* saved UID of the task */
	kgid_t		sgid;		/* saved GID of the task */
	kuid_t		euid;		/* effective UID of the task */
	kgid_t		egid;		/* effective GID of the task */
	kuid_t		fsuid;		/* UID for VFS ops */
	kgid_t		fsgid;		/* GID for VFS ops */
	
	/* ... */
} __randomize_layout;
```

These fields are all `unsigned int` fields, and they represent what you would expect - the UID, GID, and a few other less common IDs for other operations (such as the FSUID, which is checked when accessing a file on the file system). As you can expect, overwriting one or more of these fields is likely a pretty desirable goal.

{% hint style="info" %}
Note the `__randomize_layout` here at the end! This is a compiler flag that tells it to mix the layout up on each load, making it harder to target the structure!
{% endhint %}

## task\_struct

The kernel needs to store information about each running task, and to do this it uses the [`task_struct` ](https://elixir.bootlin.com/linux/v6.1/source/include/linux/sched.h#L737)structure. Each kernel task has its own instance.

{% code fullWidth="false" %}

```c
struct task_struct {
    	/* ... */
    
	/*
	 * Pointers to the (original) parent process, youngest child, younger sibling,
	 * older sibling, respectively.  (p->father can be replaced with
	 * p->real_parent->pid)
	 */

	/* Real parent process: */
	struct task_struct __rcu	*real_parent;

	/* Recipient of SIGCHLD, wait4() reports: */
	struct task_struct __rcu	*parent;

	/*
	 * Children/sibling form the list of natural children:
	 */
	struct list_head		children;
	struct list_head		sibling;
	struct task_struct		*group_leader;

	/* ... */    

	/* Objective and real subjective task credentials (COW): */
	const struct cred __rcu		*real_cred;

	/* Effective (overridable) subjective task credentials (COW): */
	const struct cred __rcu		*cred;

    	/* ... */
};
```

{% endcode %}

The `task_struct` instances are stored in a linked list, with a global kernel variable `init_task` pointing to the first one. Each `task_struct` then points to the next.

Along with linking data, the `task_struct` also (more importantly) stores `real_cred` and `cred`, which are both pointers to a `cred` struct. The difference between the two is explained [here](https://elixir.bootlin.com/linux/v5.10.220/source/include/linux/cred.h#L88):

```c
/*
 * The security context of a task
 *
 * The parts of the context break down into two categories:
 *
 *  (1) The objective context of a task.  These parts are used when some other
 *	task is attempting to affect this one.
 *
 *  (2) The subjective context.  These details are used when the task is acting
 *	upon another object, be that a file, a task, a key or whatever.
 *
 * Note that some members of this structure belong to both categories - the
 * LSM security pointer for instance.
 *
 * A task has two security pointers.  task->real_cred points to the objective
 * context that defines that task's actual details.  The objective part of this
 * context is used whenever that task is acted upon.
 *
 * task->cred points to the subjective context that defines the details of how
 * that task is going to act upon another object.  This may be overridden
 * temporarily to point to another security context, but normally points to the
 * same context as task->real_cred.
 */
```

In effect, `real_cred` is the **initial** credential of the process, and is used by processes acting **on** the process. `cred` is the **current** credential, used to define what the process is allowed to do. We have to keep track of both as some processes care about the initial cred and some about the updated.

An example of caring about the `real_cred` instead of `cred` is in [the implementation](https://elixir.bootlin.com/linux/v6.15.7/source/fs/proc/base.c#L1887) of `/proc/$PID/status`, which displays the `real_cred` as the owner of a process, even if privileges are elevated (note that [`__task_struct`](https://elixir.bootlin.com/linux/v6.15.7/source/include/linux/cred.h#L284) is a macro to grab `real_cred`, confusingly). Conversely, **setuid** executables will modify `cred` and not `real_cred`.

So, which set of credentials do we want to target with an arbitrary write? It will depend on what set is relevant for the purpose, but since you usually want to do be creating new processes (through `system` or `execve`), the `cred` is used. In some cases, `real_cred` will work too, because it seems as if the pointers [initially point to the same struct](https://elixir.bootlin.com/linux/v6.15.7/source/kernel/cred.c#L344) (though note that this excerpt is not from process creation but [`copy_process`](https://elixir.bootlin.com/linux/v6.15.7/source/kernel/fork.c#L2294), which is [called by the `fork` syscall](https://elixir.bootlin.com/linux/v6.15.7/source/kernel/fork.c#L2804), so it could differ for new process creation).

## prepare\_kernel\_cred() and commit\_creds()

As an alternative to overwriting `cred` structs in the unpredictable kernel heap, we can call `prepare_kernel_cred()` to generate a new valid `cred` struct and `commit_creds()` to overwrite the `real_cred` and `cred` of the current `task_struct`.

### prepare\_kernel\_cred()

The function can be found [here](https://elixir.bootlin.com/linux/v6.1/source/kernel/cred.c#L712), but there's not much to say - it creates a new `cred` struct called `new` then [destroys the `old`](https://elixir.bootlin.com/linux/v6.1/source/kernel/cred.c#L135). It returns `new`.

If NULL is passed as the argument, it will [return a new set of credentials that match the `init_task` credentials](https://elixir.bootlin.com/linux/v6.1/source/kernel/cred.c#L725), which [default to root credentials](https://elixir.bootlin.com/linux/v6.1/source/kernel/cred.c#L41). This is very important, as it means that calling `prepare_kernel_cred(0)` results in a new set of root creds!

{% hint style="warning" %}
This last part is different on newer kernel versions - check out [Debugging the Kernel Module](https://ir0nstone.gitbook.io/notes/binexp/kernel/debugging-a-kernel-module) section!
{% endhint %}

### commit\_creds()

This function is found [here](https://elixir.bootlin.com/linux/v6.1/source/kernel/cred.c#L447), but ultimately it will update `task->real_cred` and `task->cred` to the new credentials:

```c
rcu_assign_pointer(task->real_cred, new);
rcu_assign_pointer(task->cred, new);
```

## Resources and References

* [Xarkes' Baby Kernel 2 writeup](https://xarkes.com/b/hacklu-2019-babykernel-wu.html)
* [TeamItaly's FamilyRecipes writeup](https://github.com/TeamItaly/TeamItalyCTF-2022/blob/master/FamilyRecipes/README.md)
