A setgid share that still is not writable, and a narrowly scoped sudo rule that is not narrow
A shared build area /srv/build is owned root:devs with mode 2775. alice, bob and carol are members of devs. Alice creates artifacts that bob cannot overwrite: files appear as alice:devs with mode 0644, and directories she creates are 0755. Alice was added to the devs group 20 minutes ago and is still using the SSH session she logged in with this morning. A new user dave needs passwordless sudo for exactly one command, /usr/bin/systemctl restart builder, and nothing else. dave is currently also a member of the wheel group, which has a blanket ALL=(ALL) ALL rule in /etc/sudoers. The builder unit's ExecStart points at /srv/build/builder.sh, which alice can write.
1. Explain why the setgid bit is not enough here, and give the fix for future files, for alice's current session, and for the files already on disk.
Read the worked answer
Setgid on a directory only forces the group owner of new entries. It does not change the permission bits, which come from the creating process's umask. Alice's session has umask 0022, so files land 0644 and directories 0755 - the group gets r-x, so bob cannot overwrite.
Also, alice's running session predates her group addition: id in her shell will not show devs. Because the directory is setgid, new files still get group devs (setgid overrides the creator's primary group), which is why the symptom looks like a permissions problem and not a group-membership problem. Check both:
id alice # in her session - no devs yet (supplementary groups are fixed at login)
getent group devs
stat -c '%a %U:%G' /srv/build
Fix, in order:
- Alice re-logs in, or runs
newgrp devsfor the current shell. - Set a per-user or per-directory umask of 0007 (
/etc/profile.d/devshare.sh, orumask 0007in the shared shell profile) so new files are 0660 and dirs 0770. - Repair what exists, without flattening the setgid bit:
find /srv/build -type d -exec chmod 2770 {} +
find /srv/build -type f -exec chmod 0660 {} +
chgrp -R devs /srv/build
Default ACLs (setfacl -R -m g:devs:rwX -m d:g:devs:rwX /srv/build) are the alternative when you cannot control every user's umask - they apply regardless of who creates the file.
2. dave's sudo rule as requested is `dave ALL=(root) NOPASSWD: /usr/bin/systemctl restart builder`, placed in /etc/sudoers.d/50-dave. Evaluate whether it works, and what you would check before declaring it done.
Read the worked answer
Syntax is fine; behaviour is not what was asked. Two things to check:
- sudoers is last-match, not first-match. The blanket
ALL=(ALL) ALLfor%wheelwill still apply if it is evaluated later (or is unqualified in a way that wins for other commands). dave keeps full root access, and the narrow rule is decorative. Verify from outside dave's session:
sudo -l -U dave
sudo -l -U dave | grep -i 'systemctl restart builder'
If the output still says (ALL : ALL) ALL, either remove dave from wheel (the real fix, if he only needs this one command) or add a targeted ! revocation, realising that negations are fragile and hard to audit.
- Exact-argument matching. sudo compares the command line as typed, so
/usr/bin/systemctl restart builder.serviceorrestart builder --no-blockwill not match and will fall through to the wheel rule - where they silently succeed with full root. That means the narrow rule is not the boundary you think it is. Test the variants, includingsystemctl restart builder; id.
Also: visudo -cf /etc/sudoers.d/50-dave, file mode 0440, and no dots in the filename (sudoers.d ignores names containing .). Then re-run sudo -l -U dave after every change - that command is the only evidence that matters.
3. Given that builder.sh lives in /srv/build and alice can write to it, what does dave's passwordless restart actually grant, and how do you close it?
Read the worked answer
It grants root to alice, via dave. dave can restart builder; the service executes /srv/build/builder.sh, which alice controls (mode 0660, group devs, and she is in devs). Whoever writes that script decides what runs as the unit's User= - and if the unit runs as root, that is direct root code execution with a restart as the trigger. Even a non-root unit is a lateral move onto every credential that unit can read.
Close it in this order:
- Move the executed payload out of the shared writable tree:
/usr/local/libexec/builder.sh,root:root 0755. ChangeExecStart=to match./srv/buildbecomes data only, never code. - Confirm ownership on the whole execution chain:
systemctl cat builder(unit file and any drop-ins must be root-owned),find /usr/local/libexec -perm -o+w, and check the unit'sUser=,EnvironmentFile=andWorkingDirectory=for anything writable by devs. - Only then re-verify with
sudo -l -U daveand by running the permitted command as dave.
The judgment point: a sudo rule is only as narrow as the command it launches. If the launched artifact is user-writable, NOPASSWD on one command is equivalent to ALL for whoever can edit that artifact - and they need no sudo at all.