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; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19/* 20 * DESCRIPTION 21 * 22 * 1) shmat() chooses a suitable (unused) address when shmaddr is NULL. 23 * 2) shmat() attaches shm segment to the shmaddr when shmaddr is a 24 * page-aligned address. 25 * 3) shmat() attaches shm segment to the address equal to shmaddr rounded 26 * down to the nearest multiple of SHMLBA when shmaddr is a page-unaligned 27 * address and shmflg is set to SHM_RND. 28 * 4) shmat() attaches shm segment to the shmaddr for reading when shmflg 29 * is set to SHM_RDONLY. 30 */ 31 32#include <errno.h> 33#include <sys/types.h> 34#include <sys/ipc.h> 35#include <sys/shm.h> 36#include <sys/wait.h> 37#include <stdlib.h> 38#include <stdint.h> 39 40#include "tst_test.h" 41#include "tst_safe_sysv_ipc.h" 42#include "libnewipc.h" 43 44#define ALIGN_DOWN(in_addr) ((void *)(((uintptr_t)in_addr / SHMLBA) * SHMLBA)) 45 46static int shm_id = -1; 47static key_t shm_key; 48static void *null_addr; 49static void *aligned_addr; 50static void *unaligned_addr; 51 52static struct test_case_t { 53 void **shmaddr; 54 int flag; 55 int exp_status; 56 char *desp; 57} tcases[] = { 58 {&null_addr, 0, 0, "NULL address"}, 59 {&aligned_addr, 0, 0, "aligned address"}, 60 {&unaligned_addr, SHM_RND, 0, "unaligned address with SHM_RND"}, 61 {&aligned_addr, SHM_RDONLY, SIGSEGV, 62 "aligned address with SHM_READONLY, and got SIGSEGV on write"} 63}; 64 65static void *expected_addr(void *in_addr, void *out_addr) 66{ 67 if (!in_addr) 68 return out_addr; 69 70 return ALIGN_DOWN(in_addr); 71} 72 73static void do_child(int *in_addr, int expect_crash) 74{ 75 if (expect_crash) { 76 /* 77 * Crash is expected, avoid dumping corefile. 78 * 1 is a special value, that disables core-to-pipe. 79 * At the same time it is small enough value for 80 * core-to-file, so it skips creating cores as well. 81 */ 82 struct rlimit r; 83 84 r.rlim_cur = 1; 85 r.rlim_max = 1; 86 SAFE_SETRLIMIT(RLIMIT_CORE, &r); 87 } 88 *in_addr = 10; 89 90 exit(0); 91} 92 93static int expected_status(int status, int exp_status) 94{ 95 if (!exp_status && WIFEXITED(status)) 96 return 0; 97 98 if (exp_status && WIFSIGNALED(status) && WTERMSIG(status) == exp_status) 99 return 0; 100 101 return 1; 102} 103 104static void verify_shmat(unsigned int n) 105{ 106 int *addr; 107 pid_t pid; 108 int status; 109 struct shmid_ds buf; 110 111 struct test_case_t *tc = &tcases[n]; 112 113 addr = shmat(shm_id, *tc->shmaddr, tc->flag); 114 if (addr == (void *)-1) { 115 tst_res(TFAIL | TERRNO, "shmat() failed"); 116 return; 117 } 118 119 SAFE_SHMCTL(shm_id, IPC_STAT, &buf); 120 121 if (buf.shm_nattch != 1) { 122 tst_res(TFAIL, "number of attaches was incorrect"); 123 goto end; 124 } 125 126 if (buf.shm_segsz != INT_SIZE) { 127 tst_res(TFAIL, "segment size was incorrect"); 128 goto end; 129 } 130 131 if (expected_addr(*tc->shmaddr, addr) != addr) { 132 tst_res(TFAIL, 133 "shared memory address %p is not correct, expected %p", 134 addr, expected_addr(*tc->shmaddr, addr)); 135 goto end; 136 } 137 138 pid = SAFE_FORK(); 139 if (!pid) 140 do_child(addr, tc->exp_status == SIGSEGV); 141 else 142 SAFE_WAITPID(pid, &status, 0); 143 144 if (expected_status(status, tc->exp_status)) 145 tst_res(TFAIL, "shmat() failed to attach %s", tc->desp); 146 else 147 tst_res(TPASS, "shmat() succeeded to attach %s", tc->desp); 148 149end: 150 SAFE_SHMDT(addr); 151} 152 153static void setup(void) 154{ 155 aligned_addr = PROBE_FREE_ADDR(); 156 unaligned_addr = aligned_addr + SHMLBA - 1; 157 158 shm_key = GETIPCKEY(); 159 160 shm_id = SAFE_SHMGET(shm_key, INT_SIZE, SHM_RW | IPC_CREAT | IPC_EXCL); 161} 162 163static void cleanup(void) 164{ 165 if (shm_id != -1) 166 SAFE_SHMCTL(shm_id, IPC_RMID, NULL); 167} 168 169static struct tst_test test = { 170 .needs_root = 1, 171 .forks_child = 1, 172 .setup = setup, 173 .cleanup = cleanup, 174 .test = verify_shmat, 175 .tcnt = ARRAY_SIZE(tcases) 176}; 177