1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. 16 */ 17 18 /* 19 * DESCRIPTION 20 * 21 * 1) shmat() fails and set errno to EINVAL when shmid is invalid. 22 * 2) shmat() fails and set errno to EINVAL when shmaddr is not page 23 * aligned and SHM_RND is not given 24 * 3) shmat() fails and set errno to EACCES when the shm resource has 25 * no read/write permission. 26 */ 27 28 #include <errno.h> 29 #include <stdlib.h> 30 #include <sys/types.h> 31 #include <sys/ipc.h> 32 #include <sys/shm.h> 33 #include <pwd.h> 34 35 #include "tst_test.h" 36 #include "tst_safe_sysv_ipc.h" 37 #include "libnewipc.h" 38 39 static int shm_id1 = -1; 40 static int shm_id2 = -1; 41 static void *aligned_addr; 42 static void *unaligned_addr; 43 static key_t shm_key1; 44 static struct passwd *pw; 45 46 static struct test_case_t { 47 int *shmid; 48 void **shmaddr; 49 int exp_err; 50 int exp_user; 51 } tcases[] = { 52 {&shm_id1, &aligned_addr, EINVAL, 0}, 53 {&shm_id2, &unaligned_addr, EINVAL, 0}, 54 {&shm_id2, &aligned_addr, EACCES, 1}, 55 }; 56 57 static void verify_shmat(struct test_case_t *tc) 58 { 59 void *addr; 60 61 addr = shmat(*tc->shmid, *tc->shmaddr, 0); 62 if (addr != (void *)-1) { 63 tst_res(TFAIL, "shmat() succeeded unexpectedly"); 64 return; 65 } 66 67 if (errno == tc->exp_err) { 68 tst_res(TPASS | TERRNO, "shmat() failed as expected"); 69 } else { 70 tst_res(TFAIL | TERRNO, "shmat() failed unexpectedly," 71 "expected: %s", tst_strerrno(tc->exp_err)); 72 } 73 } 74 75 static void do_shmat(unsigned int n) 76 { 77 pid_t pid; 78 79 struct test_case_t *tc = &tcases[n]; 80 81 if (!tc->exp_user) { 82 verify_shmat(tc); 83 } else { 84 pid = SAFE_FORK(); 85 if (pid) { 86 tst_reap_children(); 87 } else { 88 SAFE_SETUID(pw->pw_uid); 89 verify_shmat(tc); 90 exit(0); 91 } 92 } 93 } 94 95 static void setup(void) 96 { 97 aligned_addr = PROBE_FREE_ADDR(); 98 unaligned_addr = aligned_addr + SHMLBA - 1; 99 100 shm_key1 = GETIPCKEY(); 101 102 shm_id2 = SAFE_SHMGET(shm_key1, INT_SIZE, SHM_RW | IPC_CREAT | IPC_EXCL); 103 104 pw = SAFE_GETPWNAM("nobody"); 105 } 106 107 static void cleanup(void) 108 { 109 if (shm_id2 != -1) 110 SAFE_SHMCTL(shm_id2, IPC_RMID, NULL); 111 } 112 113 static struct tst_test test = { 114 .needs_root = 1, 115 .forks_child = 1, 116 .test = do_shmat, 117 .tcnt = ARRAY_SIZE(tcases), 118 .setup = setup, 119 .cleanup = cleanup 120 }; 121