xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/ipc/shmget/shmget02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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 ([email protected])
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
21  *   privileged (did not have the CAP_IPC_LOCK capability) and is not a member
22  *   of the sysctl_hugetlb_shm_group group.
23  * - ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but
24  *   not 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 static int shm_id = -1;
41 static key_t shmkey, shmkey1;
42 static struct passwd *pw;
43 
44 static struct tcase {
45 	int *shmkey;
46 	size_t size;
47 	int flags;
48 	/*1: nobody expected  0: root expected */
49 	int exp_user;
50 	/*1: nobody expected  0: root expected */
51 	int exp_group;
52 	int exp_err;
53 } tcases[] = {
54 	{&shmkey1, SHM_SIZE, IPC_EXCL, 0, 0, ENOENT},
55 	{&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL, 0, 0, EEXIST},
56 	{&shmkey1, SHMMIN - 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL},
57 	{&shmkey1, 8192 + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL},
58 	{&shmkey, SHM_SIZE * 2, IPC_EXCL, 0, 0, EINVAL},
59 	{&shmkey, SHM_SIZE, SHM_RD, 1, 0, EACCES},
60 	{&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 1, EPERM},
61 	{&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 0, ENOMEM}
62 };
63 
get_hugetlb_exp_error(void)64 static int get_hugetlb_exp_error(void)
65 {
66 	long tmp;
67 	struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_HUGETLBFS");
68 
69 	tst_kconfig_read(&kconfig, 1);
70 
71 	if (kconfig.choice != 'y') {
72 		tst_res(TINFO, "SHM_HUGETLB not supported by kernel");
73 		return EINVAL;
74 	}
75 
76 	if (FILE_LINES_SCANF("/proc/meminfo", "Hugepagesize: %ld", &tmp)) {
77 		tst_res(TINFO, "Huge pages not supported by hardware");
78 		return ENOENT;
79 	}
80 
81 	return 0;
82 }
83 
do_test(unsigned int n)84 static void do_test(unsigned int n)
85 {
86 	struct tcase *tc = &tcases[n];
87 	pid_t pid;
88 
89 	if (tc->exp_user == 0 && tc->exp_group == 0) {
90 		TST_EXP_FAIL2(shmget(*tc->shmkey, tc->size, tc->flags), tc->exp_err,
91 			"shmget(%i, %lu, %i)", *tc->shmkey, tc->size, tc->flags);
92 		return;
93 	}
94 
95 	pid = SAFE_FORK();
96 	if (pid == 0) {
97 		if (tc->exp_group) {
98 			SAFE_SETGROUPS(0, NULL);
99 			SAFE_SETGID(pw->pw_gid);
100 		}
101 		SAFE_SETUID(pw->pw_uid);
102 		TST_EXP_FAIL2(shmget(*tc->shmkey, tc->size, tc->flags), tc->exp_err,
103 			"shmget(%i, %lu, %i)", *tc->shmkey, tc->size, tc->flags);
104 		exit(0);
105 	}
106 	tst_reap_children();
107 }
108 
setup(void)109 static void setup(void)
110 {
111 	struct rlimit rl = { 0, 0 };
112 	int hugetlb_errno;
113 	unsigned int i;
114 
115 	shmkey = GETIPCKEY();
116 	shmkey1 = GETIPCKEY();
117 
118 	SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl);
119 	shm_id = SAFE_SHMGET(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL);
120 	pw = SAFE_GETPWNAM("nobody");
121 	hugetlb_errno = get_hugetlb_exp_error();
122 
123 	if (!hugetlb_errno)
124 		return;
125 
126 	for (i = 0; i < ARRAY_SIZE(tcases); i++) {
127 		if (tcases[i].flags & SHM_HUGETLB)
128 			tcases[i].exp_err = hugetlb_errno;
129 	}
130 }
131 
cleanup(void)132 static void cleanup(void)
133 {
134 	if (shm_id >= 0)
135 		SAFE_SHMCTL(shm_id, IPC_RMID, NULL);
136 }
137 
138 static struct tst_test test = {
139 	.needs_tmpdir = 1,
140 	.needs_root = 1,
141 	.forks_child = 1,
142 	.setup = setup,
143 	.cleanup = cleanup,
144 	.test = do_test,
145 	.tcnt = ARRAY_SIZE(tcases),
146 	.hugepages = {TST_NO_HUGEPAGES},
147 	.save_restore = (const struct tst_path_val[]) {
148 		{"/proc/sys/kernel/shmmax", "8192", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO},
149 		{}
150 	},
151 };
152