Get your coredump after setuid(2)
For the sake of security, services are usually running as distinct unpriviledged users, be they started by unpriviledged users or the super user, root.
The problem with starting by an unpriviledged user is that it is sometimes unable to acquire certain resources, notably priviledged ports and huge number of file descriptors for highly concurrent service. There are workarounds in most cases, for instance, port rediection eliminates the need of priviledged ports and system wide limits, see pam_limits(8)
, could be tuned to grant the distinct user the ability to acquire more-than-usual resources, however, these solutions require additional administration work, increasing maintenance burden and probably service instability.
Super power, if applied wisely, makes a better life for anybody. The administrator gets alleviated from the fate of trivality, the developer gets well paid for being sophisticated, and most importantly the employer profits from business supported by ready and sophisticated employees. Your usually have to pay to be wise, but not in the case of this post.
Let’s start the service with super power for it to acquire necessary resources, then it should change to run as some distinct unpriviledged user. A common program flow is
1) with super power, load protected configurations
2) open priviledged ports and protected files, if any
3) raise hard limits of the process according to application configuration
4) `fork`, with the parent and its children connected by `pipe`s and `signal`s
4.1) the parent stays in super power required for few housekeeping work
4.2) the children change to unpriviledged user, and enter businiess cycles
Notice real service is fulfiled by children as an unpriviledged user, with resources inherited from the super parent such as opened priviledged ports and protected files, and raised hard limit, see setrlimit(2)
. The children as workers might be exploited, but it has non of capabilities(7)
that are parcels of super power. The parent does only housekeeping work and accepts simple commands from children, so although it has full capabilities that are beloved of invaders, there is little chance for exploration. Principly safe it is.
However, there’s one problem that may have troubled many developers and that probably force them to turn to clumsy workarounds discussed previously. The ability to produce coredump is lost. The program crashes, but no stacktrace is available, making diagnosis a real headache.
Please hold your rush for workarounds, calm down and read the right manual carefully,
prctl(2)
PR_SET_DUMPABLE
(Since Linux 2.4) Set the state of the flag determining whether
core dumps are produced for this process upon delivery of a sig-
nal whose default behaviour is to produce a core dump. (Nor-
mally this flag is set for a process by default, but it is
cleared when a set-user-ID or set-group-ID program is executed
and also by various system calls that manipulate process UIDs
and GIDs). In kernels up to and including 2.6.12, arg2 must be
either 0 (process is not dumpable) or 1 (process is dumpable).
Since kernel 2.6.13, the value 2 is also permitted; this causes
any binary which normally would not be dumped to be dumped read-
able by root only. (See also the description of
/proc/sys/fs/suid_dumpable in proc(5).)
It should be straightforwad that the missing of coredump is due to the fact that, when changing to run as unpriviledged user, the decisive
dumpable flag is cleared by default. So the natural solution is having it set explicitly right after dropping super power, and because of being unpriviledged, the directory to save coredump files, usually the current directory of the process, should be writable by the effective user of the process. Hence the amendment,
4.2) the children change to unpriviledged user,
switch on dumpable flag, and change to coredump directory,
then enter businiess cycles
Another trival thing to note, you are not changing user by seteuid(2)
, are you? Since effective user, which are checked against permissions, could be set to either real user or saved user, changing by seteuid(2)
merely drops super power temperarily, and that power could be regained afterwards. Do a setuid(2)
instead.