How do I get the root directory of a process programmatically? - linux

On Linux, every process has its own root directory. For most processes, this is /. However, chroot can change that. This information is exposed via /proc. However, how do I find out the root directory of a process programmatically? Is there a syscall, or, libc function for it?

I don't know whether there is another way, but lots of programs rely on the machine readable files in /proc to get additional information about processes and there's nothing inherently wrong with that.
Here's an example of a process finding its own root dir programmatically via /proc:
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
int main() {
char foo[PATH_MAX+1];
int count = readlink("/proc/self/root", foo, PATH_MAX);
if(count < 0) {
perror("Can't find root dir (is /proc mounted here?)");
} else {
foo[count]=0;
printf("My root dir is %s\n", foo);
}
}

Well there isn't. There exists a command to do this which is pwdx, here is its code https://elixir.bootlin.com/busybox/latest/source/procps/pwdx.c. It also reads root dir from /proc. You can get the pid of your process using getpid function.

One simple way is to just use a for loop. This is a one-liner that will print out the root directory of each of the processes you wish (proc1, proc2, proc3):
for i in $(ps -ef | grep -E 'proc1|proc2|proc3' | awk '{ print $2 }'); do ls -ld /proc/$i/root; done

Related

Umount("/proc") syscall for mount namespaces "Invalid Argument" error

i'm currently trying to use different namespaces for test purposes. For this i tried to implement a MNT namespace (combined with a PID namespace) so that a program within this namespace cannot see other processes on the system.
When trying to use the umount system call like this (same goes with umount("/proc"), or with umount2 and the Force-option ):
if (umount2("/proc", 0)!= 0)
{
fprintf(stderr, "Error when unmounting /proc: %s\n",strerror(errno));
printf("\tKernel version might be incorrect\n");
exit(-1);
}
the system call execution ends with error number 22 "Invalid Argument".
This code snipped is called within a function that gets called when a child process with the namespaces is created:
pid_t child_pid = clone(child_exec, child_stack+1024*1024, Child_Flags,&args);
(the child_exec function). Flags are set as following:
int Child_Flags = CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWUTS | CLONE_NEWNET |CLONE_NEWPID | CLONE_NEWNS |SIGCHLD ;
With the CLONE_NEWNS for a new mount namespace (http://man7.org/linux/man-pages/man7/namespaces.7.html)
Output of the program is as follows:
Testing with Isolation
Starting Container engine
In-Child-PID: 1
Error number 22
Error when unmounting /proc: Invalid argument
Can somebody point me to my error, so i can unmount the folder? Thank you in advance
You can't unmount things that were mounted in a different user namespace except by using pivot_root followed by umount to unmount /. You can overmount /proc without unmounting the old /proc.

How to make a fifo in C?

I have to use mkfifo in my C program in Ubuntu. But I have an error when I compile: no such file or directory .
I think the problem because I have not set the panel_fifo environment variables. But I don't khow how could I do this.
Here is my code I use to test this method:
char *myfifo="./sock/myfifo";
if (mkfifo(myfifo,0777)<0)
perror("can't make it");
if (fd=open(myfifo,O_WRONLY)<0)
perror("can't open it");
I compile this with:
gcc gh.c -o gh
When I run, I get this error message:
can't make it:no such file or directory
can't open it:no such file or directory
It's because the directory sock doesn't exist.
In a terminal:
christian#fujiu1404:~/tmp/t2$ ls
t2.c
christian#fujiu1404:~/tmp/t2$ cat t2.c
#include <fcntl.h>
main() {
int fd;
char *myfifo="./sock/myfifo";
if (mkfifo(myfifo,0777)<0)
perror("can't make it");
if (fd=open(myfifo,O_WRONLY)<0)
perror("can't open it");
}
christian#fujiu1404:~/tmp/t2$ cc t2.c
christian#fujiu1404:~/tmp/t2$ ./a.out
can't make it: No such file or directory
can't open it: No such file or directory
christian#fujiu1404:~/tmp/t2$ mkdir sock
christian#fujiu1404:~/tmp/t2$ ./a.out
Note the program hasn't completed, but your fifo does exist.
Now in a second terminal, put a string into the fifo
christian#fujiu1404:~/tmp/t2$ ls -l sock/
total 0
prwxrwxr-x 1 christian christian 0 May 27 06:45 myfifo
christian#fujiu1404:~/tmp/t2$ echo abc >sock/myfifo
Note echo also is suspended
Now in a third terminal, read from the fifo
christian#fujiu1404:~/tmp/t2$ cat sock/myfifo
abc
christian#fujiu1404:~/tmp/t2$
Note now all programs complete and exit (in all terminals)
You try
myfifo("./sock/myfifo", ...)
You get
no such file or directory
which is ENOENT.
You then want to look up the relevant documentation and find the following in man 3 mkfifo:
ERRORS
[...]
ENOENT A directory component in pathname does not exist or is a dangling symbolic link.
From all this one could conculde ./sock does not exist.

How to get child process from parent process

Is it possible to get the child process id from parent process id in shell script?
I have a file to execute using shell script, which leads to a new process process1 (parent process). This process1 has forked another process process2(child process). Using script, I'm able to get the pid of process1 using the command:
cat /path/of/file/to/be/executed
but i'm unable to fetch the pid of the child process.
Just use :
pgrep -P $your_process1_pid
I am not sure if I understand you correctly, does this help?
ps --ppid <pid of the parent>
I've written a script to get all child process pids of a parent process.
Here is the code. Hope it will help.
function getcpid() {
cpids=`pgrep -P $1|xargs`
# echo "cpids=$cpids"
for cpid in $cpids;
do
echo "$cpid"
getcpid $cpid
done
}
getcpid $1
To get the child process and thread,
pstree -p PID.
It also show the hierarchical tree
The shell process is $$ since it is a special parameter
On Linux, the proc(5) filesystem gives a lot of information about processes. Perhaps
pgrep(1) (which accesses /proc) might help too.
So try cat /proc/$$/status to get the status of the shell process.
Hence, its parent process id could be retrieved with e.g.
parpid=$(awk '/PPid:/{print $2}' /proc/$$/status)
Then use $parpid in your script to refer to the parent process pid (the parent of the shell).
But I don't think you need it!
Read some Bash Guide (or with caution advanced bash scripting guide, which has mistakes) and advanced linux programming.
Notice that some server daemon processes (wich usually need to be unique) are explicitly writing their pid into /var/run, e.g. the  sshd server daemon is writing its pid into the textual file /var/run/sshd.pid). You may want to add such a feature into your own server-like programs (coded in C, C++, Ocaml, Go, Rust or some other compiled language).
You can get the pids of all child processes of a given parent process <pid> by reading the /proc/<pid>/task/<tid>/children entry.
This file contain the pids of first level child processes.
Recursively do this for all children pids.
For more information head over to https://lwn.net/Articles/475688/
ps -axf | grep parent_pid
Above command prints respective processes generated from parent_pid, hope it helps.
+++++++++++++++++++++++++++++++++++++++++++
root#root:~/chk_prgrm/lp#
parent...18685
child... 18686
root#root:~/chk_prgrm/lp# ps axf | grep frk
18685 pts/45 R 0:11 | \_ ./frk
18686 pts/45 R 0:11 | | \_ ./frk
18688 pts/45 S+ 0:00 | \_ grep frk
You can print the PID of all child processes invoked by a parent process:
pstree -p <PARENT_PID> | grep -oP '\(\K[^\)]+'
This prints a list of pids for the main process and its children recursively
I used the following to gather the parent process and child processes of a specific process PID:
ps -p $PID --ppid $PID --forest | tail -n +2 | awk '{print$1}'
Note, this will not work to find child processes of child processes.
For the case when the process tree of interest has more than 2 levels (e.g. Chromium spawns 4-level deep process tree), pgrep isn't of much use. As others have mentioned above, procfs files contain all the information about processes and one just needs to read them. I built a CLI tool called Procpath which does exactly this. It reads all /proc/N/stat files, represents the contents as a JSON tree and expose it to JSONPath queries.
To get all descendant process' comma-separated PIDs of a non-root process (for the root it's ..stat.pid) it's:
$ procpath query -d, "..children[?(#.stat.pid == 24243)]..pid"
24243,24259,24284,24289,24260,24262,24333,24337,24439,24570,24592,24606,...
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
// Create a child process
int pid = fork();
if (pid > 0)
{
int j=getpid();
printf("in parent process %d\n",j);
}
// Note that pid is 0 in child process
// and negative if fork() fails
else if (pid == 0)
{
int i=getppid();
printf("Before sleep %d\n",i);
sleep(5);
int k=getppid();
printf("in child process %d\n",k);
}
return 0;
}

In Linux, does the location of an executable affect how the setuid bit is interpreted?

In a Linux system, does the permissions of the directory in which a setuid program resides affect how the kernel launches the process? The reason I ask is that when I compiled an identical setuid program in two different directories, it only actually assumed the user permissions in one directory. I compiled it in /tmp and /home/flag03 where flag03 is the user account that I am attempting to gain access to. When executed from /tmp it did not escalate privileges as expected, but it worked under /home.
Some background on the problem:
I'm working on level 03 of exploit-exercises.com/nebula. The exercise requires that you gain access to a flag03 user account. The exercise is setup so that the flag03 user is periodically running a cronjob which will allow you to execute a script in a specific directory. My plan was to write a simple bash script which will compile a setuid program that itself launches a bash shell, and then set the setuid bit with chmod +s. The idea is that when the setuid program is compiled, it is compiled by user flag03 via the cronjob. Once this newly compiled program is executed, it will launch a shell as user flag03, and that is the goal.
Here is the simple setuid program (l3.c, based on levels 1 + 2):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv, char **envp)
{
uid_t uid;
gid_t gid;
uid = geteuid();
gid = getegid();
setresuid(uid,uid,uid);
setresgid(gid,gid,gid);
printf("uid: %d\n", getuid());
printf("gid: %d\n", getgid());
system("/bin/bash");
return 0;
}
In order for this to work, a bash script compiles the program as user flag03 and then chmods the setuid bit.
#!/bin/bash
#gcc -o /tmp/l3 /tmp/l3.c
#chmod +s,a+rwx /tmp/l3
gcc -o /home/flag03/l3 /tmp/l3.c
chmod +s,a+rwx /home/flag03/l3
The executable generated in /tmp does not escalate privileges as expected, but the one generated in /home/flag03 works as expected.
NOTE I just created a new bash script to move the version of the setuid program that was compiled in /tmp to /home/flag03, and then reset the setuid bit. When executed from there, that version worked as well. So it appears to me that the permissions of the directory in which the setuid program resides has some kind of impact with how the process is launch. Maybe this is related to /tmp being a somewhat "special" directory?
Thanks for any interest in this long-winded question!
If the filesystem is mounted with the nosuid option, the suid bit will be ignored when executing files located there. As I understand it, /tmp is usually a separate filesystem (often tmpfs) mounted with the nosuid option. The motivation for this configuration is preventing a compromised account that has no writable storage except /tmp (e.g. nobody) from being able to produce suid binaries, which may be used in certain elaborate multi-step attacks to elevate privilege.

How to see the daemon process's output in Linux?

I wrote a test.c:
#include <unistd.h>
#include <stdio.h>
int main()
{
while(1)
{
sleep(1);
printf("====test====\r\n");
}
return 0;
}
then i compile it : gcc ./test.c -o ./test
and the i wrote a shell script:
#!/bin/sh
./test &
and then i made this script to be executed automatically on system boot.
then I login to the Linux system using secureCRT in SSH protocol.
using "ps aux | grep test" i can see the test process running,
but i just cannot see the test's output, some people told me because the test
output to tty, and i am using pts.
could anybody tell me the specific reason and how can i get the output?
thanks in advance!
It doesn't output anything because it got no terminal attached.
If you want your output to be visible to every terminal connected to the system, use wall
./test | wall
(it will be very annoying)
I suggest you to redirect the output to a log file.

Resources