I am learning C and have run into a small problem. After reading about fork() bomb on Wikipedia and on StackOverflow. I wanted to implement the same, but using command line args.
I want to endlessly call firefox/chrome, but unable to do the same in my below program. Any assistance would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
pid_t pid;
char *parmList[] = {"firefox", "index.html", NULL};
int a;
if ((pid = fork()) == -1)
{
perror("fork failed");
}
if (pid == 0)
{
a = execvp("/usr/bin/firefox", parmList);
fprintf(stdout, "execvp() returned %d\n", a);
fprintf(stdout, "errno: %s (%d).\n", strerror(errno), errno);
}
else
{
waitpid(pid, 0, 0);
}
return 0;
}
You should clarify what error you're getting, since I don't want to run a fork bomb, but the code you wrote doesn't bomb (call fork() within a loop). It spawns one process, waits nicely, and quits.
Related
I would like to create a named pipe in the parent process and after write a string to it in the child process and finally read this string in the parent process. When run the program I dont get back the prompt like still waiting for end of child process. Why the child process not finished?
Current output:
Expected output:
(picture created without multiprocesses)
My source code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int pipefd[2];
pid_t cpid;
char szoveg[32];
int fd, ret;
char buf[32];
buf[0]=0;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(-1);
}
if (cpid == 0) {
printf("%d: Child process\n",getpid());
strcpy(buf,"Some text \0");
printf("%d:write to fifo: %s:%ld\n",getpid(),buf,strlen(buf));
write(fd,buf,strlen(buf));
exit(0);
} else {
printf("%d: Parent process\n",getpid());
ret=mkfifo("FifoName",00666);
if (ret == -1) {
perror("mkfifo()");
exit(-1);
}
fd=open("FifoName",O_RDWR);
if (fd == -1) {
perror("open() error!");
exit(-1);
}
wait(NULL);
ret=read(fd,buf,32);
printf("%d:read() Read %d bytes: %s\n",getpid(),ret,buf);
close(fd);
unlink("FifoName");
exit(0);
}
}
William Pursell right. The problem was the missing fd=open("FifoName",O_RDWR); line from child process.
I have a binary from which I need to intercept a certain syscall--in this case unlinkat--and make it do nothing. I have the following code which works fine for a single process; however, with PTRACE_O_TRACECLONE added to the ptrace opts, after the tracee makes a call to clone, the waitpid call hangs forever. I've been pulling my hair out for days on different parts of the internet, to the point where I was going through the source of strace, and had in fact straced strace to see what the strace I had straced was ptracing.
Here's the source--I removed some stuff to make it as minimal as possible for readability.
#define _POSIX_C_SOURCE 200112L
// std (i think)
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// linux
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#define OPTS PTRACE_O_TRACESYSGOOD // | PTRACE_O_TRACECLONE | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEFORK
#define WOPTS 0
/* The TRACEE. Executes the process we want to target with PTRACE_TRACEME */
int do_child(int argc, char **argv) {
char *args[argc + 1];
memcpy(args, argv, argc * sizeof(char *));
args[argc] = NULL;
ptrace(PTRACE_TRACEME);
kill(getpid(), SIGSTOP);
return execvp(args[0], args);
}
/* Waits for the next syscall and checks to see if the process has been exited */
int wait_for_syscall(pid_t child) {
int status;
while (1) {
ptrace(PTRACE_SYSCALL, child, 0, 0);
waitpid(child, &status, WOPTS); // <--- THIS CALL HANGS FOREVER AFTER CLONE
if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80)
return 0;
if (WIFEXITED(status))
return 1;
}
return -1; // unreachable
}
/* The TRACER. Takes the pid of the child process that we just started and actually does the
PTRACE stuff by passing signals back and forth to that process. */
int do_trace(pid_t child) {
int status, syscall;
waitpid(child, &status, WOPTS);
ptrace(PTRACE_SETOPTIONS, child, 0, (unsigned long)OPTS);
while (1) {
// ptrace(PTRACE_SYSCALL) really needs to be called twice, first is before entry second is after exit, but idgaf
if (wait_for_syscall(child) != 0) {
break;
}
syscall = ptrace(PTRACE_PEEKUSER, child, sizeof(long) * ORIG_RAX);
switch (syscall) {
case SYS_clone:
fprintf(stderr, "DEBUG: clone detected\n");
break;
case SYS_unlinkat:
fprintf(stderr, "DEBUG: unlinkat detected\n");
ptrace(PTRACE_POKEUSER, child, sizeof(long) * RAX, 0);
break;
}
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s prog args\n", argv[0]);
exit(1);
}
pid_t child = fork();
if (child == 0) {
return do_child(argc - 1, argv + 1);
} else {
return do_trace(child);
}
return 0;
}
Just as a disclaimer, I am NOT a C developer, these days I mainly write Python, so a lot of this was just copied and pasted from different tutorials I found and I basically added/removed random shit until gcc didn't give me that many warnings.
Based on what I've read, I suspect the issue is something about raising signals to the processes involved and waiting for a SIGTRAP, I just have no real intuition on what to do at that level.
The solution was using libseccomp instead.
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <seccomp.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
int do_child(int argc, char **argv)
{
char *args[argc + 1];
memcpy(args, argv, argc * sizeof(char *));
args[argc] = NULL;
return execvp(args[0], args);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s prog args\n", argv[0]);
exit(1);
}
// Init the filter
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW); // default allow
// setup basic whitelist
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(0), SCMP_SYS(unlinkat), 0);
// build and load the filter
seccomp_load(ctx);
pid_t child = fork();
if (child == 0)
{
return do_child(argc - 1, argv + 1);
}
return 0;
}
I am trying to write a program that will fork, then open a file and execute it. The file it should execute is called child and it has been compiled. When I type ./child, it runs. However, when I run this program it does not execute the child program and I am prompted with the error message I put in "Execution failed". What I am doing wrong?
This is my parent class
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main (int argc, char **argv)
{
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
int var = execvp("./child", NULL);
if(var < 0)
{
printf("Execution failed");
}
}
exit(0); // exec never returns
}
This is the child
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
printf ("Im the child");
exit (0);
}
I actually don't know what you are doing wrong. After a copy and a compilation (and several warning complains) your code runs fine (GCC 7.2).
Obviously, child must be in the same working directory in which you run your main executable (the one that forks).
But probably I would write that code in this way, but I'm not an expert in forking:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
extern int errno;
int main () {
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
if (pid == 0) {
int ret = execl("./child", "", (char *)NULL);
if(ret < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
} else {
wait(NULL);
}
return 0;
}
At least it tells you which error execl has encountered.
I'm trying to use date and wc with pipes on CentOS. I'm not able to printf that I'm in parent or child. Any help is appreciated.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
/* pipe1.c - send information through pipe. */
void syserr(char* msg)
{
printf("%s", msg);
}
void child(int pfd[]){
dup2(pfd[1],1);
execl("/bin/date", "date", 0);
}
void main()
{
int pfd[2], i, pid;
char str[] = "Hello World!\n";
if (pipe(pfd) == -1)
syserr("pipe");
printf("pfd[0] = %d, pfd[1] = %d\n", pfd[0], pfd[1]);
pid=fork();
switch(pid) {
case -1:
syserr("fork");
case 0:
{
printf("I'm child'");
child(pfd);
}
default:{ /* parent only */
if(pid!=0)
{
printf("I'm parent'");
dup2(pfd[0],0); //input
execl("/bin/wc", "wc", 0);
}/*default*/
} /*switch*/
}
}
Remember that <stdio.h> is buffered, and stdout is generally line-buffered, at least when it is a terminal. See setvbuf(3)
So you should either end each of your printf format control string with a \n or call fflush(3) at appropriate places. In particular, do a fflush(NULL); before your fork and your execl.
Also use perror on failure (i.e. replace every call to syserr by perror) to understand how system calls are failing. See perror(3) & errno(3) & strerror(3).
BTW, your main is incorrectly declared. You should enable all warnings and debug info when compiling (e.g. compile with gcc -Wall -Wextra -g). Improve your code to get no more warnings. Then use the debugger gdb ...
Notice that to avoid zombie processes, your parent process should use some waiting system call like waitpid(2) or wait(2) or wait4(2)
Works now. I had to add close(pfd[0]); in child, and close(pfd[1]); in parent.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
/* pipe1.c - send information through pipe. */
void child(int pfd[]){
printf("I'm in child func\n");
close(pfd[0]);
dup2(pfd[1],1);
execl("/bin/date", "date", 0);
}
int main(){
int pfd[2], pid;
if (pipe(pfd) == -1) perror("pipe");
printf("pfd[0] = %d, pfd[1] = %d\n", pfd[0], pfd[1]);
fflush(NULL);
pid=fork();
switch(pid) {
case -1:
perror("fork");
case 0:
{
printf("I'm child\n");
child(pfd);
}
default:{ /* parent only */
if(pid!=0){
printf("I'm daddy\n");
close(pfd[1]);
dup2(pfd[0],0); //input
execl("/bin/wc", "wc", 0);
}/*default*/
} /*switch*/
}
return 0;
}
I already used execl() in code, and it worked well.
But this time, I really have no idea why it doesn't work.
So here's the code that do not work
#include <unistd.h>
#include <stdio.h>
int main()
{
int i = 896;
printf("please\n");
execl("home/ubuntu/server/LC/admin/admin", (char*)i, NULL);
printf("i have no idea why\n");
return 0;
}
And here's the admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int mid = argv[0];
printf("hi from child\n");
printf("%d\n", mid);
return 0;
}
Of course I compiled admin.c to admin, and the path isn't wrong.
>ls
admin admin.c why why.c
>pwd
/home/ubuntu/server/LC/admin
>./admin
hi from child
-1180858374
>./why
please
i have no ida why
Anyone know why it doesn't work?
My C is a bit rusty but your code made many rookie mistakes.
execl will replace the current process if it succeeds. So the last line ("i have no idea why") won't print if the child can launch successfully. Which means...
execl failed and you didn't check for it! Hint: check the typecast to char *.
You cast an int to a char * in the execl call, then again when you launch the child (admin). This is a big no-no in C. It freely allows you to misinterpret types. The only warning is most often a crash. GGC will warn you about it. I don't know about the compiler on AWS.
Check your array's bound! You don't know how many parameters admin was launched with. argv[0] always exist because it contains a representation of the program name. argv[1] may not be defined. Accessing array out-of-bound is an undefined behavior and highly dangerous.
The standard way to start another process in C is to fork the parent, then call one of the functions in the exec family to start the other process.
Consider this instead (I took the liberty to emit different messages to make them clearer).
parent.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main()
{
int i = 896;
char str[15];
int pid;
printf("Hello from parent\n");
sprintf(str, "%d", i); // convert the number into string
pid = fork();
if (pid == -1)
{
printf("Fork failed\n");
}
else if (pid == 0)
{
printf("Continue from parent\n");
}
else
{
// start the child process
execl("home/ubuntu/server/LC/admin/admin", str, NULL);
// check if it started properly
if (errno != 0)
{
printf("Error launching child process: %s\n", strerror(errno));
return 1;
}
}
printf("Goodbye from parent\n");
return 0;
}
admin.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char * mid;
// argc is always 1 or more
if (argc >= 2)
mid = argv[1];
else
mid = "<nothing>";
printf("hello from child\n");
printf("argc = %d, argv[1] = %s\n", argc, mid);
return 0;
}