master
c 512 lines 14.5 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 Ioprio.c
8
9 Abstract:
10
11 This file is a ioprio test.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <sys/time.h>
18 #include <sys/resource.h>
19 #include <sys/prctl.h>
20 #include "lxtutil.h"
21
22 #if !defined(__amd64__) && !defined(__aarch64__)
23
24 #include <sys/capability.h>
25
26 #else
27
28 #include <sys/cdefs.h>
29 #include <linux/capability.h>
30
31 #define _LINUX_CAPABILITY_VERSION_3 0x20080522
32
33 #ifndef O_PATH
34 #define O_PATH 010000000
35 #endif
36
37 #endif
38
39 #define IOPRIO_UID 1007
40 #define IOPRIO_GID 1007
41
42 //
43 // When the ioprio.h header is available, these types can be removed.
44 //
45
46 #define LX_IOPRIO_WHO_PROCESS 1
47 #define LX_IOPRIO_WHO_PGRP 2
48 #define LX_IOPRIO_WHO_USER 3
49
50 #define LX_IOPRIO_CLASS_NONE 0
51 #define LX_IOPRIO_CLASS_RT 1
52 #define LX_IOPRIO_CLASS_BE 2
53 #define LX_IOPRIO_CLASS_IDLE 3
54
55 #define LX_IOPRIO_CLASS_SHIFT 13
56 #define LX_IOPRIO_PRIO_MASK ((1 << LX_IOPRIO_CLASS_SHIFT) - 1)
57 #define LX_IOPRIO_PRIO_CLASS(_mask) ((_mask) >> LX_IOPRIO_CLASS_SHIFT)
58 #define LX_IOPRIO_PRIO_DATA(_mask) ((_mask) & LX_IOPRIO_PRIO_MASK)
59 #define LX_IOPRIO_PRIO_VALUE(_class, _data) (((_class) << LX_IOPRIO_CLASS_SHIFT) | (_data))
60 #define LX_IO_DEFAULT_PRIORITY 4
61
62 #define LXT_NAME "Ioprio"
63
64 int IoprioVariationGetProcess(PLXT_ARGS Args);
65
66 int IoprioVariationSetProcess(PLXT_ARGS Args);
67
68 int IoprioVariationGetSetPriority(PLXT_ARGS Args);
69
70 //
71 // Global constants
72 //
73
74 static const LXT_VARIATION g_LxtVariations[] = {
75 {"ioprio_get process", IoprioVariationGetProcess},
76 {"getpriority / setpriority", IoprioVariationGetSetPriority},
77 {"ioprio_set process", IoprioVariationSetProcess}};
78
79 int IoprioTestEntry(int Argc, char* Argv[])
80
81 /*++
82 --*/
83
84 {
85
86 LXT_ARGS Args;
87 int Result;
88
89 LxtInitialize(Argc, Argv, &Args, LXT_NAME);
90 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
91
92 ErrorExit:
93 LxtUninitialize();
94 return !LXT_SUCCESS(Result);
95 }
96
97 int IoprioVariationGetProcess(PLXT_ARGS Args)
98
99 /*++
100 --*/
101
102 {
103
104 int DefaultPriority;
105 int IoPrio;
106 int Result;
107
108 //
109 // Negative variations.
110 //
111
112 LxtCheckErrnoFailure(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, -1), ESRCH);
113 LxtCheckErrnoFailure(IoPrio = LxtIoprio_get(0, 0), EINVAL);
114
115 //
116 // Get the default priority for the current and parent thread.
117 //
118
119 LxtCheckErrno(DefaultPriority = getpriority(PRIO_PROCESS, 0));
120 LxtLogInfo("DefaultPriority: %d", DefaultPriority);
121 LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
122 LxtCheckEqual(IoPrio, LX_IO_DEFAULT_PRIORITY, "%d");
123 LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, getpid()));
124 LxtCheckEqual(IoPrio, LX_IO_DEFAULT_PRIORITY, "%d");
125 LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, getppid()));
126 LxtCheckEqual(IoPrio, LX_IO_DEFAULT_PRIORITY, "%d");
127
128 //
129 // Set the priority of the current thread and check that it does not change
130 // the io priority.
131 //
132
133 LxtCheckErrno(setpriority(PRIO_PROCESS, 0, LX_IO_DEFAULT_PRIORITY + 1));
134 LxtCheckErrno(IoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
135 LxtCheckNotEqual(IoPrio, LX_IO_DEFAULT_PRIORITY + 1, "%d");
136
137 Result = LXT_RESULT_SUCCESS;
138
139 ErrorExit:
140 setpriority(PRIO_PROCESS, 0, LX_IO_DEFAULT_PRIORITY);
141 return Result;
142 }
143
144 int IoprioVariationSetProcess(PLXT_ARGS Args)
145
146 /*++
147 --*/
148
149 {
150
151 struct __user_cap_data_struct CapData[2];
152 struct __user_cap_header_struct CapHeader;
153 int ChildPid;
154 int DefaultPriority;
155 int Index;
156 int InitialIoPrio;
157 int IoPrio;
158 int NewIoPrio;
159 int Result;
160
161 ChildPid = -1;
162
163 //
164 // Get the default priority for the current and parent thread.
165 //
166 // N.B. Setting the IO priority to this default value fails.
167 //
168
169 LxtCheckErrno(InitialIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
170 LxtLogInfo("InitialIoPrio = %d", InitialIoPrio);
171 IoPrio = InitialIoPrio;
172 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
173
174 //
175 // LX_IOPRIO_CLASS_NONE
176 //
177
178 for (Index = 0; Index < 1; Index += 1)
179 {
180 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, Index);
181 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
182 LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
183 LxtCheckEqual(IoPrio, NewIoPrio, "%d");
184 }
185
186 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, Index);
187 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
188
189 //
190 // LX_IOPRIO_CLASS_RT
191 //
192
193 for (Index = 0; Index < 8; Index += 1)
194 {
195 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
196 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
197 LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
198 LxtCheckEqual(IoPrio, NewIoPrio, "%d");
199 }
200
201 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
202 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
203
204 //
205 // LX_IOPRIO_CLASS_BE
206 //
207
208 for (Index = 0; Index < 8; Index += 1)
209 {
210 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
211 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
212 LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
213 LxtCheckEqual(IoPrio, NewIoPrio, "%d");
214 }
215
216 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
217 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
218
219 //
220 // LX_IOPRIO_CLASS_IDLE
221 //
222
223 for (Index = 0; Index < 0x8000; Index += 1)
224 {
225 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_IDLE, Index);
226 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
227 LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
228 LxtCheckEqual(IoPrio, NewIoPrio, "%d");
229 }
230
231 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_IDLE, Index);
232 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
233
234 LxtCheckErrno(ChildPid = fork());
235 if (ChildPid == 0)
236 {
237 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
238 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, getppid(), IoPrio));
239
240 memset(&CapData, 0, sizeof(CapData));
241 memset(&CapHeader, 0, sizeof(CapHeader));
242 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
243 CapData[CAP_TO_INDEX(CAP_SYS_ADMIN)].permitted |= CAP_TO_MASK(CAP_SYS_ADMIN);
244 CapData[0].effective = CapData[0].permitted;
245 CapData[1].effective = CapData[1].permitted;
246
247 //
248 // Drop all privileges but CAP_SYS_ADMIN.
249 //
250
251 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
252 LxtCheckErrno(setgid(IOPRIO_UID));
253 LxtCheckErrno(setuid(IOPRIO_GID));
254 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
255
256 //
257 // Attempt to change parent's io priority now that UID / GID do not match.
258 //
259
260 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
261 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, getppid(), IoPrio), EPERM);
262
263 for (Index = 0; Index < 8; Index += 1)
264 {
265 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
266 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
267 LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
268 LxtCheckEqual(IoPrio, NewIoPrio, "%d");
269 }
270
271 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, Index);
272 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
273
274 //
275 // Drop all privileges.
276 //
277
278 memset(&CapData, 0, sizeof(CapData));
279 memset(&CapHeader, 0, sizeof(CapHeader));
280 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
281 CapData[0].effective = CapData[0].permitted;
282 CapData[1].effective = CapData[1].permitted;
283 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
284 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, 0);
285 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EPERM);
286 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_RT, 8);
287 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EPERM);
288
289 //
290 // LX_IOPRIO_CLASS_NONE
291 //
292
293 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
294 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
295 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 1);
296 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
297
298 //
299 // LX_IOPRIO_CLASS_BE
300 //
301
302 for (Index = 0; Index < 8; Index += 1)
303 {
304 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
305 LxtCheckErrno(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio));
306 LxtCheckErrno(NewIoPrio = LxtIoprio_get(LX_IOPRIO_WHO_PROCESS, 0));
307 LxtCheckEqual(IoPrio, NewIoPrio, "%d");
308 }
309
310 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_BE, Index);
311 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
312 goto ErrorExit;
313 }
314
315 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
316
317 //
318 // Negative variations.
319 //
320
321 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
322 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, -1, IoPrio), ESRCH);
323 LxtCheckErrnoFailure(LxtIoprio_set(0, 0, IoPrio), EINVAL);
324 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_IDLE + 1, 0);
325 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
326 IoPrio = LX_IOPRIO_PRIO_VALUE(-1, 0);
327 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_PROCESS, 0, IoPrio), EINVAL);
328 LxtCheckErrnoFailure(LxtIoprio_set(0, 0, IoPrio), EINVAL);
329 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 0);
330 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, 0, IoPrio), EINVAL);
331 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, -1, IoPrio), EINVAL);
332 IoPrio = LX_IOPRIO_PRIO_VALUE(LX_IOPRIO_CLASS_NONE, 1);
333 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, 0, IoPrio), EINVAL);
334 LxtCheckErrnoFailure(LxtIoprio_set(LX_IOPRIO_WHO_USER + 1, -1, IoPrio), EINVAL);
335
336 Result = LXT_RESULT_SUCCESS;
337
338 ErrorExit:
339 if (ChildPid == 0)
340 {
341 _exit(Result);
342 }
343
344 return Result;
345 }
346
347 int IoprioSetPriority(int Which, int Who, int Priority, int ExpectedPriority)
348
349 {
350
351 int Result;
352
353 LxtCheckErrno(setpriority(Which, Who, Priority));
354 errno = 0;
355 Result = getpriority(Which, Who);
356 if ((Result != ExpectedPriority) || (errno != 0))
357 {
358 LxtLogError("getpriority returned %d expected %d - errno %d", Result, ExpectedPriority, errno);
359
360 Result = LXT_RESULT_FAILURE;
361 goto ErrorExit;
362 }
363
364 Result = LXT_RESULT_SUCCESS;
365
366 ErrorExit:
367 return Result;
368 }
369
370 int IoprioVariationGetSetPriority(PLXT_ARGS Args)
371
372 {
373 int ChildPid;
374 int OriginalPriority;
375 pid_t ParentPid;
376 int Result;
377 struct rlimit Rlimit;
378
379 ChildPid = -1;
380 errno = 0;
381 OriginalPriority = getpriority(PRIO_PROCESS, 0);
382 LxtLogInfo("OriginalPriority %d", OriginalPriority);
383
384 //
385 // Validate setting the priority to a negative number.
386 //
387
388 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -1, -1));
389
390 //
391 // Validate setting the priority to a positive number.
392 //
393
394 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 5, 5));
395
396 //
397 // Validate the lower bound of the priority (-20).
398 //
399
400 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -20, -20));
401 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -21, -20));
402 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, -444, -20));
403
404 //
405 // Validate the upper bound of the priority (19).
406 //
407
408 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 19, 19));
409 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 20, 19));
410 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 444, 19));
411
412 //
413 // Invalid parameter variations.
414 //
415
416 LxtCheckErrnoFailure(getpriority(-1, 0), EINVAL);
417
418 //
419 // Permissions checks. Reset the priority to a known value.
420 //
421
422 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 5, 5));
423 ParentPid = getpid();
424 LxtCheckErrno(ChildPid = fork());
425 if (ChildPid == 0)
426 {
427
428 //
429 // Change the UID to drop CAP_SYS_NICE and verify that the priority can
430 // be set to the same value.
431 //
432
433 LxtCheckErrno(setuid(1000));
434 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 5, 5));
435
436 //
437 // Attempt to lower the priority.
438 //
439
440 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 6, 6));
441
442 //
443 // Attempt to raise the priority (should fail).
444 //
445
446 LxtCheckErrnoFailure(setpriority(PRIO_PROCESS, 0, 4), EACCES);
447
448 //
449 // Attempt to modify the parent's priority (should fail).
450 //
451
452 LxtCheckErrnoFailure(setpriority(PRIO_PROCESS, ParentPid, 5), EPERM);
453 goto ErrorExit;
454 }
455
456 //
457 // Wait for the child to exit.
458 //
459
460 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
461
462 LxtCheckErrno(ChildPid = fork());
463 if (ChildPid == 0)
464 {
465
466 //
467 // Change the nice rlimit value.
468 //
469
470 Rlimit.rlim_cur = 19;
471 Rlimit.rlim_max = 19;
472 LxtCheckErrno(setrlimit(RLIMIT_NICE, &Rlimit));
473
474 //
475 // Change the UID to drop CAP_SYS_NICE.
476 //
477
478 LxtCheckErrno(setuid(1000));
479
480 //
481 // Setting the priority to 1 should succeed.
482 //
483 LxtCheckResult(IoprioSetPriority(PRIO_PROCESS, 0, 1, 1));
484
485 //
486 // Setting the priority to 0 should fail.
487 //
488
489 LxtCheckErrnoFailure(setpriority(PRIO_PROCESS, 0, 0), EACCES);
490 goto ErrorExit;
491 }
492
493 //
494 // Wait for the child to exit.
495 //
496
497 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
498 Result = LXT_RESULT_SUCCESS;
499
500 ErrorExit:
501 if (ChildPid == 0)
502 {
503 _exit(Result);
504 }
505
506 if (OriginalPriority > 0)
507 {
508 setpriority(PRIO_PROCESS, 0, OriginalPriority);
509 }
510
511 return Result;
512 }