Home | History | Annotate | Download | only in sysvipc
      1 /* Copyright (c) 2014 Red Hat, Inc.
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of version 2 the GNU General Public License as
      5  * published by the Free Software Foundation.
      6  *
      7  * This program is distributed in the hope that it will be useful,
      8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10  * GNU General Public License for more details.
     11  *
     12  * You should have received a copy of the GNU General Public License
     13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     14  ***********************************************************************
     15  * File: sem_comm.c
     16  *
     17  * Description:
     18  * 1. Clones two child processes with CLONE_NEWIPC flag, each child
     19  *    creates System V semaphore (sem) with the _identical_ key.
     20  * 2. Child1 locks the semaphore.
     21  * 3. Child2 locks the semaphore.
     22  * 4. Locking the semaphore with the identical key but from two different
     23  *    IPC namespaces should not interfere with each other, so if child2
     24  *    is able to lock the semaphore (after child1 locked it), test passes,
     25  *    otherwise test fails.
     26  */
     27 
     28 #define _GNU_SOURCE
     29 #include <sys/ipc.h>
     30 #include <sys/sem.h>
     31 #include <sys/types.h>
     32 #include <sys/wait.h>
     33 #include <stdio.h>
     34 #include <errno.h>
     35 #include "ipcns_helper.h"
     36 #include "test.h"
     37 #include "safe_macros.h"
     38 #include "lapi/semun.h"
     39 
     40 #define TESTKEY 124426L
     41 char *TCID	= "sem_comm";
     42 int TST_TOTAL	= 1;
     43 
     44 static void cleanup(void)
     45 {
     46 	tst_rmdir();
     47 }
     48 
     49 static void setup(void)
     50 {
     51 	tst_require_root();
     52 	check_newipc();
     53 	tst_tmpdir();
     54 	TST_CHECKPOINT_INIT(tst_rmdir);
     55 }
     56 
     57 int chld1_sem(void *arg)
     58 {
     59 	int id;
     60 	union semun su;
     61 	struct sembuf sm;
     62 
     63 	id = semget(TESTKEY, 1, IPC_CREAT);
     64 	if (id == -1) {
     65 		perror("semget");
     66 		return 2;
     67 	}
     68 
     69 	su.val = 1;
     70 	if (semctl(id, 0, SETVAL, su) == -1) {
     71 		perror("semctl");
     72 		semctl(id, 0, IPC_RMID);
     73 		return 2;
     74 	}
     75 
     76 	/* tell child2 to continue and wait for it to create the semaphore */
     77 	TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0);
     78 
     79 	sm.sem_num = 0;
     80 	sm.sem_op = -1;
     81 	sm.sem_flg = IPC_NOWAIT;
     82 	if (semop(id, &sm, 1) == -1) {
     83 		perror("semop");
     84 		semctl(id, 0, IPC_RMID);
     85 		return 2;
     86 	}
     87 
     88 	/* tell child2 to continue and wait for it to lock the semaphore */
     89 	TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0);
     90 
     91 	sm.sem_op = 1;
     92 	semop(id, &sm, 1);
     93 
     94 	semctl(id, 0, IPC_RMID);
     95 	return 0;
     96 }
     97 
     98 int chld2_sem(void *arg)
     99 {
    100 	int id, rval = 0;
    101 	struct sembuf sm;
    102 	union semun su;
    103 
    104 	/* wait for child1 to create the semaphore */
    105 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
    106 
    107 	id = semget(TESTKEY, 1, IPC_CREAT);
    108 	if (id == -1) {
    109 		perror("semget");
    110 		return 2;
    111 	}
    112 
    113 	su.val = 1;
    114 	if (semctl(id, 0, SETVAL, su) == -1) {
    115 		perror("semctl");
    116 		semctl(id, 0, IPC_RMID);
    117 		return 2;
    118 	}
    119 
    120 	/* tell child1 to continue and wait for it to lock the semaphore */
    121 	TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0);
    122 
    123 	sm.sem_num = 0;
    124 	sm.sem_op = -1;
    125 	sm.sem_flg = IPC_NOWAIT;
    126 	if (semop(id, &sm, 1) == -1) {
    127 		if (errno == EAGAIN) {
    128 			rval = 1;
    129 		} else {
    130 			perror("semop");
    131 			semctl(id, 0, IPC_RMID);
    132 			return 2;
    133 		}
    134 	}
    135 
    136 	/* tell child1 to continue */
    137 	TST_SAFE_CHECKPOINT_WAKE(NULL, 0);
    138 
    139 	sm.sem_op = 1;
    140 	semop(id, &sm, 1);
    141 
    142 	semctl(id, 0, IPC_RMID);
    143 	return rval;
    144 }
    145 
    146 static void test(void)
    147 {
    148 	int status, ret = 0;
    149 
    150 	ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem, NULL);
    151 	if (ret == -1)
    152 		tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
    153 
    154 	ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem, NULL);
    155 	if (ret == -1)
    156 		tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
    157 
    158 
    159 	while (wait(&status) > 0) {
    160 		if (WIFEXITED(status) && WEXITSTATUS(status) == 1)
    161 			ret = 1;
    162 		if (WIFEXITED(status) && WEXITSTATUS(status) == 2)
    163 			tst_brkm(TBROK | TERRNO, cleanup, "error in child");
    164 		if (WIFSIGNALED(status)) {
    165 			tst_resm(TFAIL, "child was killed with signal %s",
    166 					tst_strsig(WTERMSIG(status)));
    167 			return;
    168 		}
    169 	}
    170 
    171 	if (ret)
    172 		tst_resm(TFAIL, "SysV sem: communication with identical keys"
    173 				" between namespaces");
    174 	else
    175 		tst_resm(TPASS, "SysV sem: communication with identical keys"
    176 				" between namespaces");
    177 }
    178 
    179 int main(int argc, char *argv[])
    180 {
    181 	int lc;
    182 
    183 	tst_parse_opts(argc, argv, NULL, NULL);
    184 
    185 	setup();
    186 
    187 	for (lc = 0; TEST_LOOPING(lc); lc++)
    188 		test();
    189 
    190 	cleanup();
    191 	tst_exit();
    192 }
    193