How to kill "fast fork()" process without reboot? - linux

I've found a Torjan on Linux system, it uses a method called "fast fork", like the code below
while(1)
{
count += 1;
pid_t pid = fork();
if (pid < 0)
{
printf("there is something wrong\n");
}
if (pid > 0) // father process
{
/* every 0x1000 times fork run the evil code once */
if (count & 0xfff)
{
exit(0);
}
/* stop the program if the job isn't done in XXs */
alarm(XX);
// evil code
}
}
It's really effective and you can't find it via ps aux, is there anyway to find the process and kill it without reboot?
P.S. The code runs as a normal user (not root) and I don't have root access either.

If the process name doesn't change after each fork, you can use a method called "fast kill", like this
$ while true; do killall -9 process_name; done
(but how to get the process name if the origin file has been removed? sorry I don't have enough reputation to add a comment)

Related

How is bash able to kill children processes with CTRL+C

I wrote a simple program as follows -
int main(int argc, char* argv[]) {
setuid(0);
setgid(0);
printf("Current uid and euid are %d, %d\n", getuid(), geteuid());
while(1);
}
I compiled this as root and set the setuid bit using sudo chmod +s test.
When this program is run as a non-privileged user from bash, the program prints -
Current uid and euid are 0, 0
and then gets stuck in an infinite loop.
However I can still kill this process by pressing Crl+C. If I understand correctly, bash(running as a non-privileged user) should not be able to send SIGINT to a root process.
I also tried the same with kill <pid of test> and that fails as excepted.
How is bash able to kill the process? Is there a special relationship between the parent process and the child process?
I also tried this other wrapper program -
int main(int argc, char* argv[]) {
pid_t p = fork();
if (p == 0) {
char * args[] = {"./test", NULL};
execv("./test", args);
} else {
sleep(4);
int ret = kill(p, 9);
printf("Kill returned = %d\n", ret);
return 0;
}
}
And ran it as an unprivileged user (where test has setuid bit set by root). In this case the parent is not able to kill the child. the kill call returns -1 and the test process gets orphaned.
What is happening here? What does bash do special that it can kill the children processes it spawns?
Bash doesn't need any permissions because bash isn't doing anything. When you hit ^C, SIGINT is sent to all processes in the foreground process group by the tty driver. The signal comes from the system, not from another process, so the permission checks relevant to one process sending a signal to another don't apply.

How do I kill linux spawnProcess when the main process suddenly dies?

I have come across a problem with my application and the spawnProcess.
If the main application for some reason dies/is killed then the spawned processes seem to live on and I can't reach them unless I use terminal to kill them via their PIDs. My goal is if the main application dies then the spawned processes should be killed also, somehow.
My code is like this
auto appPid = spawnProcess("path/to/process");
scope(exit){ auto exitcode = wait(appPid);
stderr.writeln(...);}
And if I use the same approach when the main process dies, using wait(thisProcessID) I get an error. "No overload matches". Any ideas how to solve this problem?
Here's some code that will do it on Linux. It doesn't have all the features of the stdlib's spawnProcess, it just shows the bare basics, but expanding it from here isn't hard if you need more.
import core.sys.posix.unistd;
version(linux) {
// this function is Linux-specific
import core.stdc.config;
import core.sys.posix.signal;
// we can tell the kernel to send our child process a signal
// when the parent dies...
extern(C) int prctl(int, c_ulong, c_ulong, c_ulong, c_ulong);
// the constant I pulled out of the C headers
enum PR_SET_PDEATHSIG = 1;
}
pid_t mySpawnProcess(string process) {
if(auto pid = fork()) {
// this branch is the parent, it can return the child pid
// you can:
// import core.sys.posix.sys.wait;
// waitpid(this_ret_value, &status, 0);
// if you want the parent to wait for the child to die
return pid;
} else {
// child
// first, tell it to terminate when the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
// then, exec our process
char*[2] args;
char[255] buffer;
// gotta copy the string into another buffer
// so we zero terminate it and have a C style char**...
buffer[0 .. process.length] = process[];
buffer[process.length] = 0;
args[0] = buffer.ptr;
// then call exec to run the new program
execve(args[0], args.ptr, null);
assert(0); // never reached
}
}
void main() {
mySpawnProcess("/usr/bin/cat");
// parent process sleeps for one second, then exits
usleep(1_000_000);
}
So the lower level functions need to be used, but Linux does have a function that does what you need.
Of course, since it sends a signal, your child might want to handle that to close more gracefully than the default termination, but try this program and run ps while it sleeps to see cat running, then notice the cat dies when the parent exits.

How to keep track of child processes

So my program spawns a number of child processes in response to certain events, and I'm doing something ike this to keep track and kill them upon program exit (Perl syntax):
my %children = ();
# this will be called upon exit
sub kill_children {
kill 'INT' => keys %children;
exit;
}
# main code
while(1) {
...
my $child = fork();
if ($child > 0) {
$children{$child} = 1;
} elsif ($child == 0) {
# do child work ...
exit();
} else {
# handle the error
}
}
So the idea is as above. However, there's a blatant race condition there, in that a given child can start and terminate before the father has a chance to run and record its pid in the %children hash. So the father may end up thinking that a given pid belongs to an active child, even if this child has terminated.
Is there a way to do what I'm trying to accomplish in a safe way?
Edit: To better keep track of children, the code can be extended as follows (which however also suffer of the exact same race condition, so that's why I didn't write it fully in the first place):
my %children = ();
sub reap {
my $child;
while (($child = waitpid(-1, WNOHANG)) > 0) {
#print "collecting dead child $child\n";
delete $children{$child};
}
}
$SIG{CHLD} = \&reap;
# this will be called upon exit
sub kill_children {
local $SIG{CHLD} = 'IGNORE';
kill 'INT' => keys %children;
exit;
}
# main code
while(1) {
...
my $child = fork();
if ($child > 0) {
$children{$child} = 1;
} elsif ($child == 0) {
# do child work ...
exit();
} else {
# handle the error
}
}
Even in this case, the contents of %children may not reflect the actual active children.
Edit 2: I found this question, which is exactly about the same problem. I like the solution suggested in there.
On UNIX it's not a race condition. This is the standard way to handle fork(). When the child process exits, its status is changed to "terminated"; it becomes a zombie. It still has an entry in the process table until the parent process calls one of the wait functions. Only after that is the dead process really removed.
Even if the parent sets itself up to ignore SIGCHLD, it still wouldn't qualify as a race condition; the parent would just have a PID that's not valid anymore. In that case, wait() would return ECHILD. But setting SIGCHLD would free up a child's PID, possibly leading to the parent trying to kill a process that is not a child.
On Windows, which doesn't have a fork call, it is emulated by creating a thread in the perl process. See perlfork. I'm not knowlegable enough about Windows to opinionate about if that could cause a race condition, but I suspect not.

General Template for Binary Semaphore with processes

I am learning semaphores, and wanted to try out semaphore IPC on a shared memory program I have implemented before. (The program involves sharing the Shared Memory between parent and child process: Reading and writing it etc). When I use a variable and increment it in Parent and decrement it in child, due to Race condition I get unexpected output. So i wanted to synchronize the two using Semaphore. But I needed a starting point, a template to begin with.
I have done the previous shared memory example using such template (initializing,attaching,detaching etc) I found else where. So if anyone can suggest some steps...
What I am trying:
struct shmarea // My shared Memory
{
` unsigned long count;
};
struct shmarea *shma;
main()
{
id = shmget(KEY1,4096,IPC_CREAT|0600);
shma = shmat(id,0,0);
shma->count = 0;
ret = fork();
if(ret>0)
{
printf("in parent .. ppid is %lu ...and pid is %lu\n",getppid(),getpid());
sleep(5);
while(j++ < 2147483645){ // The large loop is to See the processes in top command
while(i++ < 2147483645) shma->count++;
}
}
if(ret==0)
{
printf("in child .. ppid is %lu ...and pid is %lu\n",getppid(),getpid());
while(j++ < 2147483645){
while(i++ < 2147483645) shma->count--;
}
exit(0);
}
if(ret>0)
{
//Clean up
}
}
I did look for Semaphore creation examples..But mostly I am stuck with use of semaphore sets..How to map it with binary semaphore...because in this simple program i just need to have two values 0 and 1.

what can be the reasons for a fork call not entering child code

I have this piece of code in a program function.
And there is a test script which hits this code path.
script goes through this function multiple times (~1000).
fork() call is successful as I can see child pid from parent block syslog but I don't see anything from child block.
This does NOT happen always. Happens only once in a hundred attempts.
Any idea what can be the general reasons for this to happen.
And what should I look for to get more information about the failure.
int i;
if ((i = fork()) < 0) {
syslog(LOG_NOTICE, "(%s): fork failed!\n", __func__);
}
if (i) {
syslog(LOG_NOTICE, "(%s): fork Parent: id: %d\n", __func__, i);
} else {
syslog(LOG_NOTICE, "(%s): fork child\n", __func__);
/* Do something */
}
Output:
telnetd[24600]: (startslave): fork Parent: id: 24601
<Thats it, no log after this!!>
To be exact, this is a part of freeBSD telnetd startslave() code, and script is just trying to login using telnet and logout for 1000 times and it fails sometimes. Failure is guaranteed, it can happen may be after 100 attempts or may be after 700 attempts.

Resources