0

I'm getting an error in a script that attempts to mount an external USB drive during service startup:

sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

(Note that the mount action must be synchronous, so putting it anywhere else besides the service's ExecStartPre will not be sufficient. The mount must be a hard dependency of successful service startup. Rule: if the mount fails for any reason, the service doesn't start. I'll work on notifications later.)

Here's my service configuration, running under the context of user admin:

### Editing /etc/systemd/system/[email protected]/override.conf
### Anything between here and the comment below will become the new contents of the file

[Service]
ExecStartPre=/usr/local/bin/mount-sync-drive.sh

### Lines below this comment will be discarded

### /lib/systemd/system/[email protected]
# [Unit]
# Description=Syncthing - Open Source Continuous File Synchronization for %I
# Documentation=man:syncthing(1)
# After=network.target
# StartLimitIntervalSec=60
# StartLimitBurst=4
#
# [Service]
# User=%i
# ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0 --home=/media/pi/MyBook/.config/syncthing
# Restart=on-failure
# RestartSec=1
# SuccessExitStatus=3 4
# RestartForceExitStatus=3 4
#
# # Hardening
# ProtectSystem=full
# PrivateTmp=true
# SystemCallArchitectures=native
# MemoryDenyWriteExecute=true
# NoNewPrivileges=true
#
# # Elevated permissions to sync ownership (disabled by default),
# # see https://docs.syncthing.net/advanced/folder-sync-ownership
# #AmbientCapabilities=CAP_CHOWN CAP_FOWNER
#
# [Install]
# WantedBy=multi-user.target

...and my script:

#!/bin/bash

exec &>> /var/log/syncthing.log
echo ""
date

# Check if /dev/sda1 is already mounted
if ! grep -qs '/dev/sda1' /proc/mounts; then
    # Mount /dev/sda1 to /media/pi/MyBook
    echo "Mounting /dev/sda1 to /media/pi/MyBook"
    sudo mount -v /dev/sda1 /media/pi/MyBook
fi

When I run the script manually as admin, the drive mounts just fine:

pi@RPI:~ $ mount | grep sda1
pi@RPI:~ $ sudo -u admin /usr/local/bin/mount-sync-drive.sh
mount: /dev/sda1 mounted on /media/pi/MyBook.
pi@RPI:~ $ mount | grep sda1
/dev/sda1 on /media/pi/MyBook type ext4 (rw,relatime)

Here're the contents of syncthing.log:

Wed 22 Feb 15:57:43 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Wed 22 Feb 15:57:44 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Wed 22 Feb 15:57:45 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Wed 22 Feb 15:57:46 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Here's the service startup error (journalctl doesn't reveal anything further than this):

pi@RPI:~ $ sudo systemctl status [email protected][email protected] - Syncthing - Open Source Continuous File Synchronization for admin
     Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/[email protected]
             └─override.conf
     Active: failed (Result: exit-code) since Tue 2023-02-21 17:23:14 AKST; 33s ago
       Docs: man:syncthing(1)
    Process: 959 ExecStartPre=/usr/local/bin/mount-sync-drive.sh (code=exited, status=1/FAILURE)
        CPU: 53ms

Feb 21 17:23:14 RPI systemd[1]: [email protected]: Scheduled restart job, restart counter is at 4.
Feb 21 17:23:14 RPI systemd[1]: Stopped Syncthing - Open Source Continuous File Synchronization for admin.
Feb 21 17:23:14 RPI systemd[1]: [email protected]: Start request repeated too quickly.
Feb 21 17:23:14 RPI systemd[1]: [email protected]: Failed with result 'exit-code'.
Feb 21 17:23:14 RPI systemd[1]: Failed to start Syncthing - Open Source Continuous File Synchronization for admin.

Correct me if I'm mistaken please, but I believe I've eliminated all possibilities indicated in the mount error message:

1. is /usr/bin/sudo on a file system with the 'nosuid' option set:

pi@RPI:~ $ mount | grep nosuid
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,size=186292k,nr_inodes=819200,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
bpf on /sys/fs/bpf type bpf (rw,nosuid,nodev,noexec,relatime,mode=700)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
tracefs on /sys/kernel/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)
fusectl on /sys/fs/fuse/connections type fusectl (rw,nosuid,nodev,noexec,relatime)
configfs on /sys/kernel/config type configfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=93144k,nr_inodes=23286,mode=700,uid=1000,gid=1000)

2. is /usr/bin/sudo on a file system with an NFS file system without root privileges:

pi@RPI:~ $ df -T /usr/bin/sudo
Filesystem     Type 1K-blocks    Used Available Use% Mounted on
/dev/root      ext4  30343244 4241732  24811444  15% /

I've added admin to the sudoers file using visudo and rebooted for good measure:

admin ALL=(ALL) NOPASSWD: /bin/mount

The very odd thing is that I have another similar system that runs this just fine. I've checked and double-checked all the configurations, and they're the same.

What does it mean, sudo: effective uid is not 0, and how does one fix it?

--EDIT--

Per a question by @ajgringo619 in the comments:

pi@RPI:~ $ sudo -lU admin
Matching Defaults entries for admin on RPI:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+=NO_AT_BRIDGE, env_keep+="http_proxy
    HTTP_PROXY", env_keep+="https_proxy HTTPS_PROXY", env_keep+="ftp_proxy FTP_PROXY", env_keep+=RSYNC_PROXY, env_keep+="no_proxy NO_PROXY"

User admin may run the following commands on RPI:
    (ALL : ALL) ALL
    (ALL) NOPASSWD: /bin/mount

--EDIT--

Per a question by roaima in the comments:

pi@RPI:~ $ ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 178432 Jan 14 04:29 /usr/bin/sudo
4
  • What does sudo -l return? Maybe try using the full path for mount in the script. Commented Feb 23, 2023 at 20:16
  • I've edited my question to add the output of sudo -lU admin. FYI it's exactly the same on the system on which this is working.
    – InteXX
    Commented Feb 23, 2023 at 20:34
  • I edited the script to include the full path, but there's no improvement. I think the problem is with sudo, not mount.
    – InteXX
    Commented Feb 23, 2023 at 20:35
  • @roaima — Output added.
    – InteXX
    Commented Feb 23, 2023 at 20:49

3 Answers 3

2

Your script has if ! grep -qs '/dev/sda1' /proc/mounts; then, which I assume is to address the issue of running this script for each instance of [email protected]. If another instance is running (or ran in the past), then the mount will already exist, and so this check is necessary or your ExecStartPre= will fail.

My other answer describes how to remove sudo from your script, but another solution is to replace your script with systemd's built-in mount units.

The unit can be as simple as:

# /etc/systemd/system/media-pi-MyBook.mount
[Mount]
What=/dev/sda1
Where=/media/pi/MyBook

Then, instead of having this in your override:

# /etc/systemd/system/[email protected]/override.conf
[Service]
ExecStartPre=/usr/local/bin/mount-sync-drive.sh

Do this to ensure the mount is available and running before running your service.

# /etc/systemd/system/[email protected]/override.conf
[Unit]
Requires=media-pi-MyBook.mount
After=media-pi-MyBook.mount

Now you can delete your custom script.

This takes care of several issues, such as being able to control when the unit is unmounted, and ensuring the mount exists for each instance of the template without any extra checks.

To unmount, simply sudo systemctl stop media-pi-MyBook.mount and any services which Requires= it will be automatically stopped. That's something which is much harder to script, especially when you have lots of instances of the template.

One extra detail:

The override I recommended is in [email protected]/ instead of [email protected]/. This means the dependency will exist for every instance of the syncthing@ template and not just for syncthing@admin.

2
  • I really like this solution. It's clean, elegant and simple. It's definitely one for the bag of tricks. It works, and it's the one I'm staying with.
    – InteXX
    Commented Mar 1, 2023 at 1:08
  • That's excellent +1 Commented Mar 1, 2023 at 8:02
1

Start with a status check:

systemctl show [email protected] | grep -E 'ProtectSystem|NoNewPrivileges'

The likelihood is that you've got NoNewPrivileges enabled. The result of this is that your process is not permitted to become root, so sudo cannot operate.

If this is the case you need to disable that setting. See my answer to rsyncd service ProtectSystem=off has no effect, which is similar but not a duplicate, for a full explanation of how to change these values

5
  • I made those suggested edits, ended up with ProtectSystem=no and NoNewPrivileges=no. Still same error: sudo: effective uid is not 0 ...
    – InteXX
    Commented Feb 23, 2023 at 22:27
  • I'm between a rock and a hard place. I've been fighting this for three straight days now, and I've come up with a clunky workaround that'll at least let me start syncing my files (which is at least a two-day job in itself). The workaround is an automount in /etc/fstab (which breaks my rule) and an infinite loop in the script, with a one-second sleep, that breaks when the mount is found. Trouble is, though, once I kick that sync job off, I won't be able to try any other suggestions for the duration. I'll be stuck, unable to provide you with valuable feedback. But I'm going to have to do it.
    – InteXX
    Commented Feb 23, 2023 at 22:41
  • 1
    Yes, I did. Sync is running now, so I'm on hiatus for a couple of days. But I welcome any insights you may have in the meantime. I'm open for discussion during this time, of course, but I'm unable to attempt any troubleshooting until the sync is finished.
    – InteXX
    Commented Feb 23, 2023 at 23:31
  • The sync finally finished, but I ended up going with @stewart's [mount] / [unit] suggestion. It works great, and I was able to get rid of the script altogether.
    – InteXX
    Commented Mar 1, 2023 at 7:47
  • I bumped you up a notch just now 'cause that's some good info you posted. I'll keep that one in mind during this my 7G learning curve.
    – InteXX
    Commented Mar 2, 2023 at 0:31
0

sudo is not intended for script invocation. It is intended to authenticate that an interactive user.

You should try to rework your script to avoid sudo. Your script only applies sudo to one line, but the other lines don't do too much, so it's not unreasonable to extend root permissions to that too.

man systemd.service describes "Special executable prefixes". These are prefixes you can use in your ExecStartPre= to change the behaviour. You are particularly interested in + which runs the script with full privileges.

In your drop-in, simply add that + before the path of your script:

[Service]
ExecStartPre=+/usr/local/bin/mount-sync-drive.sh

Then you can remove sudo from your script:

#!/bin/bash

exec &>> /var/log/syncthing.log
echo ""
date

# Check if /dev/sda1 is already mounted
if ! grep -qs '/dev/sda1' /proc/mounts; then
    # Mount /dev/sda1 to /media/pi/MyBook
    echo "Mounting /dev/sda1 to /media/pi/MyBook"
    mount -v /dev/sda1 /media/pi/MyBook
fi

Extra credit: You have a lot of logging in here. Note that mount already prints what it has done to stdout, so your echo command is a little redundant. You also echo a newline and the date. By default, your unit logs all of your script's stdout to the journal with the date automatically. Therefore if you choose to use the journal, yopu can remove that stuff to simplify the script.

#!/bin/bash

if ! grep -qs '/dev/sda1' /proc/mounts; then
    mount -v /dev/sda1 /media/pi/MyBook
fi

Then you can check the output with:

$ sudo journalctl -u syncthing*
Feb 21 17:23:14 RPI systemd[1]: Started [email protected] - Syncthing - Open Source Continuous File Synchronization for admin
Feb 21 17:23:14 RPI mount-sync-drive.sh[1234]: mount: /dev/sda1 mounted on /media/pi.
1
  • FYI this one didn't pay off, I'm afraid. The service started, yes, but without a mounted drive. It created its own default config, as is its expected behavior when starting the first time without an existing config. Not sure what went wrong. I checked and double-checked to make sure I had things as you describe. Not to worry, though—I prefer your [Mount] / [Unit] solution. It's by far the best way to go.
    – InteXX
    Commented Mar 1, 2023 at 1:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .