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
verify_shmat(struct test_case_t * tc)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
do_shmat(unsigned int n)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
setup(void)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
cleanup(void)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