# Privileged mode

What privileged=yes on the agent's RouterOS container makes readable, what it leaves out of reach, and what running without it costs.

Source: https://docs.jmrp.io/mikroscope/limits/privileged/

`install` creates the agent's container with `privileged=yes`. The setting decides which of the
agent's sources the kernel lets it read; it opens no network access and no view of RouterOS's
processes.

## Default

The container runs `privileged=yes` unless you pass `--privileged=false` to `install` or
`upgrade`, which recreates the container. It is a boolean flag, so it takes `=false`; a
separate `false` argument is not read as its value. The setting needs RouterOS 7.24 or
later: RouterOS added privileged mode for containers in 7.24, as its
[changelog](https://download.mikrotik.com/routeros/7.24/CHANGELOG) records.

Reading the device's internal state is what mikroscope is for, and privileged is what makes
the root-only kernel files readable. An ordinary RouterOS container is placed in a
[user namespace](https://man7.org/linux/man-pages/man7/user_namespaces.7.html) where its root maps to host uid 32768 ([read on one board](https://docs.jmrp.io/mikroscope/about/status/#not-tested)),
so `/proc/slabinfo` and `/dev/kmsg` come back `EACCES`. `privileged=yes` drops that user namespace.

It is still a real grant of privilege, which is why `plan` and `install --dry-run` print it
with the rest of the container's settings before anything is written.

## What it enables

`privileged=yes` makes these sources readable, and the agent reads each except where the table
says otherwise:

| Source                         | What it gives                                                                                                                    | Where it shows                                                                 |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `/dev/kmsg`                    | the kernel ring buffer as timestamped events, naming the router's real interfaces                                                | `mikroscope_kmsg_records_total{level}`, `mikroscope_kmsg_port_records_total{port,kind,level}`, and Loki |
| `/proc/slabinfo`               | the global slab caches: `nf_conntrack` (the router's real connection count), `skbuff_*`, `TCP`/`UDP` sockets, `kmalloc-1k`/`-2k` | `mikroscope_slab_active_objects{cache}`                                        |
| `/sys/class/mtd` ECC counters  | `corrected_bits` and `ecc_failures` per NAND partition                                                                           | `mikroscope_mtd_ecc_corrected_bits_total`, `mikroscope_mtd_ecc_failures_total` |
| the PMU, via `perf_event_open` | cycles, instructions, cache references and misses, branch misses, bus cycles, per core, system-wide                              | `mikroscope_perf_events_total{counter,cpu}`                                    |
| `/proc/pagetypeinfo`           | readable, but the agent does not read it                                                                                         | nowhere                                                                        |

The PMU needs privileged for a different reason from the files: its counters are opened
system-wide (`pid = -1`), which [`perf_event_open(2)`](https://man7.org/linux/man-pages/man2/perf_event_open.2.html) says takes `CAP_SYS_ADMIN`
against the host, `CAP_PERFMON` on Linux 5.8 and later, or a `perf_event_paranoid` below 1. A
privileged container keeps `CAP_SYS_ADMIN` against the host, so a `perf_event_paranoid` of 2 does
not block it ([measured](https://docs.jmrp.io/mikroscope/about/status/#reference-hardware)). What the PMU shows that no
tick counter can is on [Resolution limits](https://docs.jmrp.io/mikroscope/limits/).

The kernel log is read without blocking and capped at 64 records per tick. It is opened at
the end of the buffer, so a boot-time backlog is never replayed as if it had just happened.
`mikroscope_kmsg_dropped_total` counts loss events, not records: one per tick that hit the
64-record cap (that tick's one extra read is discarded, and the rest of the backlog is read on
later ticks), and one per kernel ring overrun, which can stand for many records. While it is
non-zero, the per-severity count under-counts.

Whether this deployment got them is not left to inference. `/capabilities` carries
`"privileged": true` only when both `/proc/slabinfo` and `/dev/kmsg` opened, and
`mikroscope_device_info{privileged="true"}` says the same on `/metrics` and in every sink's
device-info stream. Without privileged, the slab, PMU and MTD families are absent, not zero.
The kernel-log family appears only once a record has been seen, so its absence alone cannot
tell an unprivileged deployment from a quiet kernel; the `privileged` flag can.

## What it does not enable

It adds **no** network access and **no** view of RouterOS's processes. Privileged drops the
user namespace and leaves the network and PID namespaces in place ([verified](https://docs.jmrp.io/mikroscope/about/status/#campaign-netns-2026-09-12)).
So per-interface counters still come from the RouterOS API, and per-process CPU is out of
reach even with the host's `/proc` mounted into the container. Both are on
[Container visibility](https://docs.jmrp.io/mikroscope/limits/namespaces/).

It adds no capabilities either: an unprivileged container already holds the full set the kernel
defines ([read on one board](https://docs.jmrp.io/mikroscope/about/status/#not-tested)). What changes is the user
namespace those capabilities are confined to, not the set.

And it cannot give you more sensors than the board has. The agent reads the thermal zones, which
need no privileged, and nothing under `/sys/class/hwmon`. On the board measured, `hwmon` is empty
even privileged, so its thermal zones are its whole kernel sensor set ([measured](https://docs.jmrp.io/mikroscope/about/status/#reference-hardware)).
On a board that does have voltage, current or fan sensors, the RouterOS API tier still adds them.

## Run unprivileged

`--privileged=false` keeps everything that is readable from an ordinary container: every
global `/proc` file in the samples, the thermal zones, `scaling_cur_freq`, `/proc/yaffs`,
`/proc/buddyinfo`, `/proc/diskstats`, and the agent's own cost. What goes:

- The kernel log. A [layer-2 loop](https://docs.jmrp.io/mikroscope/playbooks/loop/) can be visible only there.
- The router's connection count from the slab cache. The RouterOS API's `count-only` table
  scan is the remaining source, which the collector runs only when `--conntrack-every` is
  set.
- The NAND ECC counters. The YAFFS wear counters remain.
- The PMU, and with it everything beneath the 10 ms tick.

What goes silent with them: `doctor`'s `health` section can then report only `softnet-drops`. Its
`ok` line does not mean there is no loop, because the loop, STP-churn and link-flap checks read the
kernel log. The alert rules `mikroscope-l2-loop` and `mikroscope-port-link-down` (kernel log),
`mikroscope-conntrack-near-limit` (slab cache; `--conntrack-every` feeds a different series that
this rule does not read) and `mikroscope-ecc-failure` (MTD) have no data and stay at OK. Check
`mikroscope_device_info{privileged}` before trusting their silence.

> **Privileged is not a mount**
>
> A privileged container with the host's `/` mounted reads the whole RouterOS configuration, secrets
> included ([tested](https://docs.jmrp.io/mikroscope/about/status/#verified-host-mounts)). The installer does not mount any host path
> into the agent's container, and nothing here needs one.

## See also

- [Container visibility](https://docs.jmrp.io/mikroscope/limits/namespaces/): the two
  namespaces privileged leaves in place, file by file.
- [Security model](https://docs.jmrp.io/mikroscope/security/): the agent's container and what it can reach, from
  the security side.
- [Conntrack without the API](https://docs.jmrp.io/mikroscope/playbooks/conntrack/): the slab count privileged
  makes readable, and how to check it.
- [Flash wear](https://docs.jmrp.io/mikroscope/playbooks/flash-wear/): the YAFFS counters that need no privilege
  and the ECC counters that do.
