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 "test.h"
     36 #include "safe_macros.h"
     37 #include "libclone.h"
     38 #include "ipcns_helper.h"
     39 #include "lapi/semun.h"
     40 
     41 #define TESTKEY 124426L
     42 char *TCID	= "sem_comm";
     43 int TST_TOTAL	= 1;
     44 
     45 static void cleanup(void)
     46 {
     47 	tst_rmdir();
     48 }
     49 
     50 static void setup(void)
     51 {
     52 	tst_require_root();
     53 	check_newipc();
     54 	tst_tmpdir();
     55 	TST_CHECKPOINT_INIT(tst_rmdir);
     56 }
     57 
     58 int chld1_sem(void *arg)
     59 {
     60 	int id;
     61 	union semun su;
     62 	struct sembuf sm;
     63 
     64 	id = semget(TESTKEY, 1, IPC_CREAT);
     65 	if (id == -1) {
     66 		perror("semget");
     67 		return 2;
     68 	}
     69 
     70 	su.val = 1;
     71 	if (semctl(id, 0, SETVAL, su) == -1) {
     72 		perror("semctl");
     73 		semctl(id, 0, IPC_RMID);
     74 		return 2;
     75 	}
     76 
     77 	/* tell child2 to continue and wait for it to create the semaphore */
     78 	TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0);
     79 
     80 	sm.sem_num = 0;
     81 	sm.sem_op = -1;
     82 	sm.sem_flg = IPC_NOWAIT;
     83 	if (semop(id, &sm, 1) == -1) {
     84 		perror("semop");
     85 		semctl(id, 0, IPC_RMID);
     86 		return 2;
     87 	}
     88 
     89 	/* tell child2 to continue and wait for it to lock the semaphore */
     90 	TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0);
     91 
     92 	sm.sem_op = 1;
     93 	semop(id, &sm, 1);
     94 
     95 	semctl(id, 0, IPC_RMID);
     96 	return 0;
     97 }
     98 
     99 int chld2_sem(void *arg)
    100 {
    101 	int id, rval = 0;
    102 	struct sembuf sm;
    103 	union semun su;
    104 
    105 	/* wait for child1 to create the semaphore */
    106 	TST_SAFE_CHECKPOINT_WAIT(NULL, 0);
    107 
    108 	id = semget(TESTKEY, 1, IPC_CREAT);
    109 	if (id == -1) {
    110 		perror("semget");
    111 		return 2;
    112 	}
    113 
    114 	su.val = 1;
    115 	if (semctl(id, 0, SETVAL, su) == -1) {
    116 		perror("semctl");
    117 		semctl(id, 0, IPC_RMID);
    118 		return 2;
    119 	}
    120 
    121 	/* tell child1 to continue and wait for it to lock the semaphore */
    122 	TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0);
    123 
    124 	sm.sem_num = 0;
    125 	sm.sem_op = -1;
    126 	sm.sem_flg = IPC_NOWAIT;
    127 	if (semop(id, &sm, 1) == -1) {
    128 		if (errno == EAGAIN) {
    129 			rval = 1;
    130 		} else {
    131 			perror("semop");
    132 			semctl(id, 0, IPC_RMID);
    133 			return 2;
    134 		}
    135 	}
    136 
    137 	/* tell child1 to continue */
    138 	TST_SAFE_CHECKPOINT_WAKE(NULL, 0);
    139 
    140 	sm.sem_op = 1;
    141 	semop(id, &sm, 1);
    142 
    143 	semctl(id, 0, IPC_RMID);
    144 	return rval;
    145 }
    146 
    147 static void test(void)
    148 {
    149 	int status, ret = 0;
    150 
    151 	ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem, NULL);
    152 	if (ret == -1)
    153 		tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
    154 
    155 	ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem, NULL);
    156 	if (ret == -1)
    157 		tst_brkm(TBROK | TERRNO, cleanup, "clone failed");
    158 
    159 
    160 	while (wait(&status) > 0) {
    161 		if (WIFEXITED(status) && WEXITSTATUS(status) == 1)
    162 			ret = 1;
    163 		if (WIFEXITED(status) && WEXITSTATUS(status) == 2)
    164 			tst_brkm(TBROK | TERRNO, cleanup, "error in child");
    165 		if (WIFSIGNALED(status)) {
    166 			tst_resm(TFAIL, "child was killed with signal %s",
    167 					tst_strsig(WTERMSIG(status)));
    168 			return;
    169 		}
    170 	}
    171 
    172 	if (ret)
    173 		tst_resm(TFAIL, "SysV sem: communication with identical keys"
    174 				" between namespaces");
    175 	else
    176 		tst_resm(TPASS, "SysV sem: communication with identical keys"
    177 				" between namespaces");
    178 }
    179 
    180 int main(int argc, char *argv[])
    181 {
    182 	int lc;
    183 
    184 	tst_parse_opts(argc, argv, NULL, NULL);
    185 
    186 	setup();
    187 
    188 	for (lc = 0; TEST_LOOPING(lc); lc++)
    189 		test();
    190 
    191 	cleanup();
    192 	tst_exit();
    193 }
    194