Saturday, 30 June 2012

sigsuspend vs pause...

For more info visit

sigsuspend and pause, both do the same work, they pause or temporarily stops the process until they receive some signal. These functions return, once the signal handling of the signal is complete.

A small difference between these functions is that, in sigsuspend, we can specify the signal mask to which the function should not listen. Suppose we implement the sigsuspend in the following manner

sigset_t tempmask; sigemptyset(&tempmask); sigaddset(&tempmask,SIGINT); sigsuspend(&tempmask);

Now, in the above code, we have specified the sigsuspend function to listen for every signal except SIGINT.

When sigsuspend receives any other signal than SIGINT, it returns.

This was a small difference between sigsuspend and pause. We get to know the major difference between their ways of working, when we have a scenario, and we try to implement it by both.

Suppose my scenario is, I have a program with two critical regions. By critical regions, I mean to say that I don't want some signal to interrupt in between, while my critical section is executing. But, at the same time I want my second critical section to start, only if I get the confirmation, that some signal has been received.

This is a very natural scenario, and we may encounter this type of condition anytime in our programs. Suppose I have two processes, p1 and p2, p2 has two critical sections, and it wants to go ahead with its second critical section only if it receives, a signal from p1 or has already received a signal from p1, and at the same time it doesn't want the signal to disturb, during the execution of its critical sections.

Let's see, how we can implement this scenario using pause()

#include<stdio.h> #include<signal.h> static void rec(int signo) { printf("\ninterrupt received\n"); } int main() { sigset_t mask1,mask2; signal(SIGINT, rec); sigemptyset(&mask1); sigaddset(&mask1,SIGINT); sigprocmask(SIG_BLOCK,&mask1,&mask2); printf("\ncritical region 1\n"); sleep(5); printf("\ncritical region 1 ends\n"); sigprocmask(SIG_SETMASK,&mask2,NULL); pause(); sigprocmask(SIG_BLOCK,&mask1,&mask2); printf("\ncritical region 2\n"); sleep(5); printf("\ncritical region 2 ends\n"); sigprocmask(SIG_SETMASK,&mask2,NULL); exit(0); }

We are using only one process, and let's assume that SIGINT is the signal which should not be allowed to interrupt the process during execution of critical section. In the above program, we block SIGINT before starting of any critical section and unblock it when the criticel section is over.

The program also pauses for confirmation that SIGINT is received before proceeding towards second critical section.

We unblock the signal SIGINT once the critical section ends, in order to receive the SIGINT signal. The main problem with this program is that, there is a time window, between unblocking of signal and pause, in which the signal can be received. In this case, the process will go to an infinite pause.

To test this problem, send the SIGINT from the terminal before the critical section 1 ends, i.e. when the process is in sleep inside first critical section

sigprocmask(SIG_SETMASK,&mask2,NULL);

//window in which the signal could be received pause();

To solve this problem, we make use of sigsuspend. We will write another program implementing the same logic, but using sigsuspend.

#include<stdio.h> #include<signal.h> static void rec(int signo) { printf("\ninterrupt received\n"); } int main() { sigset_t mask1,mask2; signal(SIGINT, rec); sigemptyset(&mask1); sigaddset(&mask1,SIGINT); sigprocmask(SIG_BLOCK,&mask1,&mask2); printf("\ncritical region 1\n"); sleep(5); printf("\ncritical region 1 ends\n"); sigsuspend(&mask2); printf("\ncritical region 2\n"); sleep(5); printf("\ncritical region 2 ends\n"); sigprocmask(SIG_SETMASK,&mask2,NULL); exit(0); }

The above program is not unblocking the SIGINT to receive it. Infact, it is using sigsuspend in place of it.

We are passing original process mask, which doesn't mask SIGINT,  in sigsuspend function. sigsuspend pauses the process and can only return if any of the signal, which is not in mask2, is received and its signal handler is executed. So, sigsuspend will return upon receival of SIGINT . When sigsuspend returns it resets the sigmask for the process to the mask just before when sigsuspend executed. In this case the SIGINT will be blocked again before execution of second critical section starts.

Monday, 18 June 2012

Session, Foreground processes, Background processes, and their interaction with Controlling Terminal.

For more info visit

Session: A session is a collection of process groups. In a session there can be only one foreground process group and more than one background process groups. The process which starts the session is known as session leader. A session leader can either be in a foreground process group or in a background process group.

Run the following command in your terminal to get the idea

ps -o pid,ppid,pgid,sid,tpgid,comm

The output will be similar as following

  PID     PPID   PGID      SID     TPGID  COMMAND 17335  17334  17335  17335  17495    bash 17495  17335  17495  17335  17495    ps

The column SID gives us the information about the session leader for the session. The SID will always be the process group id of the session leader, or we can also say that it will be same as id of session leader. Why?

Because whenever a new session is started, there is only a single process in the session, which is also known as session leader. This session leader is the process which starts the session.

In the above case, the session leader process is shell. We can also start our own sessions. Sessions are not started from some new process, but they are started from the currently existing process. The existing process is in some session before starting a new session. So, whenever a new session is started, the process which starts the new session is transferred to a new process group with group id same as its process id, means that the session starter process becomes the group leader of the new group. This new session contains only a single process, which is the starter process, and a single group in it.

As I said, a session leader can either be in foreground process group or background process group. In the above case, the shell, which is the session leader, is in background process group

Now, run the same command in background.

ps -o pid,ppid,pgid,sid,tpgid,comm &

The output will be

PID       PPID      PGID    SID     TPGID  COMMAND

17601  17600  17601   17601  17601     bash 17610  17601  17610   17601  17601      ps

Now, in this case, the shell is in foreground process group. How do we get to know, which is foreground process group and which is background process group?

Here comes the concept of Controlling terminal

A controlling terminal is the terminal device which is connected to a session. A session can have only one  terminal controller. The session leader, which makes the connection with the controlling process, is called Controlling Process. The Controlling terminal can only interact with the foreground process group.

The TPGID visible in the above example is Terminal process Group id, which is nothing, but the process group id of the foreground group process leader, which in second case is the shell.

The interrupts from the terminal such as ^C, ^D, etc are only going to effect the processes in the foreground process group.

Any Background process group can always be brought Foreground, provided the Background process group is in the same session as Foreground process group.

Now, let's see a simple example of toggling between Foreground process group and Background process group

#include<stdio.h> #include<stdlib.h> int main() { int pid; pid=fork(); if(pid==0) { setpgid(getpid(),getpid()); sleep(2); printf("\nin child process"); printf("\nchildpid %d",getpid()); printf("\nchildgrpid %d\n",getpgrp()); printf("\nchild done"); printf("\nchanged fpgid to child process%d\n",tcgetpgrp(1)); } else { printf("\ninitial fpgid %d\n",tcgetpgrp(1)); printf("\nin parent process"); printf("\nparentpid %d",getpid()); printf("\nparentgrpid %d\n",getpgrp()); tcsetpgrp(1,pid); wait(); printf("\nparent done"); printf("\nchanged fpgid to parent process%d\n",tcgetpgrp(1)); } exit(0);

Compile and run the above program The output will be -

initial fpgid 17737

in parent process parentpid 17737 parentgrpid 17737

in child process childpid 17738 childgrpid 17738

child done changed fpgid to child process17738

[1]+  Stopped                 ./a.out

Now, let's analyse the program from beginning.

We fork() a child process and change its group id to its pid. Why? This is just to transfer the child process in some other group, as, after forking it would have inherited the group of its parent. We make it sleep for 2 secs, in order to run the parent process first.

In parent process, the parent's pid, pgid, and Foreground process group id is printed. Initially, the fpgid is same as parentgrpid. After printing all this, we change the fpgid to childgrpid or childpid. Parent process waits for child process to terminate.

Child process starts after 2 secs. It prints childpid, childgrpid and changed fpgid which now is same as childgrpid. This means, now child process group is the foreground process group. Child process prints "child done" and terminates.

Now what is this "[1]+  Stopped                 ./a.out".

Looks like some process has been stopped in the background. After seeing, we get to know that parent process has been stopped.

Why was it stopped?

It was stopped because it received signal SIGTTOU while trying to print the last two statements on the terminal. This terminal sends this signal to any background process group which tries to print something on terminal.

Since the parent process is not allowed to continue, the child process has also become ZOMBIE. Though the parent process has received the exit status of child process, it couldn't delete its details from process structure table.

Now we will start this stopped parent process by bringing it in foreground.

fg %1

The output will be

parent done changed fpgid to parent process17737

One more thing, just now we changed the fpgid to child process's group id. How did it revert back to parent process's group id.

It's simple, because when we brought the job with job id 1 to Foreground, all the processes of the group came to foreground.

Note: Make sure you run the following command, before executing above program.

stty tostop

This command stop the background jobs that try to write to the terminal.

Sunday, 10 June 2012

Session, Foreground processes, Background processes, and their interaction with Controlling Terminal.

For more info visit

Session: A session is a collection of process groups. In a session there can be only one foreground process group and more than one background process groups. The process which starts the session is known as session leader. A session leader can either be in a foreground process group or in a background process group.

Run the following command in your terminal to get the idea

ps -o pid,ppid,pgid,sid,tpgid,comm

The output will be similar as following

  PID     PPID   PGID      SID     TPGID  COMMAND 17335  17334  17335  17335  17495    bash 17495  17335  17495  17335  17495    ps

The column SID gives us the information about the session leader for the session. The SID will always be the process group id of the session leader, or we can also say that it will be same as id of session leader. Why?

Because whenever a new session is started, there is only a single process in the session, which is also known as session leader. This session leader is the process which starts the session.

In the above case, the session leader process is shell. We can also start our own sessions. Sessions are not started from some new process, but they are started from the currently existing process. The existing process is in some session before starting a new session. So, whenever a new session is started, the process which starts the new session is transferred to a new process group with group id same as its process id, means that the session starter process becomes the group leader of the new group. This new session contains only a single process, which is the starter process, and a single group in it.

As I said, a session leader can either be in foreground process group or background process group. In the above case, the shell, which is the session leader, is in background process group

Now, run the same command in background.

ps -o pid,ppid,pgid,sid,tpgid,comm &

The output will be

PID       PPID      PGID    SID     TPGID  COMMAND

17601  17600  17601   17601  17601     bash 17610  17601  17610   17601  17601      ps

Now, in this case, the shell is in foreground process group. How do we get to know, which is foreground process group and which is background process group?

Here comes the concept of Controlling terminal

A controlling terminal is the terminal device which is connected to a session. A session can have only one  terminal controller. The session leader, which makes the connection with the controlling process, is called Controlling Process. The Controlling terminal can only interact with the foreground process group.

The TPGID visible in the above example is Terminal process Group id, which is nothing, but the process group id of the foreground group process leader, which in second case is the shell.

The interrupts from the terminal such as ^C, ^D, etc are only going to effect the processes in the foreground process group.

Any Background process group can always be brought Foreground, provided the Background process group is in the same session as Foreground process group.

Now, let's see a simple example of toggling between Foreground process group and Background process group

#include<stdio.h> #include<stdlib.h> int main() { int pid; pid=fork(); if(pid==0) { setpgid(getpid(),getpid()); sleep(2); printf("\nin child process"); printf("\nchildpid %d",getpid()); printf("\nchildgrpid %d\n",getpgrp()); printf("\nchild done"); printf("\nchanged fpgid to child process%d\n",tcgetpgrp(1)); } else { printf("\ninitial fpgid %d\n",tcgetpgrp(1)); printf("\nin parent process"); printf("\nparentpid %d",getpid()); printf("\nparentgrpid %d\n",getpgrp()); tcsetpgrp(1,pid); wait(); printf("\nparent done"); printf("\nchanged fpgid to parent process%d\n",tcgetpgrp(1)); } exit(0);

Compile and run the above program The output will be -

initial fpgid 17737

in parent process parentpid 17737 parentgrpid 17737

in child process childpid 17738 childgrpid 17738

child done changed fpgid to child process17738

[1]+  Stopped                 ./a.out

Now, let's analyse the program from beginning.

We fork() a child process and change its group id to its pid. Why? This is just to transfer the child process in some other group, as, after forking it would have inherited the group of its parent. We make it sleep for 2 secs, in order to run the parent process first.

In parent process, the parent's pid, pgid, and Foreground process group id is printed. Initially, the fpgid is same as parentgrpid. After printing all this, we change the fpgid to childgrpid or childpid. Parent process waits for child process to terminate.

Child process starts after 2 secs. It prints childpid, childgrpid and changed fpgid which now is same as childgrpid. This means, now child process group is the foreground process group. Child process prints "child done" and terminates.

Now what is this "[1]+  Stopped                 ./a.out".

Looks like some process has been stopped in the background. After seeing, we get to know that parent process has been stopped.

Why was it stopped?

It was stopped because it received signal SIGTOUT while trying to print the last two statements on the terminal. This terminal sends this signal to any background process group which tries to print something on terminal.

Since the parent process is not allowed to continue, the child process has also become ZOMBIE. Though the parent process has received the exit status of child process, it couldn't delete its details from process structure table.

Now we will start this stopped parent process by bringing it in foreground.

fg %1

The output will be

parent done changed fpgid to parent process17737

One more thing, just now we changed the fpgid to child process's group id. How did it revert back to parent process's group id.

It's simple, because when we brought the job with job id 1 to Foreground, all the processes of the group came to foreground.

Wednesday, 6 June 2012

What happens if we call System from a Set-User-Id Program?

For more info visitWhat is System function and why do we use it? System is a function provided by C library STDLIB, it is used to execute a command string from within a C program. We can understand it to be the substitute for fork() and exec(). Instead of forking a new child process and calling exec function to execute a new command, we can directly use System function to execute a new command. Also, System function has a lot of advantages other than just fork() and exec(). Features: i) It forks(), exec() and waits for the child process. ii) Performs error handling if fork() or exec() or waitpid() fails. iii) Doesn't handle signals. We can use system in our C program as follows system("ls -lrt"); Just a simple statement and we can execute all the commands, scripts and binary executables from our program, without using fork() and execute(). But, what happens when we try to use system function with Set-User-Id programs. Let's say there is a user, user1, who is the owner of two programs, prog1 and prog2. Now, suppose that user1 has set SUID bit for prog1, but no SUID bit has been set for prog2, i.e user1 wants that, whenever prog1 runs, it should run with the owner's permission, but prog2 should always run with the user's permission. Let's  write prog1.c #include<stdio.h> #include<stdlib.h> int main() { printf("\nreal user id %d\n",getuid()); printf("\neffective user id %d\n",geteuid()); system("prog2"); exit(0); } Now write prog2.c #include<stdio.h> #include<stdlib.h> int main() { printf("\nin prog2\n"); printf("real user id %d\n",getuid()); printf("effective user id %d\n",geteuid()); printf("exit prog2\n"); exit(0); } Compile prog2.c and prog1.c. Suppose we get two binary executables, prog1 and prog2. Set SUID bit for prog1. Now, log in as different user, let's say user2, set the directory of prog2 in PATH environment variable. Run prog1 as user2. The output shall be real user id 1197 effective user id 1196 in prog2 real user id 1197 effective user id 1196 exit prog2 Did you notice the hole in security. Even though prog2 was not SUID bit set, it was run with the file owner's permission. Always be careful while using System function. The above problem can be solved by adding an extra line of code in prog1. Modified prog1 which is secure, #include<stdio.h> #include<stdlib.h> int main() { printf("real user id %d\n",getuid()); printf("effective user id %d\n",geteuid()); setuid(getuid()); system("prog2"); exit(0); } Now compile and run the prog1 as user2. Don't forget to set the SUID bit for prog1. The output shall be real user id 1197 effective user id 1196 in prog2 real user id 1197 effective user id 1197 exit prog2 getuid() gives the real user id  and setuid(getuid()) sets the effective useri id, before calling the system function, as real user id. So, when system() is called, real user id is passed to the exec() function used in the system function, and is set as the effective user id. Whenever a new child process is executed, the exec() copies the effective user id from the parent process. Infact, setuid() doesn't only set the effective user id of the process. It performs different actions in different situations. However, in this scenario, it only sets the effective user id of the process.