blob: c128d3306ceba5cbf0c730017b63eadaec3fec1f [file] [log] [blame]
plars6c153562002-06-12 21:24:47 +00001/*
plars6c153562002-06-12 21:24:47 +00002 * Copyright (c) International Business Machines Corp., 2002
Zeng Linggang307e8262014-03-03 19:23:53 +08003 * 06/2002 Written by Paul Larson
plars6c153562002-06-12 21:24:47 +00004 *
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
Zeng Linggang307e8262014-03-03 19:23:53 +080016 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
plars6c153562002-06-12 21:24:47 +000018 */
19
20/*
Zeng Linggang307e8262014-03-03 19:23:53 +080021 * 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.
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080026 * 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.
plars6c153562002-06-12 21:24:47 +000034 */
Zeng Linggang307e8262014-03-03 19:23:53 +080035
plars6c153562002-06-12 21:24:47 +000036#include <errno.h>
37#include <unistd.h>
38#include <sys/mman.h>
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080039#include <pwd.h>
Zeng Linggang307e8262014-03-03 19:23:53 +080040
plars6c153562002-06-12 21:24:47 +000041#include "test.h"
Zeng Linggang307e8262014-03-03 19:23:53 +080042#include "safe_macros.h"
plars6c153562002-06-12 21:24:47 +000043
Cyril Hrubisfdce7d52013-04-04 18:35:48 +020044char *TCID = "mlock02";
plars6c153562002-06-12 21:24:47 +000045
robbiewd34d5812005-07-11 22:28:09 +000046#if !defined(UCLINUX)
47
Zeng Linggang307e8262014-03-03 19:23:53 +080048static void setup(void);
49static void cleanup(void);
50static void test_enomem1(void);
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080051static void test_enomem2(void);
52static void test_eperm(void);
Zeng Linggang307e8262014-03-03 19:23:53 +080053static void mlock_verify(const void *, const size_t, const int);
54
55static size_t len;
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080056static struct rlimit original;
57static struct passwd *ltpuser;
Zeng Linggang307e8262014-03-03 19:23:53 +080058
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080059static void (*test_func[])(void) = { test_enomem1, test_enomem2, test_eperm };
Zeng Linggang307e8262014-03-03 19:23:53 +080060
61int TST_TOTAL = ARRAY_SIZE(test_func);
Zeng Linggang307e8262014-03-03 19:23:53 +080062
plars6c153562002-06-12 21:24:47 +000063int main(int ac, char **av)
64{
Cyril Hrubis89af32a2012-10-24 16:39:11 +020065 int lc, i;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020066 const char *msg;
plars6c153562002-06-12 21:24:47 +000067
Garrett Cooperfa978462010-12-19 05:56:19 -080068 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
plars6c153562002-06-12 21:24:47 +000069 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
plars6c153562002-06-12 21:24:47 +000070
plars6c153562002-06-12 21:24:47 +000071 setup();
72
plars6c153562002-06-12 21:24:47 +000073 for (lc = 0; TEST_LOOPING(lc); lc++) {
Caspar Zhangd59a6592013-03-07 14:59:12 +080074 tst_count = 0;
Zeng Linggang307e8262014-03-03 19:23:53 +080075 for (i = 0; i < TST_TOTAL; i++)
76 (*test_func[i])();
Garrett Cooper2c282152010-12-16 00:55:50 -080077 }
plars6c153562002-06-12 21:24:47 +000078
plars6c153562002-06-12 21:24:47 +000079 cleanup();
Garrett Cooper2c282152010-12-16 00:55:50 -080080 tst_exit();
81}
plars6c153562002-06-12 21:24:47 +000082
Zeng Linggang307e8262014-03-03 19:23:53 +080083static void setup(void)
84{
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080085 tst_require_root(NULL);
86
Zeng Linggang307e8262014-03-03 19:23:53 +080087 tst_sig(NOFORK, DEF_HANDLER, cleanup);
88
89 TEST_PAUSE;
90
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080091 ltpuser = SAFE_GETPWNAM(cleanup, "nobody");
92
Zeng Linggang307e8262014-03-03 19:23:53 +080093 len = getpagesize();
Zeng Lingganged3e3eb2014-03-03 19:25:09 +080094
95 SAFE_GETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original);
Zeng Linggang307e8262014-03-03 19:23:53 +080096}
97
98static void test_enomem1(void)
99{
100 void *addr;
101 struct rlimit rl;
102
103 /*
104 * RLIMIT_MEMLOCK resource limit.
105 * In Linux kernels before 2.6.9, this limit controlled the amount
106 * of memory that could be locked by a privileged process. Since
107 * Linux 2.6.9, no limits are placed on the amount of memory that a
108 * privileged process may lock, and this limit instead governs the
109 * amount of memory that an unprivileged process may lock. So here
110 * we set RLIMIT_MEMLOCK resource limit to RLIM_INFINITY when kernel
111 * is under 2.6.9, to make sure this ENOMEM error is indeed caused by
112 * that some of the specified address range does not correspond to
113 * mapped pages in the address space of the process.
114 */
115 if ((tst_kvercmp(2, 6, 9)) < 0) {
116 rl.rlim_cur = RLIM_INFINITY;
117 rl.rlim_max = RLIM_INFINITY;
118 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl);
119 }
120
121 addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ,
122 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
123
124 SAFE_MUNMAP(cleanup, addr, len);
125
126 mlock_verify(addr, len, ENOMEM);
127}
128
Zeng Lingganged3e3eb2014-03-03 19:25:09 +0800129static void test_enomem2(void)
130{
131 void *addr;
132 struct rlimit rl;
133
134 if ((tst_kvercmp(2, 6, 9)) < 0) {
135 tst_resm(TCONF,
136 "ENOMEM error value test for this condition needs "
137 "kernel 2.6.9 or higher");
138 return;
139 }
140
141 rl.rlim_max = len - 1;
142 rl.rlim_cur = len - 1;
143 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl);
144
145 addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ,
146 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
147
148 SAFE_SETEUID(cleanup, ltpuser->pw_uid);
149
150 mlock_verify(addr, len, ENOMEM);
151
152 SAFE_SETEUID(cleanup, 0);
153
154 SAFE_MUNMAP(cleanup, addr, len);
155
156 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original);
157}
158
159static void test_eperm(void)
160{
161 void *addr;
162 struct rlimit rl;
163
164 if ((tst_kvercmp(2, 6, 9)) < 0) {
165 tst_resm(TCONF,
166 "EPERM error value test needs kernel 2.6.9 or higher");
167 return;
168 }
169
170 rl.rlim_max = 0;
171 rl.rlim_cur = 0;
172 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl);
173
174 addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ,
175 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
176
177 SAFE_SETEUID(cleanup, ltpuser->pw_uid);
178
179 mlock_verify(addr, len, EPERM);
180
181 SAFE_SETEUID(cleanup, 0);
182
183 SAFE_MUNMAP(cleanup, addr, len);
184
185 SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original);
186}
187
Zeng Linggang307e8262014-03-03 19:23:53 +0800188static void mlock_verify(const void *addr, const size_t len, const int error)
189{
190 TEST(mlock(addr, len));
191
192 if (TEST_RETURN != -1) {
193 tst_resm(TFAIL, "mlock succeeded unexpectedly");
194 return;
195 }
196
197 if (TEST_ERRNO != error) {
198 tst_resm(TFAIL | TTERRNO,
199 "mlock didn't fail as expected; expected - %d : %s",
200 error, strerror(error));
201 } else {
202 tst_resm(TPASS | TTERRNO, "mlock failed as expected");
203 }
204}
205
206static void cleanup(void)
207{
Zeng Linggang307e8262014-03-03 19:23:53 +0800208}
209
robbiewd34d5812005-07-11 22:28:09 +0000210#else
211
Zeng Linggang307e8262014-03-03 19:23:53 +0800212int TST_TOTAL = 1;
213
214int main(void)
robbiewd34d5812005-07-11 22:28:09 +0000215{
Garrett Cooperfa978462010-12-19 05:56:19 -0800216 tst_brkm(TCONF, NULL, "test is not available on uClinux");
robbiewd34d5812005-07-11 22:28:09 +0000217}
218
219#endif /* if !defined(UCLINUX) */