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 * Copyright (C) 2020 Cyril Hrubis <chrubis@suse.cz> 9 */ 10 11/*\ 12 * [Description] 13 * 14 * Test for EACCES, EFAULT and EINVAL errors. 15 * 16 * * EACCES - segment has no read or write permissions 17 * * EFAULT - IPC_SET & buf isn't valid 18 * * EFAULT - IPC_STAT & buf isn't valid 19 * * EINVAL - the command is not valid 20 * * EINVAL - the shmid is not valid 21 * * EINVAL - the shmid belongs to removed shm 22 * 23 * * EACCES - attempt to stat root-owned shm 24 * * EPERM - attempt to delete root-owned shm 25 * * EPERM - attempt to change root-owned shm 26 * * EPERM - attempt to lock root-owned shm 27 * * EPERM - attempt to unlock root-owned shm 28 */ 29 30#include <pwd.h> 31 32#include "tst_test.h" 33#include "tst_safe_sysv_ipc.h" 34#include "libnewipc.h" 35#include "lapi/syscalls.h" 36 37#define SHM_SIZE 2048 38 39static int shm_id1 = -1; 40static int shm_id2 = -1; 41static int shm_id3 = -1; 42static int shm_bad = -1; 43static int shm_rem; 44 45static struct shmid_ds buf; 46 47static int libc_shmctl(int shmid, int cmd, void *buf) 48{ 49 return shmctl(shmid, cmd, buf); 50} 51 52static int sys_shmctl(int shmid, int cmd, void *buf) 53{ 54 return tst_syscall(__NR_shmctl, shmid, cmd, buf); 55} 56 57static struct tcase { 58 int *shm_id; 59 int cmd; 60 struct shmid_ds *buf; 61 int error; 62} tc[] = { 63 {&shm_id1, IPC_STAT, &buf, EACCES}, 64 {&shm_id2, IPC_SET, (struct shmid_ds *)-1, EFAULT}, 65 {&shm_id2, IPC_STAT, (struct shmid_ds *)-1, EFAULT}, 66 {&shm_id2, -1, &buf, EINVAL}, 67 {&shm_bad, IPC_STAT, &buf, EINVAL}, 68 {&shm_rem, IPC_STAT, &buf, EINVAL}, 69 /* Operations on root-owned shm */ 70 {&shm_id3, IPC_STAT, &buf, EACCES}, 71 {&shm_id3, IPC_RMID, NULL, EPERM}, 72 {&shm_id3, IPC_SET, &buf, EPERM}, 73 {&shm_id3, SHM_LOCK, &buf, EPERM}, 74 {&shm_id3, SHM_UNLOCK, &buf, EPERM} 75}; 76 77static struct test_variants 78{ 79 int (*shmctl)(int shmid, int cmd, void *buf); 80 char *desc; 81} variants[] = { 82 { .shmctl = libc_shmctl, .desc = "libc shmctl()"}, 83#if (__NR_shmctl != __LTP__NR_INVALID_SYSCALL) 84 { .shmctl = sys_shmctl, .desc = "__NR_shmctl syscall"}, 85#endif 86}; 87 88static void verify_shmctl(unsigned int i) 89{ 90 struct test_variants *tv = &variants[tst_variant]; 91 92 if (tc[i].error == EFAULT && tv->shmctl == libc_shmctl) { 93 tst_res(TCONF, "EFAULT is skipped for libc variant"); 94 return; 95 } 96 97 TST_EXP_FAIL(tv->shmctl(*(tc[i].shm_id), tc[i].cmd, tc[i].buf), 98 tc[i].error, "shmctl(%i, %i, %p)", *(tc[i].shm_id), tc[i].cmd, tc[i].buf); 99} 100 101static void setup(void) 102{ 103 struct test_variants *tv = &variants[tst_variant]; 104 105 key_t shmkey1, shmkey2; 106 struct passwd *ltpuser; 107 int tmp; 108 109 tst_res(TINFO, "Testing variant: %s", tv->desc); 110 111 shm_id3 = SAFE_SHMGET(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | SHM_RW); 112 113 ltpuser = SAFE_GETPWNAM("nobody"); 114 SAFE_SETEUID(ltpuser->pw_uid); 115 116 shmkey1 = GETIPCKEY(); 117 shmkey2 = GETIPCKEY(); 118 119 shm_id1 = SAFE_SHMGET(shmkey1, SHM_SIZE, IPC_CREAT | IPC_EXCL); 120 shm_id2 = SAFE_SHMGET(shmkey2, SHM_SIZE, IPC_CREAT | IPC_EXCL | SHM_RW); 121 122 tmp = shm_rem = SAFE_SHMGET(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | SHM_RW); 123 SAFE_SHMCTL(tmp, IPC_RMID, NULL); 124} 125 126static void cleanup(void) 127{ 128 if (shm_id1 >= 0) 129 SAFE_SHMCTL(shm_id1, IPC_RMID, NULL); 130 131 if (shm_id2 >= 0) 132 SAFE_SHMCTL(shm_id2, IPC_RMID, NULL); 133 134 if (shm_id3 >= 0) { 135 SAFE_SETEUID(0); 136 SAFE_SHMCTL(shm_id3, IPC_RMID, NULL); 137 } 138} 139 140static struct tst_test test = { 141 .setup = setup, 142 .cleanup = cleanup, 143 .test = verify_shmctl, 144 .test_variants = ARRAY_SIZE(variants), 145 .tcnt = ARRAY_SIZE(tc), 146 .needs_root = 1, 147}; 148