1

In code like this in a daemon:

// run as root, after initgroups(...), setgid(...)
setuid(user);
const char* args[] = {"./userbinary",0};
execv("userbinary", args);
_exit(1);

there's an obvious problem where the user can attach to the process between the calls to setuid and exec[lvpe], and read out all the process's memory, including sensitive variables and state.

A workaround I use is like this (obviously, all error handling ommitted):

// run as root in daemon
const char* args = {"/usr/bin/mysetuid", uidStr, "./userbinary", 0};
execv("/usr/bin/mysetuid", args);
_exit(1);

// mysetuid.c:
int main(int arc, char* argv[]) {
  setuid(atoi(argv[1]));
  execv(argv[2], argv+2);
  exit(1);
}

What is the "standard" way of doing this operation? Using a helper binary seems safest, but I can't find other applications that do this. For example, OpenSSH just relies on the fact that each user's connection gets its own process, so the setuid is always done from a process that has pretty much a blank slate.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Nicholas Wilson
  • 9,435
  • 1
  • 41
  • 80
  • Why are you not stripping sensitive data before dropping the privs? (Command line arguments and environment variables are _never_ sensitive data; they're always readable by any user.) – Donal Fellows Jan 16 '14 at 11:54
  • We try, but it's a faff. Consider the problems with encapsulation – you have to go fishing in your whole codebase for anything that might be dangerous, and hope you didn't forget to zero out anything. With the helper approach, it's much simpler and cleaner, so that you don't have to second-guess what sort of state might be interesting to an attacker. I'm just surprised it doesn't seem to be common. – Nicholas Wilson Jan 16 '14 at 12:16

0 Answers0