Shell – Launch a sudoed command upon script termination

privilegesshell-scriptsudo

I'm coding a bash script that:

  • runs some sudoed command at initialization
  • releases root permissions for security purposes (sudo -K)
  • runs an unprivilegied program
  • but needs root permissions when terminating

I'm looking for a simple & secure way to avoid asking the user its password again at script termination .

I'm thinking of a fork before sudo -K waiting to catch a term signal. I don't know if that's the most elegant/secure solution.

Here's the code:

sudo unshare -m \
  sudo -u "$USER" -g `id -g -n "$USER"` \
  bash -c \
  "sudo mount --bind \"$MOUNT_DIR\" \"$MOUNT_DIR\"; \
  sudo mount --make-private \"$MOUNT_DIR\"; \
  sudo -K; \
  <unprivilegied program here>; \
  sudo umount \"$MOUNT_DIR\""

NB: For info, this creates a private mount in a namespace that only the program will have acccess to. unshare -r is not an option to run the program in.

Best Answer

I notice that you're doing a lot of switching back and forth between the regular user and root:

  • switch to root to run unshare
  • switch back to the normal user to run bash (although it seems like you don't use any bashisms so you could as well run sh which would be more portable and possibly more lightweight)
  • switch back to root multiple times inside that bash shell to do more privileged things

I think you can simplify this and reduce the number of times to need to bounce back and forth between users and solve your problem at the same time.

sudo unshare -m sh -c '
        mount --bind "$1" "$1";
        mount --make-private "$1";
        exec sudo -u "#$SUDO_UID" -g "#$SUDO_GID" sh -c "
                sudo -K;
                <unprivilegied program here>
        "
' - "$MOUNT_DIR"

Technically, there is a root shell that is continuously running throughout the execution of the unprivileged part, but the only thing that shell is going to do is wait for the unprivileged part to complete and nothing else. But if you really want to give up your sudo privileges ahead of time and not have to ask the user to grant them again, all alternatives are also going to involve a lingering process waiting for the signal to run the umount command in some fashion or other.

As an aside, it's nice that your command is all self-contained and everything, and I kept that spirit in my suggestion, but honestly large blocks of code supplied as a command line option to sh -c are hard to write and read and maintain because of all the quoting complexities you have to worry about, and I would recommend factoring them out into their own script and running the whole thing as:

sudo unshare -m /usr/local/bin/script-that-does-the-rest-of-the-work

Also, doing that would make it easier to write your sudo rules for permitted commands, which are difficult to write using my suggestion unless you permit the user to run any command at all, which is the same as giving them full root access. In this case you'd have to permit the command unshare -m sh -c <huge block> "$MOUNT_DIR" which is a pretty challenging Cmnd_Alias to write.

Related Question