Least privilege runtime

Looks like there is no openwrt distro with processes running with just enough privilege? I am sure you at least tried to run web server as non root. How long did it take?

more modern OpenWrt have split things to less-privileged users, like ubus (internal interprocess communication), logd (logging), dnsmasq (dhcp/DNS), and many non-core packages have their own non-root user (syncthing, zabbix and so on).

I think web interface has to run as root because it must give commands and edit configuration.

3 Likes

Why isn't it done by default?
Can one just configure without any code change?

it is done by default for system services that can be run as non-root like logging or dnsmasq (dhcp/dns) or monitoring agents like Zabbix (optional package installed on my router to collect data on my own Zabbix server)

See for example this process list of my router running master snapshot (similar to next release, 21.02)

 177 ubus      1044 S    /sbin/ubusd
  178 root       700 S    /sbin/askfirst /usr/libexec/login.sh
  212 root       812 S    /sbin/urngd
  740 logd      1028 S    /sbin/logd -S 64
  792 root      2064 S    /sbin/rpcd -s /var/run/ubus/ubus.sock -t 30
 1153 root      3320 S    /usr/sbin/hostapd -s -g /var/run/hostapd/global
 1154 root      3224 S    /usr/sbin/wpa_supplicant -n -s -g /var/run/wpa_supplicant/global
 1216 root      1604 S    /sbin/netifd
 1270 root      1248 S    /usr/sbin/odhcpd
 1719 root       888 S    /usr/sbin/dropbear -F -P /var/run/dropbear.1.pid -p 192.168.11.254:22 -K 300 -
 1721 root      1108 S    -ash
 1737 root      1100 R    ps
 1879 root      4488 S    /usr/sbin/uhttpd -f -h /www -r AlbyRouter -x /cgi-bin -u /ubus -t 60 -T 30 -k
 2007 zabbix    1996 S    /usr/sbin/zabbix_agentd -c /etc/zabbix_agentd.conf -f
 2176 zabbix    1996 S    /usr/sbin/zabbix_agentd: collector [idle 1 sec]
 2177 zabbix    2004 S    /usr/sbin/zabbix_agentd: active checks #1 [idle 1 sec]
 2574 root       864 S    /usr/sbin/dropbear -F -P /var/run/dropbear.1.pid -p 192.168.11.254:22 -K 300 -
 3299 root      1104 S<   /usr/sbin/ntpd -n -N -l -S /usr/sbin/ntpd-hotplug -p 0.openwrt.pool.ntp.org -p
 3901 dnsmasq   1264 S    /usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf.cfg01411c -k -x /var/run/dnsmasq/dn
 9461 root      1100 S    udhcpc -p /var/run/udhcpc-br-wan.pid -s /lib/netifd/dhcp.script -f -t 0 -i br-
20133 root      3200 S    /usr/sbin/snmpd -Lf /dev/null -f -r

And this is the user list where you see there are a bunch of non-root users that default services use.

cat /etc/passwd 
root:x:0:0:root:/root:/bin/ash
daemon:*:1:1:daemon:/var:/bin/false
ftp:*:55:55:ftp:/home/ftp:/bin/false
network:*:101:101:network:/var:/bin/false
nobody:*:65534:65534:nobody:/var:/bin/false
ntp:x:123:123:ntp:/var/run/ntp:/bin/false
dnsmasq:x:453:453:dnsmasq:/var/run/dnsmasq:/bin/false
logd:x:514:514:logd:/var/run/logd:/bin/false
ubus:x:81:81:ubus:/var/run/ubus:/bin/false
zabbix:x:53:53:zabbix:/var/run/zabbix:/bin/false

EDIT: as shown below by the other person, services will create a new user on install if they are configured to run as non-root. You will not see services in this list unless you have installed the packages.

Usually no. It's either done by default or not done at all.
If your package can be run as a specific user without problems, you need to modify the init script in /etc/conf/init.d to start the service as a different user, and of course create the user.
If you tell me what package you want to run as non-root I can look at the files and give you more specific instructions to make the change.

If you are developing a package you can do the change permanently and ask the system to generate the user when you install the package. You can see how this was done in the commit for Syncthing package

2 Likes

i've upgraded many times and tested quite a few packages... (most of them are not currently installed) but had a laugh the other day when I saw my cumulative passwd...

root:x:0:0:root:/root:/bin/ash
daemon:*:1:1:daemon:/var:/bin/false
ftp:*:55:55:ftp:/home/ftp:/bin/false
network:*:101:101:network:/var:/bin/false
nobody:*:65534:65534:nobody:/var:/bin/false
dnsmasq:x:453:453:dnsmasq:/var/run/dnsmasq:/bin/false
apache:x:377:377:apache:/var/run/apache:/bin/false
mosquitto:x:200:200:mosquitto:/var/run/mosquitto:/bin/false
ntp:x:123:123:ntp:/var/run/ntp:/bin/false
logd:x:514:514:logd:/var/run/logd:/bin/false
ubus:x:81:81:ubus:/var/run/ubus:/bin/false
docker:x:65536:65536:docker:/var/run/docker:/bin/false
syncthing:x:499:499:syncthing:/var/run/syncthing:/bin/false
prometheus:x:112:112:prometheus:/var/run/prometheus:/bin/false
radicale2:x:225:225:radicale2:/var/run/radicale2:/bin/false
aria2:x:6800:6800:aria2:/var/run/aria2:/bin/false
minidlna:x:65537:65537:minidlna:/var/run/minidlna:/bin/false
dummy:x:65999:65999:dummy:/var:/bin/false

actually a good sign of the times...

2 Likes

I would hazard a guess that it isn't done by default because OpenWrt relies on Busybox for most things for simplicity and space reasons.

You can install https://openwrt.org/packages/pkgdata/shadow-useradd to get full-fat useradd functionality though.

No it is not a space problem, running an application as a different user requires only a few lines in a script.

It is a "knowledge issue".
You cannot just "run everything as a different user" by default because you don't know what they need to read/write or do. This can only be configured separately for each application by someone that knows what the application does so you can change permissions to folders and files it must work with too.

In a normal Linux or Windows or Mac PC most applications are started with the same non-root account, aka the user account, which is not very secure system either, because yes the applications don't have root access, but since the system does not know where they need to read or write it gives them access to everything the user can read/write.

So all applications in your PC can read and write all your files (and all other application files), no questions asked. They also have access to shell commands, just like the user.

The applications in OpenWrt that are "run as a different user" as you see above are all running as system services, like it is set up in a server, with their own user that has access ONLY to the folders they actually need and has NO access to shell.

This is why this requires either manual configuration or that the package maintainer has modified the package scripts to do these operations automatically.

Because this is actual process isolation, not just "let's run everyting with the same non-root user". And the solution if packages are running as root when they don't need it is "fix the package"

2 Likes

I've been working quite on procd a lot to improve the situation in the past 2 years. While the main goal is to have an OCI compliant runtime at a fraction of the size of runc or even crun, as a by-product some of the means of isolating containers (namespaces, capabilities, cgroups, seccomp, ...) have also been made available for regular services. Install procd-ujail and procd-seccomp to try.

  • hostapd and wpa_supplicant running as user network with some additional capabilities

  • ntpd runs as user ntp with CAP_SYS_TIME and CAP_NET_BIND_SERVICE

  • dnsmasq is gets its own mount, pid and ipc namespace, isolated from the rest of the filesystem.

  • umdns and transmission-daemon make use of namespaces and seccomp.

If there is interest I may also make the cgroup-v2 devices eBPF generator available to regular services in a similar way.

However, it's up to package maintainers to make use of these now available methods also for other services. If help with that is needed, feel free to contact me.

5 Likes

I happened to "stumble" upon procd-ujail and procd-seccomp by coincidence. I think this could be mentioned in the release notes for 21.02 more prominently because I find it quite useful outside the container world as well. From the hostapd package sources, I wrongly assumed that the daemon runs unprivileged by default. But that's only the case if you have procd-ujail and procd-seccomp installed. Unfortunately, it's mentioned nowhere that you need to install additional packages to apply additional hardening to some core services and also how easy it is to actually do it. I understand it's not done by default because it may break some setups, but I installed procd-ujail and procd-seccomp on my OpenWrt access point and it runs just fine and hostapd, as you mentioned, now runs as user network instead of root.

those two packages have been added to default list https://github.com/openwrt/openwrt/commit/6a56a6eb30799fcec9eecc3ee860dc4d8a5d952a
but then immediately removed
https://github.com/openwrt/openwrt/commit/2812ea3acb88c7e3649c912d6ad761bf8818fc51
because they were causing unbootable system

but as mentioned in the comments of that commit on github it seems the actual issue were other commits in ujail

@daniel I see on git you are very active on ujail functionality of procd, do you plan to add these packages again in default list later?

Also is it documented anywhere how to use the functions provided by them? Even just a readme file in the package source. I'm not seeing much, maybe I'm looking in the wrong place?
Some form of usable documentation would help adoption of these new functions.

The problems supposedly caused by ujail were indeed related to other changes in ubus, as @ptpt52 correctly stated in the comments.

I personally believe ujail should be used by default and for as many services as possible. I'm not sure if I will try another time to have it added by default, the feedback I got for it when I tried that before wasn't all that positive... A few people carry the patch which enables it by default in their staging trees, so I hope that someone else will just apply it in the right moment.

Documentation for service isolation features is here: https://openwrt.org/docs/guide-developer/procd-init-scripts#service_parameters

I don't think the documentation is complete, though. The dnsmasq init script suggests there are at least three more parameters:

procd_add_jail
procd_add_jail_mount
procd_add_jail_mount_rw

Looking at the script also suggests that these parameters do not depend on procd-ujail as they aren't added conditionally.

I think it would already help to promote the installation of the packages procd-ujail and procd-seccomp in the release notes. The more people know about it and actually use it, the more likely they are to provide feedback. In case something breaks for some people, I'm sure they'll speak up. And maybe some will just confirm that everything runs smoothly for them which may encourage developers to ship the packages by default.

3 Likes
verbage1

pretty impressed in general with this featureset... and this is coming from someone very resistant to change...

small flash aside... i'm pretty happy to have these bundled by default once some teething stuff is ironed out...

perhaps these comments are coming from not enough background with these features but...

  1. would be great if jailed services were togglable from config/SERVICE and/or a system wide fallback tunable was in place...
verbage2

I see the merit in just installing an ipk and things are jailed... but I believe in not obfuscating things to a level where a user has little or no runtime control over jailing features...

(technology comes and goes... especially namespace stuff... tying everything down into a single automated procd solution may prove ultimately way too restrictive/inflexible)

just trying now...

  • ntp (great-opkg-autorestarted-service)
  • dnsmasq (opkg-did-not-restart-service, manual failed to start, is it a requirement to reboot? should this be printed on live opkg install?, does it need a rollback-esque fault condition behavior?)

(BUILD_ID="r17143")

(also utrace and seccomp-trace dont offer any --help ... which I find pretty useful in all commands)

2c

If you tell me what package you want to run as non-root I can look at the files and give you more specific instructions to make the change.
Why not have an Openwrt pkg defaulted to run with least-privilege possible?

If you tell me what package you want to run as non-root I can look at the files and give you more specific instructions to make the change.

You cannot just "run everything as a different user" by default because you don't know what they need to read/write or do. This can only be configured separately for each application by someone that knows what the application does so you can change permissions to folders and files it must work with too.

In a normal Linux or Windows or Mac PC most applications are started with the same non-root account, aka the user account, which is not very secure system either, because yes the applications don't have root access, but since the system does not know where they need to read or write it gives them access to everything the user can read/write.

So all applications in your PC can read and write all your files (and all other application files), no questions asked. They also have access to shell commands, just like the user.

The applications in OpenWrt that are "run as a different user" as you see above are all running as system services, like it is set up in a server, with their own user that has access ONLY to the folders they actually need and has NO access to shell.

This is why this requires either manual configuration or that the package maintainer has modified the package scripts to do these operations automatically.

Because this is actual process isolation, not just "let's run everyting with the same non-root user". And the solution if packages are running as root when they don't need it is "fix the package"

1 Like

Implied in that statement is every process in the default openwrt distro has right capabilities, sandboxing, ... preconfigured. Not blindly run as nonroot user.

Without going into detail about things you could write a book on, I'm surprised not to see the word "suid" in this discussion; a useful part of splitting the difference between all or nothing privileges.

If suid is the answer, I don't want to know the question. The real answer would be linux capabilities, fine grained access rights and then selinux, apparmor, etc.

--
suid is an all-or-nothing approach, the binary marked as suid runs as full root, but can be executed by mere users. It's an old way of doing things, there are some use cases where this is necessary, but in general it would be a major security issue, as the binary in question needs to be thoroughly audited about what it can do.

1 Like

Fair enough. I think of suid more in terms of scripts than binaries, when a process needs privilege to do perhaps precisely one thing, and then runs with ordinary user privileges after or apart from that particular thing. But you're quite right that there are less crude, more surgically precise ways to accomplish it for those willing to put in the time and research to do it.