• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines  Corp., 2001
4  *  03/2001 - Written by Wayne Boyer
5  *
6  * Copyright (c) 2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com)
7  */
8 
9 /*\
10  * [Description]
11  *
12  * Test for ENOENT, EEXIST, EINVAL, EACCES, EPERM errors.
13  *
14  * ENOENT - No segment exists for the given key and IPC_CREAT was not specified.
15  * EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given.
16  * EINVAL - A new segment was to be created and size is less than SHMMIN or
17  * greater than SHMMAX. Or a segment for the given key exists, but size is
18  * gran eater than the size of that segment.
19  * EACCES - The user does not have permission to access the shared memory segment.
20  * EPERM - The SHM_HUGETLB flag was specified, but the caller was not privileged
21  * (did not have the CAP_IPC_LOCK capability) and is not a member of the
22  * sysctl_hugetlb_shm_group group.
23  * ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but not
24  * have enough hugepage memory space.
25  */
26 
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/ipc.h>
30 #include <stdlib.h>
31 #include <pwd.h>
32 #include <sys/shm.h>
33 #include <grp.h>
34 #include "tst_safe_sysv_ipc.h"
35 #include "tst_kconfig.h"
36 #include "tst_test.h"
37 #include "libnewipc.h"
38 #include "lapi/shm.h"
39 
40 #define CONFIG_HUGETLBFS "CONFIG_HUGETLBFS"
41 
42 static int shm_id = -1;
43 static key_t shmkey, shmkey1;
44 static struct passwd *pw;
45 
46 static struct tcase {
47 	int *shmkey;
48 	size_t size;
49 	int flags;
50 	/*1: nobody expected  0: root expected */
51 	int exp_user;
52 	/*1: nobody expected  0: root expected */
53 	int exp_group;
54 	int exp_err;
55 } tcases[] = {
56 	{&shmkey1, SHM_SIZE, IPC_EXCL, 0, 0, ENOENT},
57 	{&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL, 0, 0, EEXIST},
58 	{&shmkey1, SHMMIN - 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL},
59 	{&shmkey1, SHMMAX + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL},
60 	{&shmkey, SHM_SIZE * 2, IPC_EXCL, 0, 0, EINVAL},
61 	{&shmkey, SHM_SIZE, SHM_RD, 1, 0, EACCES},
62 	{&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 1, EPERM},
63 	{&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 0, ENOMEM}
64 };
65 
get_hugetlb_exp_error(void)66 static int get_hugetlb_exp_error(void)
67 {
68 	long tmp;
69 	struct tst_kconfig_var kconfig = {
70 		.id = CONFIG_HUGETLBFS,
71 		.id_len = sizeof(CONFIG_HUGETLBFS)-1,
72 	};
73 
74 	tst_kconfig_read(&kconfig, 1);
75 
76 	if (kconfig.choice != 'y') {
77 		tst_res(TINFO, "SHM_HUGETLB not supported by kernel");
78 		return EINVAL;
79 	}
80 
81 	if (FILE_LINES_SCANF("/proc/meminfo", "Hugepagesize: %ld", &tmp)) {
82 		tst_res(TINFO, "Huge pages not supported by hardware");
83 		return ENOENT;
84 	}
85 
86 	return 0;
87 }
88 
do_test(unsigned int n)89 static void do_test(unsigned int n)
90 {
91 	struct tcase *tc = &tcases[n];
92 	pid_t pid;
93 
94 	if (tc->exp_user == 0 && tc->exp_group == 0) {
95 		TST_EXP_FAIL2(shmget(*tc->shmkey, tc->size, tc->flags), tc->exp_err,
96 			"shmget(%i, %lu, %i)", *tc->shmkey, tc->size, tc->flags);
97 		return;
98 	}
99 
100 	pid = SAFE_FORK();
101 	if (pid == 0) {
102 		if (tc->exp_group) {
103 			SAFE_SETGROUPS(0, NULL);
104 			SAFE_SETGID(pw->pw_gid);
105 		}
106 		SAFE_SETUID(pw->pw_uid);
107 		TST_EXP_FAIL2(shmget(*tc->shmkey, tc->size, tc->flags), tc->exp_err,
108 			"shmget(%i, %lu, %i)", *tc->shmkey, tc->size, tc->flags);
109 		exit(0);
110 	}
111 	tst_reap_children();
112 }
113 
setup(void)114 static void setup(void)
115 {
116 	struct rlimit rl = { 0, 0 };
117 	int hugetlb_errno;
118 	unsigned int i;
119 
120 	shmkey = GETIPCKEY();
121 	shmkey1 = GETIPCKEY();
122 
123 	SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl);
124 	shm_id = SAFE_SHMGET(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL);
125 	pw = SAFE_GETPWNAM("nobody");
126 	hugetlb_errno = get_hugetlb_exp_error();
127 
128 	if (!hugetlb_errno)
129 		return;
130 
131 	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
132 		if (tcases[i].flags & SHM_HUGETLB)
133 			tcases[i].exp_err = hugetlb_errno;
134 	}
135 }
136 
cleanup(void)137 static void cleanup(void)
138 {
139 	if (shm_id >= 0)
140 		SAFE_SHMCTL(shm_id, IPC_RMID, NULL);
141 }
142 
143 static struct tst_test test = {
144 	.needs_tmpdir = 1,
145 	.needs_root = 1,
146 	.forks_child = 1,
147 	.setup = setup,
148 	.cleanup = cleanup,
149 	.test = do_test,
150 	.tcnt = ARRAY_SIZE(tcases),
151 	.request_hugepages = TST_NO_HUGEPAGES,
152 };
153