Ntpd running as root instead of ntp

I am trying to understand the following situation: on all of my devices the busybox ntpd is running as user ntp, except one. On this device it is running as root. I have checked

  • md5sum of /etc/init.d/sysntpd
  • user ntp exists

What else? What configuration can cause this?

device1 running with user ntp
root@device1:~# ubus call system board
{
        "kernel": "6.12.87",
        "hostname": "device1",
        "system": "Qualcomm Atheros QCA9533 ver 2 rev 0",
        "model": "GL.iNet GL-AR300M (NOR)",
        "board_name": "glinet,gl-ar300m-nor",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "25.12.4",
                "firmware_url": "https://downloads.openwrt.org/",
                "revision": "r32933-4ccb782af7",
                "target": "ath79/nand",
                "description": "OpenWrt 25.12.4 r32933-4ccb782af7",
                "builddate": "1778712129"
        }
}
root@device1:~# ps | grep ntpd
 3689 root      2960 S    {ntpd} /sbin/ujail -t 5 -n ntpd -U ntp -G ntp -C /etc/capabilities/ntpd.json -c -u -r /bin/ubus -r /usr/bin/env -r /usr/bin/jshn -r /usr/sbin/ntpd-hotplug -r /us
 3715 ntp       1424 S    /usr/sbin/ntpd -n -N -l -S /usr/sbin/ntpd-hotplug -p 192.168.6.12
17985 root      1424 S    grep ntpd
root@device1:~# cat /etc/config/system

config system
        option ttylogin '0'
        option log_size '2560'
        option urandom_seed '0'
        option zonename 'Europe/Berlin'
        option timezone 'CET-1CEST,M3.5.0,M10.5.0/3'
        option log_proto 'udp'
        option conloglevel '8'
        option cronloglevel '7'
        option hostname 'device1'

config timeserver 'ntp'
        list server '192.168.6.12'
        option enable_server '1'

config led 'led_lan'
        option name 'LAN'
        option sysfs 'green:lan'
        option trigger 'netdev'
        option mode 'link tx rx'
        option dev 'eth0'

root@device1:~# md5sum /etc/init.d/sysntpd
71cafa201546c2f0c45af73ac0a2fade  /etc/init.d/sysntpd
root@device1:~# cat /etc/passwd | grep ntp
ntp:x:123:123:ntp:/var/run/ntp:/bin/false
root@device1:~# cat /etc/shadow  | grep ntp
ntp:x:0:0:99999:7:::
root@device1:~#
device2 running with root
root@device2:~# ubus call system board
{
        "kernel": "6.12.87",
        "hostname": "device2",
        "system": "MediaTek MT7628AN ver:1 eco:2",
        "model": "GL-MT300N-V2",
        "board_name": "glinet,gl-mt300n-v2",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "25.12.4",
                "firmware_url": "https://downloads.openwrt.org/",
                "revision": "r32933-4ccb782af7",
                "target": "ramips/mt76x8",
                "description": "OpenWrt 25.12.4 r32933-4ccb782af7",
                "builddate": "1778712129"
        }
}
root@device2:~# ps | grep ntpd
 3265 root      1428 S<   /usr/sbin/ntpd -n -N -S /usr/sbin/ntpd-hotplug -p 192.168.6.12
 3854 root      1424 S    grep ntpd
root@device2:~# cat /etc/config/system

config system
        option hostname 'device2'
        option ttylogin '0'
        option log_size '5120'
        option urandom_seed '0'
        option zonename 'Europe/Berlin'
        option log_proto 'udp'
        option conloglevel '8'
        option cronloglevel '7'
        option timezone 'CET-1CEST,M3.5.0,M10.5.0/3'

config timeserver 'ntp'
        list server '192.168.6.12'

config led 'led_wifi_led'
        option name 'wifi'
        option sysfs 'red:wlan'
        option trigger 'netdev'
        option mode 'link tx rx'
        option dev 'wlan0'

config led 'led_wan'
        option name 'wan'
        option sysfs 'green:wan'
        option trigger 'switch0'
        option port_mask '0x1'

root@device2:~# md5sum /etc/init.d/sysntpd
71cafa201546c2f0c45af73ac0a2fade  /etc/init.d/sysntpd
root@device2:~# cat /etc/passwd | grep ntp
ntp:x:123:123:ntp:/var/run/ntp:/bin/false
root@device2:~# cat /etc/shadow  | grep ntp
ntp:x:0:0:99999:7:::
root@device2:~#

Is it because device2 is a target which has the small_flash flag during compilation?

Could you check whether ujail (or procd-ujail) is still installed on device2?
The main difference I see is that on device1 ntpd is started through ujail and drops privileges to user ntp, while on device2 it starts directly as root.

Maybe the package was removed at some point (for example to save flash space)?

you could verify with:

which ujail
apk list --installed | grep ujail

-------------------------------------------------------------------------------------------------------------------

I checked the default package set for the GL-MT300N-V2 (ramips/mt76x8) and noticed that procd-ujail was not included in the generated image by default.

I then built a new custom image and explicitly added:

procd-ujail wget-ssl

The first build attempt failed, but after also adding wget-ssl the image was generated successfully, and I can now see:

Installing procd-ujail ...

in the build log.

So this seems to confirm that the original image for device2 simply did not contain procd-ujail, which would explain why ntpd was started directly as root instead of through ujail as user ntp.

I installed procd-ujail without reflash. Maybe this is wrong, I need to retry tomorrow. This time I got this error:

17.05.2026, 01:04:26 MESZ] daemon.info: procd: Instance sysntpd::instance1 s in a crash loop 6 crashes, 0 seconds since last crash
[17.05.2026, 01:05:54 MESZ] daemon.info: procd: Instance sysntpd::instance1 s in a crash loop 7 crashes, 0 seconds since last crash

Maybe ABI incompatible at the moment?

Yes.

I see, thanks. I guess there must be more optimizations because I am getting this crash reports even with a clean install with procd-ujail included.

17.05.2026, 01:04:26 MESZ] daemon.info: procd: Instance sysntpd::instance1 s in a crash loop 6 crashes, 0 seconds since last crash
[17.05.2026, 01:05:54 MESZ] daemon.info: procd: Instance sysntpd::instance1 s in a crash loop 7 crashes, 0 seconds since last crash

ntpd does not come up and the system time is off to the newest file, which is only some minutes older than current time. I also get more errors, even with apk update, which cannot be time related.
So I reverted back to an image without procd-ujail. At least the device is working again.

Sorry, I think my earlier assumption was only partially correct.

I focused on the missing procd-ujail package itself, but I did not properly consider the underlying reason why it was absent in the first place: the target is built with the small_flash feature.

So the issue is not simply “ujail missing accidentally”, but rather that the image was intentionally built without it due to flash constraints. In that context, installing procd-ujail afterwards on a running system may lead to unexpected runtime problems or crash loops because the original image/profile was not really designed or validated for that setup.

Your observation about small_flash and the target.mk logic clarified the actual root cause much better. @dave14305