Terminate all child process in LInux - linux

I am developing a sandbox on linux. And now i am confused terminating all process in the sandbox.
My sandbox works as follows:
At first only one process run in the sandbox.
Then it can create several child process.
And child process will create their subprocess also.
And parent process may exit at some time before its children exited.
At last sandbox will terminate all the process.
I used to do this by using killall or pkill -u with a unique user attached to the sandbox.But it seems doesn't work on the program which uses fork() fastly.
Then I search for the source code of pkill and realized that pkill is lose of atomicity.
So how could i achieve my goal ?

You could use process groups setpgid(2) and sessions setsid(2), but I don't qualify what you do as a sandbox (in particular because if one of the processes is setuid or change its process group or session itself, you'll lose it; read execve(2) carefully and several times!). Notice that kill(2) with a negative pid kills an entire process group.
Read a good book like Advanced Linux Programming. Consider also using chroot(2).
And explain what and why you really want to do. sandboxing is harder that what you think. See also capabilities(7), credentials(7) and SElinux.

Related

Is it possible for a process in Linux to change another process's UID?

I was wondering if it was possible for a process in Linux (assuming it had root access) to change another process's UID including the RUID, SUID, and EUID, and if so, if there was a specific implementation I could do (whether that be in C++ or in a bash script, e.t.c). I'm mainly trying to stop certain recurrent processes from executing with root privileges immediately upon spawn, which they seem to upon spawning.
Thanks! My apologies if the question is unclear. If it is, I can clarify any details.
No, it is not possible for one process to change another process's UID. That would be a huge security problem if so. If you're in process A, you don't know what state process B is in, and you don't know if elevating privileges is safe at that point. Similarly, you could cause a privileged process to hog shared resources and deadlock other processes if you forced it to drop privileges unexpectedly, since it might fail in the middle of a critical section.
Even if you could somehow work around this, you'll still run into a race condition that your spawned process could execute any amount of code (how much, you don't know) as root before you can force it to drop privileges.
You should figure out what's spawning your processes and adjust it to either not spawn them as root or prevent it from spawning them at all.

Run a background process and free up terminal won't work with & [duplicate]

I am writing a Linux daemon . I found two ways to do it.
Daemonize your process by calling fork() and setting sid.
Running your program with &.
Which is the right way to do it?
From http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC16
Here are the steps to become a daemon:
fork() so the parent can exit, this returns control to the command line or shell invoking your program. This step is required so that the new process is guaranteed not to be a process group leader. The next step, setsid(), fails if you're a process group leader.
setsid() to become a process group and session group leader. Since a controlling terminal is associated with a session, and this new session has not yet acquired a controlling terminal our process now has no controlling terminal, which is a Good Thing for daemons.
fork() again so the parent, (the session group leader), can exit. This means that we, as a non-session group leader, can never regain a controlling terminal.
chdir("/") to ensure that our process doesn't keep any directory in use. Failure to do this could make it so that an administrator couldn't unmount a filesystem, because it was our current directory. [Equivalently, we could change to any directory containing files important to the daemon's operation.]
umask(0) so that we have complete control over the permissions of anything we write. We don't know what umask we may have inherited. [This step is optional]
close() fds 0, 1, and 2. This releases the standard in, out, and error we inherited from our parent process. We have no way of knowing where these fds might have been redirected to. Note that many daemons use sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells you the maximun open files/process. Then in a loop, the daemon can close all possible file descriptors. You have to decide if you need to do this or not. If you think that there might be file-descriptors open you should close them, since there's a limit on number of concurrent file descriptors.
Establish new open descriptors for stdin, stdout and stderr. Even if you don't plan to use them, it is still a good idea to have them open. The precise handling of these is a matter of taste; if you have a logfile, for example, you might wish to open it as stdout or stderr, and open '/dev/null' as stdin; alternatively, you could open '/dev/console' as stderr and/or stdout, and '/dev/null' as stdin, or any other combination that makes sense for your particular daemon.
Better yet, just call the daemon() function if it's available.
I suggest not writing your program as a daemon at all. Make it run in the foreground with the file descriptors, current directory, process group, etc as given to it.
If you want to then run this program as a daemon, use start-stop-daemon(8), init(8), runsv (from runit), upstart, systemd, or whatever to launch your process as a daemon. That is, let your user decide how to run your program and don't enforce that it must run as a daemon.
Just use daemon(3) (from unistd.h).
The daemon() function is for programs
wishing to detach themselves from the
controlling terminal and run in the
background as system daemons. ...
The first. The second is not daemonizing, but running on the background. Daemonized programs should be on its own session and process group, and should not have a controlling terminal.
Actually to make a daemon you have to double fork.
Running the program with a & makes the shell run the program in the background, which does not make it a daemon. Daemons have init (pid 1) as a parent, that's why the double fork is needed.
So the nice way to do things, if your program is a daemon, would be to take care of this issue yourself (there are more methods, see here too). You could also use the start-stop-daemon program.
What language are you using? Some languages have helper methods that make daemonizing easier. For example, Ruby has the daemons package.

What special precautions must I make for docker apps running as pid 1?

From what I gather, programs that run as pid 1 may need to take special precautions such as capturing certain signals.
It's not altogether clear how to correctly write a pid 1. I'd rather not use runit or supervisor in my case. For example, supervisor is written in python and if you install that, it'll result in a much larger container. I'm not a fan of runit.
Looking at the source code for runit is intersting but as usual, comments are virtually non-existent and don't explain what's being done for what reason.
There is a good discussion here:
When the process with pid 1 die for any reason, all other processes
are killed with KILL signal
When any process having children dies for any reason, its children are reparented to process with PID 1
Many signals which have default action of Term do not have one for PID 1.
The relevant part for your question:
you can’t stop process by sending SIGTERM or SIGINT, if process have not installed a signal handler

Secure method for killing a process and all offspring

I am creating a sandbox environment in Linux using apparmor, setrlimit, cap_set_rpoc to let anonymous users basically execute some arbitrary code on my server in the context of a scientific application. One thing that is specifically allowed in the sandbox is starting new processes by forking and calling executables (although the total number of processes by one user is limited by RLIMIT_NPROC).
After a given time period, say 1 minute, the system will kill the main process, and all of the potential children. I am currently relying on the process group id to identify children. However, in theory, a child process could call setpgid to change its process group, so that it will no longer be affected when I call kill(-1 * pid) on the main process id (correct?). Unfortunately, there is no linux capability that I can set to prevent processes from calling setpgid.
What would be a robust way of killing a process and all of its (recursive) children, which would make it very hard for the children to somehow "escape" the massacre and continue as orphan processes?
If you use lxc (Linux containers) to isolate each process tree, then you can use lxc-stop to kill all the processes in a container. See the "Starting / Stopping a container" section of the lxc manual page.

How do I reliably track child/grandchild processes on a POSIX system?

I have an interesting (at least to me) problem: I can't manage to find a way to reliably and portably get information on grandchildren processes in certain cases. I have an application, AllTray, that I am trying to get to work in certain strange cases where its subprocess spawns a child and then dies. AllTray's job is essentially to dock an application to the task tray, which is (usually) specified as a command line for AllTray to invoke (i.e., alltray xterm would start xterm, and manage it in AllTray).
Most GUI software runs just fine under it. It sets the _NET_WM_PID property on its window (or a widget library does) and all's well, because _NET_WM_PID == fork()ed child. However, in some cases (such as when running oowriter, or software written to run under KDE such as K3b), the child process that AllTray runs is a wrapper, be it a shell script (as in OO.o's case) or a strange program that fork()s and exec()s itself and effectively backgrounds itself, since the parent process dies very early.
I had the idea to not reap my child processes, so as to preserve in the process table the parent process ID for my grandchildren, so that I could link them back to me by traversing the family tree from bottom-to-top. That doesn't work, though: once my child process dies and turns into a zombie, the system considers my grandchild process to be an orphan, and init adopts it. This appears to be the case on at least Linux 2.6 and NetBSD; I'd presume it's probably the norm, and POSIX doesn't seem to specify that to be the case, so I was hoping for the opposite.
Since that approach won't work, I thought about using LD_PRELOAD and intercepting my child process' call to fork(), and passing information back to my parent process. However, I'm concerned that won't be as portable as the ideal solution, because different systems have different rules on how the dynamic linker does things like LD_PRELOAD. It won't work for setuid/setgid GUI applications either without the helper library also being setuid or setgid, at least on Linux systems. Generally, it smells like a bad idea to me, and feels quite hackish.
So, I'm hoping that someone has an idea on how to do this, or if the idea of relying on a mechanism like LD_PRELOAD is really the only option I have short of patching kernels (which is not going to happen).
You could investigate the possibility of using process groups to keep track of, well, process groups. A process group is a property (just a number) which you can set before forking, and child processes then inherit it automatically.
AllTray can create a new process group for each application started with it. You can the send signals to all members of the process group. I suppose the most useful signals here would be TERM and KILL, in order to kill an application managed in AllTray.
I'm not sure if there is a convenient way to figure out if all members of the process group have already exited or not. You may have to resort to going through the entire process list and call getpgid for each process to see if there are any left in the process group.
Note that process groups won't work for applications which create new process groups themselves. But that's relatively rare and you probably don't need to worry about such applications.

Resources