# How Dopamine Manipulates Process Credentials (kauth_cred Operations) in iOS Jailbreak

> Discover how Dopamine manipulates process credentials by adjusting kernel memory and swapping ucred pointers. Understand kauth_cred operations in iOS jailbreaks.

- Repository: [Lars Fröder/Dopamine](https://github.com/opa334/Dopamine)
- Tags: internals
- Published: 2026-08-12

---

**Dopamine manipulates process credentials by reading `kauth_cred` structures from kernel memory, adjusting reference counts through atomic operations, and swapping `ucred` pointers between processes while handling iOS version differences between `proc` and `proc_ro` layouts.**

The **libjailbreak** component in [opa334/Dopamine](https://github.com/opa334/Dopamine) provides a complete abstraction layer for `kauth_cred` operations. This subsystem enables elevated privilege operations by working directly with the kernel's credential structures that control UID/GID identity, group memberships, and privilege flags.

## Reading Process Credentials Across iOS Versions

Dopamine's credential manipulation begins with safely reading a process's `ucred` pointer. In [`BaseBin/libjailbreak/src/kernel.c`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/kernel.c), the `proc_ucred()` function handles semantic differences between iOS versions:

```c
uint64_t proc_ucred(uint64_t proc) {
    if (gSystemInfo.kernelStruct.proc_ro.exists) {
        uint64_t proc_ro = kread_ptr(proc + koffsetof(proc, proc_ro));
        return kread_ptr(proc_ro + koffsetof(proc_ro, ucred));
    } else {
        return kread_ptr(proc + koffsetof(proc, ucred));
    }
}

```

This abstraction resolves a critical kernel structure change: **iOS ≤ 15** stores `ucred` directly in the `proc` structure, while **iOS ≥ 16** moves it to a read-only sub-structure `proc_ro`. The function uses offset tables defined in [`info.h`](https://github.com/opa334/Dopamine/blob/main/info.h) and [`info.c`](https://github.com/opa334/Dopamine/blob/main/info.c) to remain portable across kernel builds.

## Reference Count Management for kauth_cred

Credential objects in XNU use reference counting for memory safety. Dopamine implements four helpers in [`kernel.c`](https://github.com/opa334/Dopamine/blob/main/kernel.c) that mirror the kernel's own `kauth_cred` API:

| Helper | Purpose |
|--------|---------|
| `kauth_cred_ref()` | Atomically increments strong reference count |
| `kauth_cred_unref()` | Atomically decrements strong reference count |
| `kauth_cred_hold()` | Increments weak reference count |
| `kauth_cred_drop()` | Decrements weak reference count |

These functions detect the kernel's credential layout at runtime via `gSystemInfo.kernelStruct.ucred_rw.exists`. When **ucred_rw** is present, operations target the `weak_ref` field; otherwise they use the classic `ref` field in `ucred`. All operations use `kaccess_mapped` with atomic fetch-add/subtract to prevent race conditions.

## Swapping Credentials Between Processes

The `proc_copy_ucred()` function in [`BaseBin/libjailbreak/src/util.c`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/util.c) performs safe credential handoffs:

```c
void proc_copy_ucred(uint64_t procCopyFrom, uint64_t procCopyTo) {
    uint64_t ucredToCopy = proc_ucred(procCopyFrom);
    uint64_t origUcred   = proc_ucred(procCopyTo);

    // Release the old credential of the target process
    kauth_cred_drop(origUcred);
    kauth_cred_unref(origUcred);

    // Retain the new credential
    kauth_cred_ref(ucredToCopy);
    kauth_cred_hold(ucredToCopy);

    // Finally write the new ucred pointer
    proc_ucred_update(procCopyTo, ucredToCopy);
}

```

The operation follows strict ordering: **drop** destination references, **reference** source credential, then **write** the new pointer via `proc_ucred_update()`. This prevents use-after-free and maintains kernel invariants.

## Root Credential Stealing via XPC

For privilege escalation scenarios, `jbclient_root_steal_ucred()` in [`BaseBin/libjailbreak/src/jbclient_xpc.c`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/jbclient_xpc.c) provides an inter-process mechanism. The function sends an XPC message containing a target `ucred` address and optionally receives the original credential in exchange. The underlying swap still uses the reference-counted helpers above, ensuring the root credential's lifetime is properly managed even when transferred across process boundaries.

## Practical Usage Examples

Spawning a binary with root credentials:

```c
uid_t  uid  = 0;            // root UID
gid_t  gid  = 0;            // root GID
gid_t  ruid = 0, rgid = 0;
gid_t  groups[NGROUPS_MAX] = {0};

int ret = target_proc_with_ucred("/usr/bin/someBinary", uid, gid,
                                 ruid, rgid, groups);
if (ret == 0) {
    /* Child now runs with the root credential */
}

```

Replacing the current process's credential:

```c
uint64_t myProc    = proc_find(getpid());
uint64_t otherProc = proc_find(otherPid);
proc_copy_ucred(otherProc, myProc);   // now myProc adopts otherProc's credentials

```

## Key Implementation Files

- **[`BaseBin/libjailbreak/src/kernel.c`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/kernel.c)** — `kauth_cred_*` helpers and `proc_ucred()` accessor
- **[`BaseBin/libjailbreak/src/util.c`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/util.c)** — `proc_copy_ucred()`, `proc_ucred_update()`, `target_proc_with_ucred()`
- **[`BaseBin/libjailbreak/src/jbclient_xpc.c`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/jbclient_xpc.c)** — XPC interface for `jbclient_root_steal_ucred()`
- **[`BaseBin/libjailbreak/src/info.h`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/info.h)** / **[`info.c`](https://github.com/opa334/Dopamine/blob/main/info.c)** — Structure offsets for `ucred`, `ucred_rw`, `proc`, `proc_ro`
- **[`BaseBin/libjailbreak/src/kernel.h`](https://github.com/opa334/Dopamine/blob/main/BaseBin/libjailbreak/src/kernel.h)** — Declarations for credential manipulation API

## Summary

- **Version abstraction**: `proc_ucred()` transparently handles `proc` vs. `proc_ro` layout differences between iOS 15 and iOS 16+
- **Memory safety**: Four reference count helpers (`ref`/`unref`/`hold`/`drop`) maintain kernel invariants using atomic operations
- **Safe swapping**: `proc_copy_ucred()` implements ordered release-retain-write to prevent credential leaks or dangling pointers
- **Privilege elevation**: XPC-based `jbclient_root_steal_ucred()` enables cross-process credential transfer for root operations

## Frequently Asked Questions

### What is kauth_cred in the XNU kernel?

The `kauth_cred` structure (commonly referenced as `ucred`) is the kernel's canonical representation of process identity. It contains the **real and effective UID/GID**, **supplementary groups**, **privilege flags**, and **audit information**. Multiple processes can share the same credential object, which is why reference counting is essential for memory management.

### Why does Dopamine need to manipulate process credentials directly?

iOS **prohibits standard privilege escalation APIs** in sandboxed or non-root contexts. Dopamine bypasses these restrictions by directly modifying kernel structures through read/write primitives, allowing arbitrary processes to assume root identity without traditional BSD syscalls that would be blocked by MAC policies.

### How does Dopamine avoid kernel panics during credential swapping?

The implementation enforces three safety properties: **atomic reference count operations** prevent use-after-free, **ordered release-before-retain** ensures the destination credential remains valid until replaced, and **version-detected offsets** guarantee correct structure field access across different kernel builds.

### What is the difference between strong and weak credential references?

**Strong references** (`ref`/`unref`) participate in garbage collection—when the count reaches zero, the credential is freed. **Weak references** (`hold`/`drop`) allow caching and temporary borrowing without preventing deallocation. Dopamine manipulates both to match kernel conventions and ensure credential objects are valid throughout operation lifetimes.