1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2020 Cyril Hrubis <chrubis@suse.cz>
4 */
5
6 /*\
7 * [Description]
8 *
9 * Test for a SHM_SET.
10 *
11 * The test clears the group and others bits from the shm_perm.mode and checks
12 * the result as well as if the ctime was updated correctly.
13 */
14
15 #define _GNU_SOURCE
16 #include <stdio.h>
17 #include "tst_test.h"
18 #include "tst_safe_sysv_ipc.h"
19 #include "libnewipc.h"
20
21 #define SHM_SIZE 2048
22
23 static int shm_id = -1;
24
test_ipc_set(struct shmid_ds * ds)25 static int test_ipc_set(struct shmid_ds *ds)
26 {
27 TEST(shmctl(shm_id, IPC_SET, ds));
28
29 if (TST_RET != 0) {
30 tst_res(TFAIL, "shmctl(%i, IPC_SET, ...)", shm_id);
31 return 1;
32 }
33
34 tst_res(TPASS, "shmctl(%i, IPC_SET, {shm_perm.mode=%04o})",
35 shm_id, ds->shm_perm.mode);
36 return 0;
37 }
38
check_mode(struct shmid_ds * ds,short exp_mode)39 static void check_mode(struct shmid_ds *ds, short exp_mode)
40 {
41 if (ds->shm_perm.mode == exp_mode) {
42 tst_res(TPASS, "shm_perm.mode=%04o", exp_mode);
43 return;
44 }
45
46 tst_res(TFAIL, "shm_perm.mode=%04o, expected %i",
47 ds->shm_perm.mode, exp_mode);
48 }
49
verify_shmset(void)50 static void verify_shmset(void)
51 {
52 struct shmid_ds ds;
53 unsigned short old_mode;
54 time_t old_ctime;
55
56 SAFE_SHMCTL(shm_id, IPC_STAT, &ds);
57
58 old_mode = ds.shm_perm.mode;
59 old_ctime = ds.shm_ctime;
60
61 check_mode(&ds, 0666);
62
63 sleep(1);
64
65 ds.shm_perm.mode &= ~0066;
66
67 if (test_ipc_set(&ds))
68 return;
69
70 memset(&ds, 0, sizeof(ds));
71 SAFE_SHMCTL(shm_id, IPC_STAT, &ds);
72 check_mode(&ds, old_mode & ~0066);
73
74 if (ds.shm_ctime <= old_ctime || ds.shm_ctime > old_ctime + 10) {
75 tst_res(TFAIL, "shm_ctime not updated old %li new %li",
76 (long)old_ctime, (long)ds.shm_ctime);
77 } else {
78 tst_res(TPASS, "shm_ctime updated correctly diff=%li",
79 (long)(ds.shm_ctime - old_ctime));
80 }
81
82 ds.shm_perm.mode = old_mode;
83 if (test_ipc_set(&ds))
84 return;
85
86 memset(&ds, 0, sizeof(ds));
87 SAFE_SHMCTL(shm_id, IPC_STAT, &ds);
88 check_mode(&ds, old_mode & MODE_MASK);
89 }
90
setup(void)91 static void setup(void)
92 {
93 shm_id = SAFE_SHMGET(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
94 }
95
cleanup(void)96 static void cleanup(void)
97 {
98 if (shm_id >= 0)
99 SAFE_SHMCTL(shm_id, IPC_RMID, NULL);
100 }
101
102 static struct tst_test test = {
103 .setup = setup,
104 .cleanup = cleanup,
105 .test_all = verify_shmset,
106 };
107