What is the safest way for programmatically writing to a file with root privileges?

You don't need to give sudo access to echo. In fact, that's pointless because, e.g. with sudo echo foo > bar, the redirection is done as the original user, not as root.

Call the small script with sudo, allowing NOPASSWD: access to ONLY that script (and any other similar scripts) by the user(s) who need access to it.

This is always the best/safest way to use sudo. Isolate the small number of commands that need root privileges into their own separate script(s) and allow the un-trusted or partially-trusted user to only run that script as root.

The small sudo-able script(s) should either not take args (or input) from the user (i.e. any other programs it calls should have hard-coded options and args) or it should very careful validate any arguments/input that it has to accept from the user.

Be paranoid in the validation - rather than look for 'known bad' things to exclude, allow only 'known good' things and abort on any mismatch or error or anything even remotely suspicious.

The validation should occur as early in the script as possible (preferably before it does anything else as root).


I really should have mentioned this when I first wrote this answer, but if your script is a shell script it MUST properly quote all variables. Be especially careful to quote variables containing input supplied by the user in any way, but don't assume some variables are safe, QUOTE THEM ALL.

That includes environment variables potentially controlled by the user (e.g. "$PATH", "$HOME", "$USER" etc. And definitely including "$QUERY_STRING" and "HTTP_USER_AGENT" etc in a CGI script). In fact, just quote them all. If you have to construct a command line with multiple arguments, use an array to build the args list and quote that - "${myarray[@]}".

Have I said "quote them all" often enough yet? remember it. do it.


Check the owner on the gpio files:

ls -l /sys/class/gpio/

Most likely, you'll find out that they are owned by group gpio:

-rwxrwx--- 1 root     gpio     4096 Mar  8 10:50 export
...

In that case, you can simply add your user to the gpio group to grant access without sudo:

sudo usermod -aG gpio myusername

You'll need to logout and log back in after that for the change to take effect.


One solution for this (used particularly on the Linux desktop but also applicable in other cases) is to use D-Bus to activate a small service running as root and polkit to do the authorization. This is fundamentally what polkit was designed for; from its introductory documentation:

polkit provides an authorization API intended to be used by privileged programs (“MECHANISMS”) offering service to unprivileged programs (“CLIENTS”). See the polkit manual page for the system architecture and big picture.

Rather than execing your helper program, the big, unprivileged program would send a request on the bus. Your helper could either be running as a daemon started at system boot, or, better, be activated as needed by systemd. Then, that helper would use polkit to verify that the request is coming from an authorized place. (Or, in this case, if that feels like overkill, you could use some other hard-coded authentication/authorization mechanism.)

I found a good basic article on communicating via D-Bus, and while I haven't tested it, this appears to be a basic example of adding polkit to the mix.

In this approach, nothing needs to be marked setuid.