1 /* 2 * Copyright (c) International Business Machines Corp., 2002 3 * 06/2002 Written by Paul Larson 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * Test Description: 22 * Verify that, 23 * 1. mlock() fails with -1 return value and sets errno to ENOMEM, 24 * if some of the specified address range does not correspond to 25 * mapped pages in the address space of the process. 26 * 2. mlock() fails with -1 return value and sets errno to ENOMEM, 27 * if (Linux 2.6.9 and later) the caller had a non-zero RLIMIT_MEMLOCK 28 * soft resource limit, but tried to lock more memory than the limit 29 * permitted. This limit is not enforced if the process is privileged 30 * (CAP_IPC_LOCK). 31 * 3. mlock() fails with -1 return value and sets errno to EPERM, 32 * if (Linux 2.6.9 and later) the caller was not privileged (CAP_IPC_LOCK) 33 * and its RLIMIT_MEMLOCK soft resource limit was 0. 34 */ 35 36 #include <errno.h> 37 #include <unistd.h> 38 #include <sys/mman.h> 39 #include <pwd.h> 40 41 #include "test.h" 42 #include "safe_macros.h" 43 44 char *TCID = "mlock02"; 45 46 #if !defined(UCLINUX) 47 48 static void setup(void); 49 static void cleanup(void); 50 static void test_enomem1(void); 51 static void test_enomem2(void); 52 static void test_eperm(void); 53 static void mlock_verify(const void *, const size_t, const int); 54 55 static size_t len; 56 static struct rlimit original; 57 static struct passwd *ltpuser; 58 59 static void (*test_func[])(void) = { test_enomem1, test_enomem2, test_eperm }; 60 61 int TST_TOTAL = ARRAY_SIZE(test_func); 62 63 int main(int ac, char **av) 64 { 65 int lc, i; 66 67 tst_parse_opts(ac, av, NULL, NULL); 68 69 setup(); 70 71 for (lc = 0; TEST_LOOPING(lc); lc++) { 72 tst_count = 0; 73 for (i = 0; i < TST_TOTAL; i++) 74 (*test_func[i])(); 75 } 76 77 cleanup(); 78 tst_exit(); 79 } 80 81 static void setup(void) 82 { 83 tst_require_root(); 84 85 tst_sig(NOFORK, DEF_HANDLER, cleanup); 86 87 TEST_PAUSE; 88 89 ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); 90 91 len = getpagesize(); 92 93 SAFE_GETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); 94 } 95 96 static void test_enomem1(void) 97 { 98 void *addr; 99 struct rlimit rl; 100 101 /* 102 * RLIMIT_MEMLOCK resource limit. 103 * In Linux kernels before 2.6.9, this limit controlled the amount 104 * of memory that could be locked by a privileged process. Since 105 * Linux 2.6.9, no limits are placed on the amount of memory that a 106 * privileged process may lock, and this limit instead governs the 107 * amount of memory that an unprivileged process may lock. So here 108 * we set RLIMIT_MEMLOCK resource limit to RLIM_INFINITY when kernel 109 * is under 2.6.9, to make sure this ENOMEM error is indeed caused by 110 * that some of the specified address range does not correspond to 111 * mapped pages in the address space of the process. 112 */ 113 if ((tst_kvercmp(2, 6, 9)) < 0) { 114 rl.rlim_cur = RLIM_INFINITY; 115 rl.rlim_max = RLIM_INFINITY; 116 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); 117 } 118 119 addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, 120 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 121 122 SAFE_MUNMAP(cleanup, addr, len); 123 124 mlock_verify(addr, len, ENOMEM); 125 } 126 127 static void test_enomem2(void) 128 { 129 void *addr; 130 struct rlimit rl; 131 132 if ((tst_kvercmp(2, 6, 9)) < 0) { 133 tst_resm(TCONF, 134 "ENOMEM error value test for this condition needs " 135 "kernel 2.6.9 or higher"); 136 return; 137 } 138 139 rl.rlim_max = len - 1; 140 rl.rlim_cur = len - 1; 141 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); 142 143 addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, 144 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 145 146 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 147 148 mlock_verify(addr, len, ENOMEM); 149 150 SAFE_SETEUID(cleanup, 0); 151 152 SAFE_MUNMAP(cleanup, addr, len); 153 154 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); 155 } 156 157 static void test_eperm(void) 158 { 159 void *addr; 160 struct rlimit rl; 161 162 if ((tst_kvercmp(2, 6, 9)) < 0) { 163 tst_resm(TCONF, 164 "EPERM error value test needs kernel 2.6.9 or higher"); 165 return; 166 } 167 168 rl.rlim_max = 0; 169 rl.rlim_cur = 0; 170 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); 171 172 addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, 173 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 174 175 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 176 177 mlock_verify(addr, len, EPERM); 178 179 SAFE_SETEUID(cleanup, 0); 180 181 SAFE_MUNMAP(cleanup, addr, len); 182 183 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); 184 } 185 186 static void mlock_verify(const void *addr, const size_t len, const int error) 187 { 188 TEST(mlock(addr, len)); 189 190 if (TEST_RETURN != -1) { 191 tst_resm(TFAIL, "mlock succeeded unexpectedly"); 192 return; 193 } 194 195 if (TEST_ERRNO != error) { 196 tst_resm(TFAIL | TTERRNO, 197 "mlock didn't fail as expected; expected - %d : %s", 198 error, strerror(error)); 199 } else { 200 tst_resm(TPASS | TTERRNO, "mlock failed as expected"); 201 } 202 } 203 204 static void cleanup(void) 205 { 206 } 207 208 #else 209 210 int TST_TOTAL = 1; 211 212 int main(void) 213 { 214 tst_brkm(TCONF, NULL, "test is not available on uClinux"); 215 } 216 217 #endif /* if !defined(UCLINUX) */ 218