Why does PPID change? - linux

This is my code:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid;
int status;
if ((pid = fork()) < 0) {
printf("Fork failed.");
} else if (pid == 0) {
printf("CHILD:\nPID: %d, PPID: %d, UID: %d\n", pid, getppid(), getuid());
} else {
wait(&status); //wait for child to terminate
printf("PARENT:\nPID: %d, PPID: %d, UID: %d\n", pid, getppid(), getuid());
}
return 0;
}
This is the output:
CHILD:
PID: 0, PPID: 4309, UID: 1000
PARENT:
PID: 4310, PPID: 3188, UID: 1000
Why is 4309 the PPID of the child? Shouldn't it be 4310?
Thnak you.

You didn't print out the parent's PID in the parent code, so you have nothing to compare it to. fork() returns the child's PID to the parent. In your example it appears that the parent has PID 4309 and the child 4310.

Related

Multi Level Single Parent Single Child Process tree?

so I wanted to write a programme where i will create multi level child processes. With single parent and single child.
example: Parent->child1->child2->child3. like that.
See image here
But the problem is I want to take input from terminal how many child processes will be created (single parent - single Child processes).
So How Can I modify that Nested if statement to some loop such that it will create child processes as i wanted it to be.
so Here goes My code
#include<stdio.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
int a, b;
{
if(fork() == 0)
{
printf("child my pid is %d ppid is %d\n",getpid(),getppid());
if(fork()== 0)
{
printf("child my pid is %d ppid is %d\n",getpid(),getppid());
if(fork()== 0)
{
printf("child my pid is %d ppid is %d\n",getpid(),getppid());
}
}
}
else
printf("father my pid is %d ppid is %d\n",getpid(),getppid());
}
for(int i=0;i<3;i++)
wait(NULL);
return 0;
}
OUTPUT GOES HERE:
father my pid is 4496 ppid is 3621
child my pid is 4497 ppid is 4496
child my pid is 4498 ppid is 4497
child my pid is 4499 ppid is 4498
Thanks It's working finally.
Just loop it:
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
int main(int argc, char *argv[])
{
assert(argc == 2);
int num = atoi(argv[1]);
for (int i = 0; i < num; ++i) {
int child;
switch ((child = fork())) {
case 0:
printf("child my pid is %d ppid is %d\n", getpid(), getppid());
break;
case -1:
fprintf(stderr, "fork failed\n");
break;
default:
printf("father my pid is %d ppid is %d and i just created %d\n",getpid(), getppid(), child);
i = num; // break of loop
break;
}
}
wait(NULL);
return 0;
}
#edit:
The break of loop was in the wrong place. Now the process creates a tree of processes as intended:
Compiled the code using gcc and run:
$ ./a.out 5
father my pid is 21893 ppid is 21640 and i just created 21894
child my pid is 21894 ppid is 21893
father my pid is 21894 ppid is 21893 and i just created 21895
child my pid is 21895 ppid is 21894
father my pid is 21895 ppid is 21894 and i just created 21896
child my pid is 21896 ppid is 21895
father my pid is 21896 ppid is 21895 and i just created 21897
child my pid is 21897 ppid is 21896
father my pid is 21897 ppid is 21896 and i just created 21898
child my pid is 21898 ppid is 21897
The program:
starts as pid 21893
creates child with pid 21894
child 21894 creates child 21895
child 21895 creates child 21896
child 21896 creates child 21897
child 21907 creates child 21898

Interprocess communication with messages under linux

So basically, I have 5 processes, which are communicating like this - the 5th process sends its PID to the 4th, the 4th sends its own PID and the 5th's PID to the 3rd process and so on, and in the end the 1st process shows the PIDs of all the other processes. I've done the communication via pipes communication:
#include <sys/unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
int pid,pid1,pid2,pid3;
int fd[2],fd1[2],fd2[2],fd3[2];
pipe(fd);
if( (pid = fork()) != 0 ) { //parent
int temp[5];
close(fd[1]);
read(fd[0],&temp,sizeof(temp));
temp[0]=getpid();
int i;
for(i=0;i<5;i++) {
printf("%d\n",temp[i]);
}
wait(); //wait for the child to complete
}
else { //child
pipe(fd1);
if( (pid1 = fork() ) != 0 ) { //parent
int temp[5];
close(fd1[1]);
read(fd1[0],&temp,sizeof(temp));
temp[1]= getpid();
close(fd[0]);
write(fd[1],&temp,sizeof(temp));
wait();
}
else { //child
pipe(fd2);
if( (pid2 = fork() ) != 0 ) { //parent
int temp[5];
close(fd2[1]);
read(fd2[0],&temp,sizeof(temp));
temp[2]= getpid();
close(fd1[0]);
write(fd1[1],&temp,sizeof(temp));
wait();
}
else { //child
pipe(fd3);
if( (pid3 = fork() ) != 0 ) { //parent
int temp[5];
close(fd3[1]);
read(fd3[0],&temp,sizeof(temp));
temp[3]= getpid();
close(fd2[0]);
write(fd2[1],&temp,sizeof(temp));
wait();
}
else { //child
int temp[5];
temp[4] = getpid();
close(fd3[0]);
write(fd3[1],&temp,sizeof(temp));
}
}
}
}
return 0;
}
But I have hard time doing the communication via messages. I can provide more information if needed. Any suggestion will be greatly appreciated. Thank you in advance for your time.

Does the CHILD_SUBREAPER bit persist across fork()?

When a process sets the child subreaper bit with prctl(PR_SET_CHILD_SUBREAPER, 1) (documented here), does it need to use prctl(PR_SET_CHILD_SUBREAPER, 0) to clear it after a fork?
No, the child subreaper bit does not persist across forks.
The relevant Linux kernel code is in copy_signal() in kernel/fork.c: the signal struct is initialized to all zeros, and the is_child_subreaper bit is never set.
However, has_child_subreaper is set:
sig->has_child_subreaper = current->signal->has_child_subreaper ||
current->signal->is_child_subreaper;
This test program demonstrates the behavior:
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
int main(int argc, char** argv) {
int pid;
int i;
prctl(PR_SET_CHILD_SUBREAPER, 1);
prctl(PR_GET_CHILD_SUBREAPER, &i);
printf("Before fork: %d\n", i);
pid = fork();
if (pid < 0) {
return 1;
} else if (pid == 0) {
prctl(PR_GET_CHILD_SUBREAPER, &i);
printf("In child: %d\n", i);
return 0;
}
return 0;
}
Outputs:
Before fork: 1
In child: 0

Reading a child process's /proc/pid/mem file from the parent

In the program below, I am trying to cause the following to happen:
Process A assigns a value to a stack variable a.
Process A (parent) creates process B (child) with PID child_pid.
Process B calls function func1, passing a pointer to a.
Process B changes the value of variable a through the pointer.
Process B opens its /proc/self/mem file, seeks to the page containing a, and prints the new value of a.
Process A (at the same time) opens /proc/child_pid/mem, seeks to the right page, and prints the new value of a.
The problem is that, in step 6, the parent only sees the old value of a in /proc/child_pid/mem, while the child can indeed see the new value in its /proc/self/mem. Why is this the case? Is there any way that I can get the parent to to see the child's changes to its address space through the /proc filesystem?
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#define PAGE_SIZE 0x1000
#define LOG_PAGE_SIZE 0xc
#define PAGE_ROUND_DOWN(v) ((v) & (~(PAGE_SIZE - 1)))
#define PAGE_ROUND_UP(v) (((v) + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)))
#define OFFSET_IN_PAGE(v) ((v) & (PAGE_SIZE - 1))
# if defined ARCH && ARCH == 32
#define BP "ebp"
#define SP "esp"
#else
#define BP "rbp"
#define SP "rsp"
#endif
typedef struct arg_t {
int a;
} arg_t;
void func1(void * data) {
arg_t * arg_ptr = (arg_t *)data;
printf("func1: old value: %d\n", arg_ptr->a);
arg_ptr->a = 53;
printf("func1: address: %p\n", &arg_ptr->a);
printf("func1: new value: %d\n", arg_ptr->a);
}
void expore_proc_mem(void (*fn)(void *), void * data) {
off_t frame_pointer, stack_start;
char buffer[PAGE_SIZE];
const char * path = "/proc/self/mem";
int child_pid, status;
int parent_to_child[2];
int child_to_parent[2];
arg_t * arg_ptr;
off_t child_offset;
asm volatile ("mov %%"BP", %0" : "=m" (frame_pointer));
stack_start = PAGE_ROUND_DOWN(frame_pointer);
printf("Stack_start: %lx\n",
(unsigned long)stack_start);
arg_ptr = (arg_t *)data;
child_offset =
OFFSET_IN_PAGE((off_t)&arg_ptr->a);
printf("Address of arg_ptr->a: %p\n",
&arg_ptr->a);
pipe(parent_to_child);
pipe(child_to_parent);
bool msg;
int child_mem_fd;
char child_path[0x20];
child_pid = fork();
if (child_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (!child_pid) {
close(child_to_parent[0]);
close(parent_to_child[1]);
printf("CHILD (pid %d, parent pid %d).\n",
getpid(), getppid());
fn(data);
msg = true;
write(child_to_parent[1], &msg, 1);
child_mem_fd = open("/proc/self/mem", O_RDONLY);
if (child_mem_fd == -1) {
perror("open (child)");
exit(EXIT_FAILURE);
}
printf("CHILD: child_mem_fd: %d\n", child_mem_fd);
if (lseek(child_mem_fd, stack_start, SEEK_SET) == (off_t)-1) {
perror("lseek");
exit(EXIT_FAILURE);
}
if (read(child_mem_fd, buffer, sizeof(buffer))
!= sizeof(buffer)) {
perror("read");
exit(EXIT_FAILURE);
}
printf("CHILD: new value %d\n",
*(int *)(buffer + child_offset));
read(parent_to_child[0], &msg, 1);
exit(EXIT_SUCCESS);
}
else {
printf("PARENT (pid %d, child pid %d)\n",
getpid(), child_pid);
printf("PARENT: child_offset: %lx\n",
child_offset);
read(child_to_parent[0], &msg, 1);
printf("PARENT: message from child: %d\n", msg);
snprintf(child_path, 0x20, "/proc/%d/mem", child_pid);
printf("PARENT: child_path: %s\n", child_path);
child_mem_fd = open(path, O_RDONLY);
if (child_mem_fd == -1) {
perror("open (child)");
exit(EXIT_FAILURE);
}
printf("PARENT: child_mem_fd: %d\n", child_mem_fd);
if (lseek(child_mem_fd, stack_start, SEEK_SET) == (off_t)-1) {
perror("lseek");
exit(EXIT_FAILURE);
}
if (read(child_mem_fd, buffer, sizeof(buffer))
!= sizeof(buffer)) {
perror("read");
exit(EXIT_FAILURE);
}
printf("PARENT: new value %d\n",
*(int *)(buffer + child_offset));
close(child_mem_fd);
printf("ENDING CHILD PROCESS.\n");
write(parent_to_child[1], &msg, 1);
if (waitpid(child_pid, &status, 0) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
}
}
int main(void) {
arg_t arg;
arg.a = 42;
printf("In main: address of arg.a: %p\n", &arg.a);
explore_proc_mem(&func1, &arg.a);
return EXIT_SUCCESS;
}
This program produces the output below. Notice that the value of a (boldfaced) differs between parent's and child's reading of the /proc/child_pid/mem file.
In main: address of arg.a: 0x7ffffe1964f0
Stack_start: 7ffffe196000
Address of arg_ptr->a: 0x7ffffe1964f0
PARENT (pid 20376, child pid 20377)
PARENT: child_offset: 4f0
CHILD (pid 20377, parent pid 20376).
func1: old value: 42
func1: address: 0x7ffffe1964f0
func1: new value: 53
PARENT: message from child: 1
CHILD: child_mem_fd: 4
PARENT: child_path: /proc/20377/mem
CHILD: new value 53
PARENT: child_mem_fd: 7
PARENT: new value 42
ENDING CHILD PROCESS.
There's one silly mistake in this code:
const char * path = "/proc/self/mem";
...
snprintf(child_path, 0x20, "/proc/%d/mem", child_pid);
printf("PARENT: child_path: %s\n", child_path);
child_mem_fd = open(path, O_RDONLY);
So you always end up reading parent's memory here. However after changing this, I get:
CHILD: child_mem_fd: 4
CHILD: new value 53
read (parent): No such process
And I don't know why it could happen - maybe /proc is too slow in refreshing the entries? (it's from perror("read") in the parent - had to add a comment to see which one fails) But that seems weird, since the seek worked - as well as open itself.
That question doesn't seem to be new either: http://lkml.indiana.edu/hypermail/linux/kernel/0007.1/0939.html (ESRCH is "no such process")
Actually a better link is: http://www.webservertalk.com/archive242-2004-7-295131.html - there was an issue with marking processes pthread-attach-safe. You can find there Alan Cox sending someone to Solar Designer... for me that spells "here be dragons" and that it's not solvable if you don't hack kernels in your sleep :(
Maybe it's enough for you to check what is gdb doing in that case and replicating it? (Probably it just goes via ptrace(PTRACE_PEEKDATA,...))
The solution is to use ptrace to synchronize parent with child. Even though I am already communicating between parent and child (and the man page for ptrace says that it causes the two processes to behave as if they were parent and child), and even though the child is blocking on the read call, the child has apparently not "stopped" enough for Linux to allow the parent to read the child's /proc/child_pid/mem file. But if the parent first calls ptrace (after it receives the message over the pipe) with PTRACE_ATTACH, then it can open the file--and get the correct contents! Then the parent calls ptrace again, with PTRACE_DETACH, before sending the message back to the child to terminate.

ptrace'ing of parent process

Can child process use the ptrace system call to trace its parent?
Os is linux 2.6
Thanks.
upd1:
I want to trace process1 from "itself". It is impossible, so I do fork and try to do ptrace(process1_pid, PTRACE_ATTACH) from child process. But I can't, there is a strange error, like kernel prohibits child from tracing their parent processes
UPD2: such tracing can be prohibited by security policies. Which polices do this? Where is the checking code in the kernel?
UPD3: on my embedded linux I have no errors with PEEKDATA, but not with GETREGS:
child: getregs parent: -1
errno is 1, strerror is Operation not permitted
errno = EPERM
This question really interested me. So I wrote some code to try it out.
Firstly keep in mind, that when tracing a process, the tracing process becomes a parent for most purposes, except in name (i.e. getppid()). Firstly, a snippet of the PTRACE_ATTACH section of the manual is helpful:
PTRACE_ATTACH
Attaches to the process specified in pid, making it a traced
"child" of the calling process; the behavior of the child is as
if it had done a PTRACE_TRACEME. The calling process actually
becomes the parent of the child process for most purposes (e.g.,
it will receive notification of child events and appears in
ps(1) output as the child's parent), but a getppid(2) by the
child will still return the PID of the original parent. The
child is sent a SIGSTOP, but will not necessarily have stopped
by the completion of this call; use wait(2) to wait for the
child to stop. (addr and data are ignored.)
Now here is the code I wrote to test and verify that you can in fact ptrace() your parent (you can build this by dumping it in a file named blah.c and running make blah:
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
int main()
{
pid_t pid = fork();
assert(pid != -1);
int status;
long readme = 0;
if (pid)
{
readme = 42;
printf("parent: child pid is %d\n", pid);
assert(pid == wait(&status));
printf("parent: child terminated?\n");
assert(0 == status);
}
else
{
pid_t tracee = getppid();
printf("child: parent pid is %d\n", tracee);
sleep(1); // give parent time to set readme
assert(0 == ptrace(PTRACE_ATTACH, tracee));
assert(tracee == waitpid(tracee, &status, 0));
printf("child: parent should be stopped\n");
printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme));
}
return 0;
}
Note that I'm exploiting the replication of the parent's virtual address space to know where to look. Also note that when the child then terminates, I suspect there's an implicit detach which must allow the parent to continue, I didn't investigate further.
Yes it is possible...
Even GETREGS works.
Checked on x86
(based on Matt Joiner code, thanks him)
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
int main()
{
pid_t pid = fork();
// assert(pid != -1);
int status;
long readme = 0;
struct user_regs_struct regs;
if (pid)
{
readme = 42;
printf("parent: child pid is %d\n", pid);
assert(pid == wait(&status));
printf("parent: child terminated?\n");
assert(0 == status);
}
else
{
pid_t tracee = getppid();
printf("child: parent pid is %d\n", tracee);
sleep(1); // give parent time to set readme
assert(0 == ptrace(PTRACE_ATTACH, tracee));
assert(tracee == waitpid(tracee, &status, 0));
printf("child: parent should be stopped\n");
printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme, NULL));
printf("Regs was %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
printf("child: getregs parent: %ld\n", ptrace(PTRACE_GETREGS, tracee, NULL, &regs));
printf("Regs is %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
}
return 0;
}
result:
child: parent pid is 1188
parent: child pid is 1189
child: parent should be stopped
child: peeking at parent: 42
Regs was (nil), (nil), (nil), (nil); &status is 0xbfffea50
child: getregs parent: 0
Regs is 0xfffffe00, 0xffffffff, 0xbfffea50, (nil); &status is 0xbfffea50
parent: child terminated?

Resources