# Who can manage a service

_Peios / Using Peios / Services & jobs_

> Every control command runs AccessCheck against the service's ServiceSecurity descriptor. The rights, the defaults, and the system control descriptor.

A service is a *securable object*. Just as a [file](/peios/security-fundamentals/file-access/overview.md) or a [registry key](/peios/using-peios/registry-security/access-control.md) carries a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md) that decides who may touch it, a service carries one that decides who may **start, stop, query, or reload** it. peinit enforces it on *every* [control command](/peios/using-peios/services-and-jobs/controlling-services.md) — there is no command that skips the check.

This is the second, independent half of the security model. The first half, [Service identity and privileges](/peios/using-peios/services-and-jobs/identity-and-privileges.md), is about what a service *can do* (its token). This page is about who can *manage the service* — a completely separate question, answered by a completely separate descriptor.

## Two descriptors, two questions

A service is associated with **two** descriptors that are easy to conflate but answer different questions and are enforced by different components:

| Descriptor | Question | Stored | Enforced by |
|---|---|---|---|
| **Registry key SD** | Who can *read or edit the definition*? | On the `Machine\System\Services\<name>` key | [LCS](/peios/using-peios/registry-security/access-control.md), at key-open time |
| **ServiceSecurity SD** | Who can *manage the running service*? | As the `ServiceSecurity` binary value on that key | **peinit**, on every control command |

The registry key SD is ordinary [registry access control](/peios/using-peios/registry-security/access-control.md) and not peinit's concern — peinit reads definitions as SYSTEM, which has full access. The **ServiceSecurity** SD is peinit's domain, and the rest of this page is about it.

They are genuinely independent. An administrator might be able to *query a service's status* (ServiceSecurity grants `SERVICE_QUERY_STATUS`) but not *read its configuration* (the registry key SD denies read) — or the reverse. Runtime control and configuration access are separate concerns, and both combinations are valid.

## Service access rights

The ServiceSecurity descriptor grants these rights:

| Right | Bit | Grants |
|---|---|---|
| `SERVICE_QUERY_STATUS` | 0x0001 | Query state, PID, cause, health, warnings. |
| `SERVICE_START` | 0x0002 | Start the service. |
| `SERVICE_STOP` | 0x0004 | Stop the service. |
| `SERVICE_INTERROGATE` | 0x0008 | Reload the service. |
| `SERVICE_ALL_ACCESS` | 0x000F | All of the above — the "full access" granted to SYSTEM by default. |

`restart` requires **both** `SERVICE_STOP` and `SERVICE_START`, since it is a stop followed by a start. `reset` requires `SERVICE_STOP`.

When peinit evaluates the descriptor it maps the generic rights as follows, so a descriptor written with generic rights behaves sensibly:

| Generic | Maps to |
|---|---|
| `GENERIC_READ` | `SERVICE_QUERY_STATUS` |
| `GENERIC_WRITE` | `SERVICE_START` \| `SERVICE_STOP` \| `SERVICE_INTERROGATE` |
| `GENERIC_EXECUTE` | `SERVICE_START` \| `SERVICE_STOP` \| `SERVICE_INTERROGATE` |
| `GENERIC_ALL` | `SERVICE_ALL_ACCESS` |

## How a command is authorised

Every control command runs the same gate:

1. peinit captures the caller's [token](/peios/using-peios/services-and-jobs/identity-and-privileges.md) from the kernel (`kacs_open_peer_token`) — the caller's *effective* identity at connection time, so if the caller is [impersonating](/peios/security-fundamentals/impersonation/overview.md), the impersonated identity is what is checked.
2. peinit resolves the target service and its ServiceSecurity descriptor.
3. peinit runs [AccessCheck](/peios/security-fundamentals/access-decisions/overview.md): the caller's token against the descriptor, for the right the command needs.
4. **Denied** → return `ACCESS_DENIED` and **log the attempt** (caller SID, target service, requested right).
5. **Granted** → execute the command.

> [!NOTE]
> Access denials are always logged — caller, target, and the right requested. Silent denial is a specification violation. If you are debugging a denial, the audit record has everything you need; see [Debugging a denial](/peios/security-fundamentals/access-decisions/debugging-a-denial.md).

## The default descriptor

If a service has no `ServiceSecurity` value, it **inherits** its parent key's. If no ancestor sets one either, peinit applies a built-in default:

- **SYSTEM** (`S-1-5-18`) — full access.
- **Administrators** (`S-1-5-32-544`) — query and stop only.

So out of the box, administrators can see and stop a service but not start or reload it unless a descriptor grants more — a conservative default that you widen deliberately.

ServiceSecurity is **hot-reloaded**: a change to the value in the registry takes effect on the **next control request**, with no service restart. peinit picks the change up through a [registry notification](/peios/using-peios/registry-concepts/watches.md). This is why ServiceSecurity is in its own [mutability class](/peios/using-peios/services-and-jobs/defining-a-service.md) — access policy should be able to change without disturbing a running service.

## The system control descriptor

Some operations are not about any one service — `shutdown` and `reload-config` act on the whole system. These are checked against **peinit's own** descriptor, stored at `Machine\System\Init\ControlSecurity`:

| Right | Bit | Grants |
|---|---|---|
| `SYSTEM_SHUTDOWN` | 0x0001 | Initiate poweroff, reboot, or halt. |
| `SYSTEM_RELOAD_CONFIG` | 0x0002 | Re-read all definitions and rebuild the graph. |

Its generic mapping deliberately gives `GENERIC_READ` *nothing* — there is no "read" of the system control object, only the two actions:

| Generic | Maps to |
|---|---|
| `GENERIC_READ` | (nothing) |
| `GENERIC_WRITE` | `SYSTEM_RELOAD_CONFIG` |
| `GENERIC_EXECUTE` | `SYSTEM_SHUTDOWN` |
| `GENERIC_ALL` | `SYSTEM_SHUTDOWN` \| `SYSTEM_RELOAD_CONFIG` |

The default grants **SYSTEM** full access and **Administrators** both rights. peinit loads this descriptor at boot and hot-reloads it on registry change, exactly like ServiceSecurity.

## The list command filters, it does not deny

`list` is access-control-aware in a quieter way: it returns only the services the caller has `SERVICE_QUERY_STATUS` on, and simply **omits** the rest. A caller with no query rights gets an empty list, not a denial. This means a low-privilege principal cannot even enumerate the services it cannot see — the existence of a service is itself information the descriptor controls.

## The boundaries that hold

A few invariants are worth stating outright, because they are what make this trustworthy:

- **peinit never bypasses AccessCheck for a control operation.** No backdoor, no override flag, no "trust localhost."
- **The descriptors are the only policy inputs.** peinit consults the ServiceSecurity and ControlSecurity descriptors and nothing else — not config files, not environment variables, not hardcoded lists.
- **One service's state is never exposed to another without a check.** `status` is per-service access-controlled; `list` filters.

## Where to start

For the *other* half of the security model — what a service can reach once it is running — read [Service identity and privileges](/peios/using-peios/services-and-jobs/identity-and-privileges.md).

For the commands these rights gate, read [Controlling services](/peios/using-peios/services-and-jobs/controlling-services.md).

For the descriptor and AccessCheck machinery itself, read [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md) and [Access decisions](/peios/security-fundamentals/access-decisions/overview.md).

Related content:

- [Service identity and privileges](/peios/using-peios/services-and-jobs/identity-and-privileges.md)
- [Controlling services](/peios/using-peios/services-and-jobs/controlling-services.md)
- [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md)
- [Access decisions](/peios/security-fundamentals/access-decisions/overview.md)
- [Access control on keys](/peios/using-peios/registry-security/access-control.md)
