Skip to content

Commit 8d775d1

Browse files
authored
Merge pull request #47 from linuxserver/misc-doc-revisions
Update misc docs with better explanations
2 parents 83da5f0 + fb158ba commit 8d775d1

2 files changed

Lines changed: 46 additions & 8 deletions

File tree

‎docs/misc/non-root.md‎

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,46 @@
55

66
## What?
77

8-
If you run one of our typical images in a standard Docker setup, the container itself will run as `root`. After init we then drop to an unprivileged user, `abc` to run the actual application service(s). We do this because at the time we designed our architecture the alternative - setting a fixed unprivileged user at build time - would have prevented us from offering the range of options that wanted to. While it is now possible to use the `--user` parameter to run any container as an arbitrary user, it hasn't been something we've been able to support before now.
8+
If you run one of our typical images in a standard Docker setup, the container itself will run as `root`. After init we then drop to an unprivileged user, `abc` to run the actual application service(s). We do this because at the time we designed our architecture the alternative - setting a fixed unprivileged user at build time - would have prevented us from offering the range of options that wanted to. While it is now possible to use the `--user` parameter to start any container as an arbitrary user, it hasn't been something we've been able to support before now.
99

1010
The other approach is to run [Docker itself rootless](https://docs.docker.com/engine/security/rootless/). This creates a separate user and network namespace for your containers and means that even containers nominally running as `root` don't have root permissions on your host. Running a container as a non-root user and running it rootless are **not** the same, but are commonly conflated.
1111

1212
## Why?
1313

14-
Some people take the position that a container running as root *at any point in any configuration* is an unacceptable security risk. Those people typically misunderstand the attack surface of containers and where the risks actually lie. Having said that, there *are* some risks with having containers running as root, depending on the environment; generally, a better solution to running every container as an unprivileged user is to run Docker itself rootless, but that's not always desirable. In these situations, being able to run a single container as a unprivileged user has its benefits.
14+
Some people take the position that a container running as root *at any point in any configuration* is an unacceptable security risk, this is typically driven by a misunderstanding of the security boundaries of containers and the likely paths an attacker has access to. Having said that, there are risks with having containers running as root, depending on the environment; generally, rather than starting containers as an unprivileged user, a better approach is to run Docker itself rootless, but that's not always practical. In these situations, being able to start individual containers as an unprivileged user has its benefits.
1515

16-
To give you some sense of the scope of potential risk, let's take our SABnzbd image, imagine you've exposed it to the internet, and for some reason allowed unauthenticated access. Now let's assume a user were to discover a Remote Code Execution vulnerability in SABnzbd, and were able to exploit it to get a shell in the container (not a simple task, but let's be generous). At this point they have a shell running as the unprivileged `abc` account, which heavily limits what they can do. There's no sudo/doas in the container so they'd likely need to chain a Privilege Escalation vulnerability (within the limited set of packages installed) to get root. Even at that point, with root access inside the container, they would then need a further Container Escape vulnerability in order to do anything meaningful to the host beyond simply deleting or modifying data in a mounted path (which they could do as a non-root user anyway). That said, some of our containers do require additional Capabilities to run, and these *could* be exploited by a user with root to affect the host in various ways.
16+
To give you some sense of the scope of potential risk, let's take a look at possible configurations:
17+
18+
### Container starts as root, application runs as root
19+
20+
If the application is compromised, an attacker could gain root access to the container without any further action. However, without a further container escape vulnerability, they cannot affect the host unless the container has additional capabilities, runs privileged, or is configured with shared namespaces, mounted devices, or other advanced options that expand its attack surface.
21+
22+
### Container starts as root, application runs as unprivileged user
23+
24+
This is the configuration for most LSIO images. If the application is compromised, an attacker has access to the container as an unprivileged user. Our images do not typically include tools such as su/sudo/doas, or other suid binaries, and so without a further local privilege escalation vulnerability they cannot gain root access inside the container. If they were able to find a container escape vulnerability that could be exploited without root access, they may be able to gain access to the host as either an unprivileged or root user, depending on the exploit.
25+
26+
### Container starts as unprivileged user, application runs as unprivileged user
27+
28+
This is the "non-root" configuration for LSIO images. This is identical to the previous scenario *except* that the container init runs as an unprivileged user as well as the application, so if an attacker were to compromise that process - such as via custom scripts or a supply chain exploit in an included package - they would not have root access inside the container. The root user still exists in the image, and can still be accessed, it just isn't used by the running container.
29+
30+
### Docker runs rootless, container and application run in any of the above configurations
31+
32+
Docker runs itself and the entire container in a user namespace, separate from the rest of the host. Even if the application in the container is running as root, and the container is running privileged, an attacker is limited to that user namespace and cannot access the rest of the host. They could however access other containers in that namespace, or data mounted into containers from outside the namespace. There is also the possibility of vulnerabilities that would allow namespace escape, so even with a rootless environment you should still follow good security practices.
33+
34+
### A note on no-new-privileges=true
35+
36+
Docker provides an option to restrict privilege escalation - via suid binary, exploit, or other route - that can be set via CLI or compose:
37+
38+
```shell
39+
--security-opt=no-new-privileges:true
40+
```
41+
42+
```yaml
43+
security_opt:
44+
- no-new-privileges=true
45+
```
46+
47+
This will prevent any process in the container from gaining more privileges than its parent. This can be used in combination with any of the above configurations, subject to the caveats listed below, and with the understanding that it will prevent the use of tools such as `sudo`, or any other suid binary such as `passwd`.
1748

1849
## How?
1950

@@ -26,7 +57,7 @@ services:
2657
user: <uid>:<gid>
2758
```
2859

29-
Will run the container as that user, and that cannot then be changed without recreating it. It's never quite that simple, however.
60+
Will start the container as that user, and that cannot then be changed without recreating the container. It's never quite that simple, however.
3061

3162
Our images use s6 as a supervisor and that needs to be able to write its service files to `/run`; many applications expect to be able to write to their working directory, changing UIDs and GIDs requires writing to `/etc/passwd` & `/etc/group`, installing new packages requires writing to numerous locations, and mods need to be extracted to the container filesystem. In short, there are some heavy limitations around operation of our images with a non-root user:
3263

@@ -38,7 +69,7 @@ Our images use s6 as a supervisor and that needs to be able to write its service
3869
* You cannot set `no-new-privileges=true` unless you additionally set permissions on /run to match your `user` UID and GID
3970
* This is because s6 needs `/run` to be owned by the user running the container
4071

41-
For all of these reasons, we recommend you *do not* switch existing container instances to run with a non-root user without careful testing.
72+
For all of these reasons, we recommend you *do not* switch existing container instances to use a non-root user without careful testing.
4273

4374
For example:
4475

@@ -84,9 +115,10 @@ services:
84115

85116
## Support Policy
86117

87-
Operation of our images with a non-root user is supported on a Reasonable Endeavours basis and *only* for images which we have specifically tested. These images will have their ability to be run with a non-root user noted in the readme, along with any additional caveats. Please see our [Support Policy](https://linuxserver.io/supportpolicy) for more details.
118+
Operation of our images with a non-root user is supported on a Reasonable Endeavours basis and *only* for images which we have specifically tested. These images will have their ability to use a non-root user noted in the readme, along with any additional caveats. Please see our [Support Policy](https://linuxserver.io/supportpolicy) for more details.
88119

89120
## Change History
90121

122+
* 2026-09-15 - Update "Why" section to clarify configuration options
91123
* 2025-08-13 - Add notes about `no-new-privileges=true`
92124
* 2024-12-17 - Initial release

‎docs/misc/read-only.md‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Will mount its filesystem as read-only, and that cannot then be changed without
3030
3131
Our images use s6 as a supervisor and that needs to be able to write its service files to `/run`; many applications expect to be able to write to their working directory, changing UIDs and GIDs requires writing to `/etc/passwd` & `/etc/group`, installing new packages requires writing to numerous locations, and as discussed above, mods need to be extracted to the container filesystem. In short, there are some heavy limitations around read-only operation of our images:
3232

33-
* The PUID & PGID variables will not have any effect, the container will run applications with a UID of 911, and will apply those permissions to `/config`.
33+
* The PUID & PGID variables will not have any effect, the container will run applications as UID 911, and will apply those permissions to the `/config` host mount.
3434
* The UMASK variable will not have any effect
3535
* Docker Mods will not be run
3636
* Custom Services will not be run
@@ -72,4 +72,10 @@ services:
7272

7373
## Support Policy
7474

75-
Read-only operation of our images is supported on a Reasonable Endeavours basis and *only* for images which we have specifically tested. These images will have their ability to be run read-only noted in the readme, along with any additional caveats. Please see our [Support Policy](https://linuxserver.io/supportpolicy) for more details.
75+
Read-only operation of our images is supported on a Reasonable Endeavours basis and *only* for images which we have specifically tested. These images will have their ability to be run read-only noted in the readme, along with any additional caveats, such as needing to mount `/tmp` or not supporting certain configurations. Please see our [Support Policy](https://linuxserver.io/supportpolicy) for more details.
76+
77+
## Change History
78+
79+
* 2026-09-15 - Clarifying updates to some wording
80+
* 2024-07-08 - Add warning about migrating existing containers
81+
* 2024-06-26 - Initial release

0 commit comments

Comments
 (0)