master
c 2,581 lines 71 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 vfsaccess.c
8
9 Abstract:
10
11 This file is a vfs access permissions test.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/xattr.h>
21 #include <utime.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <sys/syscall.h>
25 #include <sys/mman.h>
26 #include <sys/prctl.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <pwd.h>
31 #include <sys/wait.h>
32 #include <limits.h>
33 #include "lxtfs.h"
34
35 #if !defined(__amd64__) && !defined(__aarch64__)
36
37 #include <sys/capability.h>
38
39 #else
40
41 #include <sys/cdefs.h>
42 #include <linux/capability.h>
43
44 #define _LINUX_CAPABILITY_VERSION_3 0x20080522
45
46 #ifndef O_PATH
47 #define O_PATH 010000000
48 #endif
49
50 #endif
51
52 #include <sys/vfs.h>
53 #include <linux/prctl.h>
54 #include <stdio.h>
55
56 #define LXT_NAME "vfsaccess"
57 #define LXT_NAME_DRVFS "vfsaccess_drvfs"
58
59 #define VFS_FILE_OBJECT_COUNT LXT_COUNT_OF(g_VfsFileObjectFlags)
60
61 #define VFS_FILE_CONTENTS "vfsaccesstestfilecontents"
62
63 #define VFS_ACCESS_UID 1012
64
65 #define VFS_ACCESS_PARENT_DIR "/data/test/vfsaccesstest"
66
67 #define VFS_ACCESS_CHMOD_DIR VFS_ACCESS_PARENT_DIR "/vfsaccessdir_chmod"
68
69 #define VFS_ACCESS_OPATH_DIR VFS_ACCESS_PARENT_DIR "/vfsaccessopathdir"
70
71 #define VFS_ACCESS_OPATH_FILE VFS_ACCESS_PARENT_DIR "/vfsaccessopath"
72
73 #define VFS_ACCESS_OPATH_FILE_LINK VFS_ACCESS_PARENT_DIR "/vfsaccessopathlink"
74
75 #define VFS_ACCESS_STICKY_BIT_DIR VFS_ACCESS_PARENT_DIR "/vfsaccessdir_stickybit"
76
77 #define VFS_ACCESS_GROUP_USER_ID_DIR VFS_ACCESS_PARENT_DIR "/vfsaccessdir_groupuserid"
78
79 #define VFS_ACCESS_UTIME_FILE VFS_ACCESS_PARENT_DIR "/vfsaccesutime"
80
81 #define VFS_ACCESS_FSUID_FILE VFS_ACCESS_PARENT_DIR "/setfsuid_testfile"
82
83 #define VFS_ACCESS_FIFO VFS_ACCESS_PARENT_DIR "/vfsaccess_fifo"
84
85 #define O_NOACCESS (O_WRONLY | O_RDWR)
86
87 #define VFS_ACCESS_EXECVE_TEST_RESULT (123)
88
89 typedef struct _VFS_ACCESS_FILE
90 {
91 char* Name;
92 mode_t Mode;
93 } VFS_ACCESS_FILE, *PVFS_ACCESS_FILE;
94
95 typedef struct _VFS_ACCESS_FILE_OBJECT
96 {
97 int Fd;
98 int Flags;
99 } VFS_ACCESS_FILE_OBJECT, *PVFS_ACCESS_FILE_OBJECT;
100
101 struct reuid_t
102 {
103 uid_t r;
104 uid_t e;
105 uid_t s;
106 };
107
108 int VfsAccessCheckResult(int ResultActual, int ResultExpected, int ErrnoActual, int ErrnoExpected, char* Message, int VariationIndex);
109
110 void VfsAccessFileObjectCleanup(void);
111
112 int VfsAccessFileObjectCreateFiles(void);
113
114 int VfsAccessFileObjectCreateSymlinks(void);
115
116 int VfsAccessFileObjectOpenFiles(VFS_ACCESS_FILE_OBJECT Files[]);
117
118 int VfsAccessFileObjectOpenSymlinks(VFS_ACCESS_FILE_OBJECT Files[]);
119
120 int VfsAccessFileObjectChecks(PLXT_ARGS Args);
121
122 int VfsAccessFileObjectSymlinksChecks(PLXT_ARGS Args);
123
124 int VfsAccessRemapReference(PLXT_ARGS Args);
125
126 int VfsAccessChmod(PLXT_ARGS Args);
127
128 int VfsAccessChmodCap(PLXT_ARGS Args);
129
130 LXT_VARIATION_HANDLER VfsAccessFifo;
131
132 int VfsAccessOPath(PLXT_ARGS Args);
133
134 int VfsAccessStickyBit(PLXT_ARGS Args);
135
136 int VfsAccessSetUserGroupId(PLXT_ARGS Args);
137
138 int VfsAccessSetUserGroupIdExecveChild(void);
139
140 int VfsAccessInodeChecks(PLXT_ARGS Args);
141
142 int VfsAccessParseArgs(int Argc, char* Argv[], LXT_ARGS* Args);
143
144 int VfsAccessUTimeCap(PLXT_ARGS Args);
145
146 int VfsAccessSetFsUid(PLXT_ARGS Args);
147
148 int VfsAccessSetUid(PLXT_ARGS Args);
149
150 //
151 // Global constants
152 //
153
154 #define VFS_ACCESS_FILE_OBJECT_FILE 0
155 #define VFS_ACCESS_REMAP_FILE 1
156
157 static const VFS_ACCESS_FILE g_VfsFiles[] = {
158 {VFS_ACCESS_PARENT_DIR "/vfsaccessfile", S_IRWXU | S_IRWXG | S_IRWXO},
159 {VFS_ACCESS_PARENT_DIR "/vfsaccessfile_remap", S_IRWXU | S_IRWXG | S_IRWXO}};
160
161 static const char* g_VfsSymlinks[] = {
162 VFS_ACCESS_PARENT_DIR "/sym_vfsaccessfile", VFS_ACCESS_PARENT_DIR "/sym_vfsaccessfile_remap"};
163
164 static const int g_VfsFileObjectFlags[] = {O_RDONLY, O_WRONLY, O_RDWR, O_NOACCESS, O_RDONLY | O_PATH, O_RDWR | O_APPEND};
165
166 static const VFS_ACCESS_FILE g_VfsInodeEntries[] = {
167 {VFS_ACCESS_PARENT_DIR "/vfsaccessfile_r", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH},
168 {VFS_ACCESS_PARENT_DIR "/vfsaccessfile_w", S_IFREG | S_IWUSR | S_IWGRP | S_IWOTH},
169 {VFS_ACCESS_PARENT_DIR "/vfsaccessfile_x", S_IFREG | S_IXUSR | S_IXGRP | S_IXOTH},
170 {VFS_ACCESS_PARENT_DIR "/vfsaccessfile_rw", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH},
171 {VFS_ACCESS_PARENT_DIR "/vfsaccessdir_r", S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH},
172 {VFS_ACCESS_PARENT_DIR "/vfsaccessdir_w", S_IFDIR | S_IWUSR | S_IWGRP | S_IWOTH},
173 {VFS_ACCESS_PARENT_DIR "/vfsaccessdir_x", S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH},
174 {VFS_ACCESS_PARENT_DIR "/vfsaccessdir_wx", S_IFDIR | S_IWUSR | S_IWGRP | S_IWOTH | S_IXUSR | S_IXGRP | S_IXOTH}};
175
176 #define VFS_ACCESS_INODE_ENTRY_FILE "vfsaccessfile"
177
178 int g_VfsSetFsUidCaps[] = {
179 CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, CAP_LINUX_IMMUTABLE, CAP_MAC_OVERRIDE, CAP_MKNOD};
180
181 static const LXT_VARIATION g_LxtVariations[] = {
182 {"VfsAccess file object checks", VfsAccessFileObjectChecks},
183 {"VfsAccess symlinks checks", VfsAccessFileObjectSymlinksChecks},
184 {"VfsAccess remap reference", VfsAccessRemapReference},
185 {"VfsAccess chmod", VfsAccessChmod},
186 {"VfsAccess chmod cap", VfsAccessChmodCap},
187 {"VfsAccess O_PATH", VfsAccessOPath},
188 {"VfsAccess sticky bit", VfsAccessStickyBit},
189 {"VfsAccess set-user-ID set-group-ID", VfsAccessSetUserGroupId},
190 {"VfsAccess inode checks", VfsAccessInodeChecks},
191 {"VfsAccess utime cap", VfsAccessUTimeCap},
192 {"VfsAccess setfsuid", VfsAccessSetFsUid},
193 //{"VfsAccess Fifo", VfsAccessFifo},
194 {"VfsAccess set*uid", VfsAccessSetUid}};
195
196 bool g_UseDrvFs = false;
197
198 int VfsAccessTestEntry(int Argc, char* Argv[])
199
200 /*++
201 --*/
202
203 {
204
205 LXT_ARGS Args;
206 int Result;
207
208 if ((Argc == 2) && (strcmp(Argv[1], "execvetest") == 0))
209 {
210 return VFS_ACCESS_EXECVE_TEST_RESULT;
211 }
212
213 LxtCheckResult(VfsAccessParseArgs(Argc, Argv, &Args));
214
215 ErrorExit:
216 LxtUninitialize();
217 return !LXT_SUCCESS(Result);
218 }
219
220 void VfsAccessFileObjectCleanup(void)
221
222 /*++
223
224 Description:
225
226 This routine cleans up test files.
227
228 Arguments:
229
230 None.
231
232 Return Value:
233
234 None.
235
236 --*/
237
238 {
239
240 int Index;
241
242 for (Index = 0; Index < LXT_COUNT_OF(g_VfsSymlinks); Index += 1)
243 {
244 unlink(g_VfsSymlinks[Index]);
245 }
246
247 for (Index = 0; Index < LXT_COUNT_OF(g_VfsFiles); ++Index)
248 {
249 unlink(g_VfsFiles[Index].Name);
250 }
251
252 for (Index = 0; Index < LXT_COUNT_OF(g_VfsInodeEntries); ++Index)
253 {
254 if (S_ISREG(g_VfsInodeEntries[Index].Mode))
255 {
256 unlink(g_VfsInodeEntries[Index].Name);
257 }
258 else
259 {
260 rmdir(g_VfsInodeEntries[Index].Name);
261 }
262 }
263
264 return;
265 }
266
267 int VfsAccessFileObjectCreateFiles(void)
268
269 /*++
270 --*/
271
272 {
273
274 unsigned int BytesWritten;
275 unsigned int Index;
276 int Fd;
277 int Result;
278
279 Fd = -1;
280 for (Index = 0; Index < LXT_COUNT_OF(g_VfsFiles); ++Index)
281 {
282 unlink(g_VfsFiles[Index].Name);
283 LxtCheckErrno(Fd = open(g_VfsFiles[Index].Name, O_RDWR | O_CREAT, g_VfsFiles[Index].Mode));
284 LxtCheckErrno(write(Fd, VFS_FILE_CONTENTS, sizeof(VFS_FILE_CONTENTS)));
285 if (Index == VFS_ACCESS_REMAP_FILE)
286 {
287 BytesWritten = sizeof(VFS_FILE_CONTENTS);
288 while (BytesWritten < 2 * PAGE_SIZE)
289 {
290 LxtCheckErrno(write(Fd, VFS_FILE_CONTENTS, sizeof(VFS_FILE_CONTENTS)));
291 BytesWritten += sizeof(VFS_FILE_CONTENTS);
292 }
293 }
294
295 LxtClose(Fd);
296 Fd = -1;
297 }
298
299 for (Index = 0; Index < LXT_COUNT_OF(g_VfsInodeEntries); ++Index)
300 {
301 if (S_ISREG(g_VfsInodeEntries[Index].Mode))
302 {
303 unlink(g_VfsInodeEntries[Index].Name);
304 LxtCheckErrno(Fd = open(g_VfsInodeEntries[Index].Name, O_RDWR | O_CREAT, g_VfsInodeEntries[Index].Mode));
305
306 LxtCheckErrno(write(Fd, VFS_FILE_CONTENTS, sizeof(VFS_FILE_CONTENTS)));
307 LxtClose(Fd);
308 Fd = -1;
309 }
310 else
311 {
312 rmdir(g_VfsInodeEntries[Index].Name);
313 LxtCheckErrno(mkdir(g_VfsInodeEntries[Index].Name, g_VfsInodeEntries[Index].Mode));
314 }
315 }
316
317 Result = LXT_RESULT_SUCCESS;
318
319 ErrorExit:
320 if (Fd != -1)
321 {
322 LxtClose(Fd);
323 }
324
325 return Result;
326 }
327
328 int VfsAccessFileObjectCreateSymlinks(void)
329
330 /*++
331 --*/
332
333 {
334
335 unsigned int Index;
336 int IntermediateResult;
337 int Result;
338
339 LxtCheckEqual(LXT_COUNT_OF(g_VfsFiles), LXT_COUNT_OF(g_VfsSymlinks), "%d");
340
341 //
342 // Create symlinks for the files.
343 //
344
345 for (Index = 0; Index < LXT_COUNT_OF(g_VfsFiles); Index += 1)
346 {
347 IntermediateResult = symlink(g_VfsFiles[Index].Name, g_VfsSymlinks[Index]);
348
349 //
350 // The symlink call may fail if the symlink already exists. This is ok
351 // in order to run the unit test on the same machine multiple times.
352 //
353
354 if (IntermediateResult < 0)
355 {
356 LxtCheckErrnoFailure(IntermediateResult, EEXIST);
357 }
358 }
359
360 Result = LXT_RESULT_SUCCESS;
361
362 ErrorExit:
363 return Result;
364 }
365
366 int VfsAccessCheckResult(int ResultActual, int ResultExpected, int ErrnoActual, int ErrnoExpected, char* Message, int VariationIndex)
367
368 /*++
369 --*/
370
371 {
372
373 int Result;
374
375 Result = LXT_RESULT_FAILURE;
376 if (ResultActual != ResultExpected)
377 {
378 if (ResultActual >= 0)
379 {
380 ErrnoActual = 0;
381 }
382
383 LxtLogError("Unexpected %s (%d) result actual %d (%s) != expected %d", Message, VariationIndex, ResultActual, strerror(ErrnoActual), ResultExpected);
384
385 goto ErrorExit;
386 }
387
388 if ((ResultActual == -1) && (ErrnoActual != ErrnoExpected))
389 {
390 Result = LXT_RESULT_FAILURE;
391 LxtLogError("Unexpected %s (%d) errno actual %s != expected %s", Message, VariationIndex, strerror(ErrnoActual), strerror(ErrnoExpected));
392
393 goto ErrorExit;
394 }
395
396 Result = LXT_RESULT_SUCCESS;
397
398 ErrorExit:
399 return Result;
400 }
401
402 int VfsAccessFifo(PLXT_ARGS Args)
403
404 /*++
405
406 Description:
407
408 This routine tests access permissions on fifos.
409
410 Arguments:
411
412 Args - Supplies the command line arguments.
413
414 Return Value:
415
416 Returns 0 on success, -1 on failure.
417
418 --*/
419
420 {
421
422 int ChildPid;
423 int Result;
424
425 LxtCheckErrnoZeroSuccess(mkfifo(VFS_ACCESS_FIFO, 0600));
426 LxtCheckErrno(ChildPid = fork());
427 if (ChildPid == 0)
428 {
429 setgid(1000);
430 setuid(1000);
431 LxtCheckErrnoFailure(open(VFS_ACCESS_FIFO, O_RDONLY | O_NONBLOCK), EACCES);
432
433 LxtCheckErrnoFailure(open(VFS_ACCESS_FIFO, O_WRONLY | O_NONBLOCK), EACCES);
434
435 exit(0);
436 }
437
438 LxtWaitPidPoll(ChildPid, 0);
439
440 ErrorExit:
441 unlink(VFS_ACCESS_FIFO);
442 return Result;
443 }
444
445 int VfsAccessFileObjectChecks(PLXT_ARGS Args)
446
447 /*++
448 --*/
449
450 {
451
452 int AccessMode;
453 char Buffer;
454 int ErrnoExpected;
455 VFS_ACCESS_FILE_OBJECT Files[VFS_FILE_OBJECT_COUNT];
456 unsigned int Index;
457 void* Map;
458 int Result;
459 int ResultActual;
460 int ResultExpected;
461
462 LxtLogInfo("Fs type %d with dax = %d\n", g_LxtFsInfo.FsType, g_LxtFsInfo.Flags.Dax);
463 memset(Files, -1, sizeof(Files));
464 LxtCheckResult(VfsAccessFileObjectOpenFiles(Files));
465 for (Index = 0; Index < VFS_FILE_OBJECT_COUNT; ++Index)
466 {
467
468 //
469 // Validate read with a valid buffer.
470 //
471
472 ResultExpected = -1;
473 if ((Files[Index].Flags == O_RDONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
474 {
475
476 ResultExpected = 1;
477 }
478
479 ResultActual = LxtRead(Files[Index].Fd, &Buffer, 1);
480 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EBADF, "read", Index));
481
482 //
483 // Validate read with a invalid buffer and a size of 0. The size of 0
484 // should cause the buffer to not be checked.
485 //
486
487 ResultExpected = -1;
488 if ((Files[Index].Flags == O_RDONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
489 {
490
491 ResultExpected = 0;
492 }
493
494 ResultActual = LxtRead(Files[Index].Fd, (void*)0x1, 0);
495 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EBADF, "read", Index));
496
497 //
498 // Validate write with a valid buffer.
499 //
500
501 ResultExpected = -1;
502 if ((Files[Index].Flags == O_WRONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
503 {
504
505 ResultExpected = 1;
506 }
507
508 ResultActual = LxtWrite(Files[Index].Fd, &Buffer, 1);
509 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EBADF, "write", Index));
510
511 //
512 // Validate write with a invalid buffer and a size of 0. The size of 0
513 // should cause the buffer to not be checked.
514 //
515
516 ResultExpected = -1;
517 if ((Files[Index].Flags == O_WRONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
518 {
519
520 ResultExpected = 0;
521 }
522
523 ResultActual = LxtWrite(Files[Index].Fd, (void*)0x1, 0);
524 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EBADF, "write", Index));
525
526 //
527 // Validate map read shared and upgrading to write access.
528 //
529 // N.B. The Linux 9p client does not allow mapping shared if the file is
530 // opened for write.
531 //
532
533 ErrnoExpected = EACCES;
534 if (Files[Index].Flags == O_PATH)
535 {
536 ErrnoExpected = EBADF;
537 }
538
539 ResultExpected = -1;
540 if ((((Files[Index].Flags & O_ACCMODE) == O_RDONLY) || ((Files[Index].Flags & O_ACCMODE) == O_RDWR)) &&
541 ((Files[Index].Flags & O_PATH) == 0))
542 {
543
544 ResultExpected = 1;
545 }
546
547 Map = mmap(NULL, sizeof(Buffer), PROT_READ, MAP_SHARED, Files[Index].Fd, 0);
548 ResultActual = -1;
549 if (Map != MAP_FAILED)
550 {
551 ResultActual = 1;
552 }
553
554 LxtLogInfo("%d, %d, %d", Index, Files[Index].Flags, ResultExpected);
555 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap read shared", Index));
556
557 if (Map != MAP_FAILED)
558 {
559 ResultExpected = -1;
560 if ((Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
561 {
562
563 ResultExpected = 0;
564 }
565
566 ResultActual = mprotect(Map, sizeof(Buffer), PROT_WRITE);
567 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap read shared mprotect", Index));
568
569 LxtCheckErrno(LxtMunmap(Map, sizeof(Buffer)));
570 }
571
572 //
573 // Validate map read private and upgrading to write access.
574 //
575 // N.B. The Linux 9p client does not allow mapping shared if the file is
576 // opened for write.
577 //
578
579 ResultExpected = -1;
580 if ((Files[Index].Flags == O_RDONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
581 {
582
583 ResultExpected = 1;
584 }
585
586 Map = mmap(NULL, sizeof(Buffer), PROT_READ, MAP_PRIVATE, Files[Index].Fd, 0);
587 ResultActual = -1;
588 if (Map != MAP_FAILED)
589 {
590 ResultActual = 1;
591 }
592
593 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap read private", Index));
594
595 if (Map != MAP_FAILED)
596 {
597 ResultExpected = -1;
598 if ((Files[Index].Flags == O_RDONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
599 {
600
601 ResultExpected = 0;
602 }
603
604 ResultActual = mprotect(Map, sizeof(Buffer), PROT_WRITE);
605 VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap read private mprotect", Index);
606
607 LxtCheckErrno(LxtMunmap(Map, sizeof(Buffer)));
608 }
609
610 //
611 // Validate map write shared and private
612 //
613
614 ErrnoExpected = EACCES;
615 if (Files[Index].Flags == O_PATH)
616 {
617 ErrnoExpected = EBADF;
618 }
619
620 ResultExpected = -1;
621 if ((Files[Index].Flags & O_ACCMODE) == O_RDWR)
622 {
623 ResultExpected = 1;
624 }
625
626 Map = mmap(NULL, sizeof(Buffer), PROT_WRITE, MAP_SHARED, Files[Index].Fd, 0);
627 ResultActual = -1;
628 if (Map != MAP_FAILED)
629 {
630 ResultActual = 1;
631 LxtCheckErrno(LxtMunmap(Map, sizeof(Buffer)));
632 }
633
634 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap write shared", Index));
635
636 ResultExpected = -1;
637 if ((Files[Index].Flags == O_RDONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
638 {
639
640 ResultExpected = 1;
641 }
642
643 Map = mmap(NULL, sizeof(Buffer), PROT_WRITE, MAP_PRIVATE, Files[Index].Fd, 0);
644 ResultActual = -1;
645 if (Map != MAP_FAILED)
646 {
647 ResultActual = 1;
648 LxtCheckErrno(LxtMunmap(Map, sizeof(Buffer)));
649 }
650
651 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap write private", Index));
652
653 LxtClose(Files[Index].Fd);
654 Files[Index].Fd = -1;
655 }
656
657 Result = LXT_RESULT_SUCCESS;
658
659 ErrorExit:
660 return Result;
661 }
662
663 int VfsAccessFileObjectSymlinksChecks(PLXT_ARGS Args)
664
665 /*++
666 --*/
667
668 {
669
670 char Buffer;
671 int ErrnoExpected;
672 VFS_ACCESS_FILE_OBJECT Files[VFS_FILE_OBJECT_COUNT];
673 unsigned int Index;
674 void* Map;
675 int Result;
676 int ResultActual;
677 int ResultExpected;
678
679 LxtLogInfo("Fs type %d with dax = %d\n", g_LxtFsInfo.FsType, g_LxtFsInfo.Flags.Dax);
680
681 memset(Files, -1, sizeof(Files));
682 LxtCheckResult(VfsAccessFileObjectOpenSymlinks(Files));
683 for (Index = 0; Index < VFS_FILE_OBJECT_COUNT; ++Index)
684 {
685
686 //
687 // Validate read
688 //
689
690 ResultExpected = -1;
691 if ((Files[Index].Flags == O_RDONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
692 {
693
694 ResultExpected = 1;
695 }
696
697 ResultActual = LxtRead(Files[Index].Fd, &Buffer, 1);
698 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EBADF, "read", Index));
699
700 //
701 // Validate write
702 //
703
704 ResultExpected = -1;
705 if ((Files[Index].Flags == O_WRONLY) || (Files[Index].Flags == O_RDWR) || (Files[Index].Flags == (O_RDWR | O_APPEND)))
706 {
707
708 ResultExpected = 1;
709 }
710
711 ResultActual = LxtWrite(Files[Index].Fd, &Buffer, 1);
712 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EBADF, "write", Index));
713
714 //
715 // Validate map read
716 //
717
718 ErrnoExpected = EACCES;
719 if (Files[Index].Flags == O_PATH)
720 {
721 ErrnoExpected = EBADF;
722 }
723
724 ResultExpected = -1;
725 if ((((Files[Index].Flags & O_ACCMODE) == O_RDONLY) || ((Files[Index].Flags & O_ACCMODE) == O_RDWR)) &&
726 ((Files[Index].Flags & O_PATH) == 0))
727 {
728
729 ResultExpected = 1;
730 }
731
732 Map = mmap(NULL, sizeof(Buffer), PROT_READ, MAP_SHARED, Files[Index].Fd, 0);
733 ResultActual = -1;
734 if (Map != MAP_FAILED)
735 {
736 ResultActual = 1;
737 LxtCheckErrno(LxtMunmap(Map, sizeof(Buffer)));
738 }
739
740 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap read", Index));
741
742 //
743 // Validate map write
744 //
745
746 ErrnoExpected = EACCES;
747 if (Files[Index].Flags == O_PATH)
748 {
749 ErrnoExpected = EBADF;
750 }
751
752 ResultExpected = -1;
753 if ((Files[Index].Flags & O_ACCMODE) == O_RDWR)
754 {
755 ResultExpected = 1;
756 }
757
758 Map = mmap(NULL, sizeof(Buffer), PROT_WRITE, MAP_SHARED, Files[Index].Fd, 0);
759 ResultActual = -1;
760 if (Map != MAP_FAILED)
761 {
762 ResultActual = 1;
763 LxtCheckErrno(LxtMunmap(Map, sizeof(Buffer)));
764 }
765
766 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "mmap write", Index));
767
768 LxtClose(Files[Index].Fd);
769 Files[Index].Fd = -1;
770 }
771
772 Result = LXT_RESULT_SUCCESS;
773
774 ErrorExit:
775 return Result;
776 }
777
778 int VfsAccessFileObjectOpenFiles(VFS_ACCESS_FILE_OBJECT Files[])
779
780 /*++
781 --*/
782
783 {
784
785 unsigned int Index;
786 int Result;
787
788 for (Index = 0; Index < VFS_FILE_OBJECT_COUNT; ++Index)
789 {
790 Files[Index].Flags = g_VfsFileObjectFlags[Index];
791 LxtCheckErrno(Files[Index].Fd = open(g_VfsFiles[VFS_ACCESS_FILE_OBJECT_FILE].Name, Files[Index].Flags, 0));
792 }
793
794 Result = LXT_RESULT_SUCCESS;
795
796 ErrorExit:
797 return Result;
798 }
799
800 int VfsAccessFileObjectOpenSymlinks(VFS_ACCESS_FILE_OBJECT Files[])
801
802 /*++
803 --*/
804
805 {
806
807 unsigned int Index;
808 int Result;
809
810 for (Index = 0; Index < VFS_FILE_OBJECT_COUNT; Index += 1)
811 {
812 Files[Index].Flags = g_VfsFileObjectFlags[Index];
813 LxtCheckErrno(Files[Index].Fd = open(g_VfsSymlinks[VFS_ACCESS_FILE_OBJECT_FILE], Files[Index].Flags, 0));
814 }
815
816 Result = LXT_RESULT_SUCCESS;
817
818 ErrorExit:
819 return Result;
820 }
821
822 int VfsAccessRemapReference(PLXT_ARGS Args)
823
824 {
825
826 char Buffer;
827 int FdReadOnly = -1;
828 int FdReadWrite = -1;
829 void* MapResult;
830 void* MapReadOnly = NULL;
831 void* MapReadWrite = NULL;
832 void* RemappedMemory = NULL;
833 int Result;
834
835 //
836 // Open and map a file whose only reference is read only and open second
837 // file descriptor and mapping read write.
838 //
839
840 LxtCheckErrno(FdReadOnly = open(g_VfsFiles[VFS_ACCESS_REMAP_FILE].Name, O_RDONLY, 0));
841 LxtCheckMapErrno(MapReadOnly = mmap(NULL, sizeof(Buffer), PROT_READ, MAP_SHARED, FdReadOnly, 0));
842 LxtCheckErrno(FdReadWrite = open(g_VfsFiles[VFS_ACCESS_REMAP_FILE].Name, O_RDWR, 0));
843 LxtCheckMapErrno(MapReadWrite = mmap(NULL, sizeof(Buffer), PROT_READ | PROT_WRITE, MAP_SHARED, FdReadWrite, 0));
844 LxtCheckMapErrno(RemappedMemory = mremap(MapReadWrite, sizeof(Buffer), PAGE_SIZE * 2, MREMAP_MAYMOVE));
845
846 ErrorExit:
847 if (FdReadOnly != -1)
848 {
849 if (MapReadOnly != NULL)
850 {
851 LxtMunmap(MapReadOnly, sizeof(Buffer));
852 }
853
854 LxtClose(FdReadOnly);
855 }
856
857 if (FdReadWrite != -1)
858 {
859 if (RemappedMemory != NULL)
860 {
861 LxtMunmap(RemappedMemory, PAGE_SIZE * 2);
862 }
863 else if (MapReadWrite != NULL)
864 {
865 LxtMunmap(MapReadWrite, sizeof(Buffer));
866 }
867
868 LxtClose(FdReadWrite);
869 }
870
871 return Result;
872 }
873
874 int VfsAccessChmod(PLXT_ARGS Args)
875
876 /*++
877 --*/
878
879 {
880
881 int DirFd;
882 int Result;
883 struct stat StatBuf;
884
885 DirFd = -1;
886
887 //
888 // Set bits with chmod and then fchmod.
889 //
890
891 rmdir(VFS_ACCESS_CHMOD_DIR);
892 LxtCheckErrno(mkdir(VFS_ACCESS_CHMOD_DIR, S_IRWXU));
893 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
894 if (StatBuf.st_mode != (S_IRWXU | S_IFDIR))
895 {
896 LxtLogError("Unexpected mode %d != S_IRWXU | S_IFDIR", StatBuf.st_mode);
897 goto ErrorExit;
898 }
899
900 LxtCheckErrno(chmod(VFS_ACCESS_CHMOD_DIR, S_IRWXG));
901 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
902 if (StatBuf.st_mode != (S_IRWXG | S_IFDIR))
903 {
904 LxtLogError("Unexpected mode %d != S_IRWXG | S_IFDIR", StatBuf.st_mode);
905 goto ErrorExit;
906 }
907
908 LxtCheckErrno(chmod(VFS_ACCESS_CHMOD_DIR, S_IRWXO));
909 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
910 if (StatBuf.st_mode != (S_IRWXO | S_IFDIR))
911 {
912 LxtLogError("Unexpected mode %d != S_IRWXO | S_IFDIR", StatBuf.st_mode);
913 goto ErrorExit;
914 }
915
916 LxtCheckErrno(chmod(VFS_ACCESS_CHMOD_DIR, S_IRWXU));
917 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
918 if (StatBuf.st_mode != (S_IRWXU | S_IFDIR))
919 {
920 LxtLogError("Unexpected mode %d != S_IRWXU | S_IFDIR", StatBuf.st_mode);
921 goto ErrorExit;
922 }
923
924 LxtCheckErrno(chmod(VFS_ACCESS_CHMOD_DIR, 0xffff));
925 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
926 if (StatBuf.st_mode != (S_ISVTX | S_ISGID | S_ISUID | S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR))
927 {
928 LxtLogError("Unexpected mode %d != All bits", StatBuf.st_mode);
929 goto ErrorExit;
930 }
931
932 LxtCheckErrno(DirFd = open(VFS_ACCESS_CHMOD_DIR, O_DIRECTORY | O_RDONLY, 0));
933 LxtCheckErrno(fchmod(DirFd, S_IRWXG));
934 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
935 if (StatBuf.st_mode != (S_IRWXG | S_IFDIR))
936 {
937 LxtLogError("Unexpected mode %d != S_IRWXG | S_IFDIR", StatBuf.st_mode);
938 goto ErrorExit;
939 }
940
941 LxtCheckErrno(fchmod(DirFd, S_IRWXO));
942 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
943 if (StatBuf.st_mode != (S_IRWXO | S_IFDIR))
944 {
945 LxtLogError("Unexpected mode %d != S_IRWXO | S_IFDIR", StatBuf.st_mode);
946 goto ErrorExit;
947 }
948
949 LxtCheckErrno(fchmod(DirFd, S_IRWXU));
950 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
951 if (StatBuf.st_mode != (S_IRWXU | S_IFDIR))
952 {
953 LxtLogError("Unexpected mode %d != S_IRWXU | S_IFDIR", StatBuf.st_mode);
954 goto ErrorExit;
955 }
956
957 LxtCheckErrno(fchmod(DirFd, 0xffff));
958 LxtCheckErrno(stat(VFS_ACCESS_CHMOD_DIR, &StatBuf));
959 if (StatBuf.st_mode != (S_ISVTX | S_ISGID | S_ISUID | S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR))
960 {
961 LxtLogError("Unexpected mode %d != All bits", StatBuf.st_mode);
962 goto ErrorExit;
963 }
964
965 Result = LXT_RESULT_SUCCESS;
966
967 ErrorExit:
968 if (DirFd != -1)
969 {
970 LxtClose(DirFd);
971 }
972
973 rmdir(VFS_ACCESS_CHMOD_DIR);
974 return Result;
975 }
976
977 void VfsAccessChmodCapChild(void)
978
979 /*++
980 --*/
981
982 {
983
984 struct __user_cap_data_struct CapData[2];
985 struct __user_cap_header_struct CapHeader;
986 int Result;
987
988 memset(&CapData, 0, sizeof(CapData));
989 memset(&CapHeader, 0, sizeof(CapHeader));
990 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
991 CapData[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
992 CapData[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
993 CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
994 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
995 CapData[0].effective = CapData[0].permitted;
996 CapData[1].effective = CapData[1].permitted;
997
998 //
999 // Drop privileges so the current process does not have CAP_FOWNER.
1000 //
1001
1002 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1003 LxtCheckErrno(setgid(VFS_ACCESS_UID));
1004 LxtCheckErrno(setuid(VFS_ACCESS_UID));
1005 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1006
1007 //
1008 // TODO: Update the below when checks are enforced
1009 //
1010
1011 //
1012 // Try to chmod the directory to the current value.
1013 //
1014
1015 LxtCheckErrnoFailure(chmod(VFS_ACCESS_CHMOD_DIR, S_IRWXU), EPERM);
1016
1017 //
1018 // Try to chmod on the directory without CAP_FOWNER to 0751.
1019 //
1020
1021 LxtCheckErrnoFailure(chmod(VFS_ACCESS_CHMOD_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH), EPERM);
1022 Result = LXT_RESULT_SUCCESS;
1023
1024 ErrorExit:
1025 _exit(Result);
1026 }
1027
1028 int VfsAccessChmodCap(PLXT_ARGS Args)
1029
1030 /*++
1031 --*/
1032
1033 {
1034
1035 int ChildPid;
1036 int Result;
1037
1038 rmdir(VFS_ACCESS_CHMOD_DIR);
1039 LxtCheckErrno(mkdir(VFS_ACCESS_CHMOD_DIR, S_IRWXU));
1040 ChildPid = fork();
1041 if (ChildPid == 0)
1042 {
1043 VfsAccessChmodCapChild();
1044 }
1045
1046 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1047 Result = LXT_RESULT_SUCCESS;
1048
1049 ErrorExit:
1050 rmdir(VFS_ACCESS_CHMOD_DIR);
1051 return Result;
1052 }
1053
1054 void VfsAccessOPathChild(void)
1055
1056 /*++
1057 --*/
1058
1059 {
1060
1061 char Buffer[100];
1062 struct __user_cap_data_struct CapData[2];
1063 struct __user_cap_header_struct CapHeader;
1064 int Fd;
1065 int Result;
1066 struct stat StatBuffer;
1067 struct statfs StatFsBuffer;
1068 struct timespec Times[2] = {{0, UTIME_NOW}, {0, UTIME_NOW}};
1069
1070 memset(&CapData, 0, sizeof(CapData));
1071 memset(&CapHeader, 0, sizeof(CapHeader));
1072 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1073 CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
1074 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
1075 CapData[0].effective = CapData[0].permitted;
1076 CapData[1].effective = CapData[1].permitted;
1077 Fd = -1;
1078
1079 //
1080 // Drop privileges so the current process does not have VFS related
1081 // capabilities.
1082 //
1083
1084 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1085 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1086
1087 //
1088 // Open the file with O_PATH and check the behavior for the syscalls of
1089 // interest.
1090 //
1091
1092 LxtCheckErrno(Fd = open(VFS_ACCESS_OPATH_FILE, O_PATH, 0));
1093
1094 //
1095 // Check syscalls that take a file descriptor should fail because O_PATH was
1096 // specified.
1097 //
1098
1099 LxtCheckErrnoFailure(fchmod(Fd, 0), EBADF);
1100 LxtCheckErrnoFailure(fchown(Fd, 0, 0), EBADF);
1101 LxtCheckErrnoFailure(fsync(Fd), EBADF);
1102 LxtCheckErrnoFailure(LxtGetdents64(Fd, (struct dirent*)Buffer, sizeof(Buffer)), EBADF);
1103 LxtCheckErrnoFailure(futimens(Fd, Times), EBADF);
1104 LxtCheckErrnoFailure(flistxattr(Fd, Buffer, sizeof(Buffer)), EBADF);
1105
1106 //
1107 // Check syscalls that take a file descriptor should succeed even through
1108 // O_PATH was specified.
1109 //
1110
1111 LxtCheckErrno(fstat(Fd, &StatBuffer));
1112 LxtCheckErrno(fstatfs(Fd, &StatFsBuffer));
1113
1114 //
1115 // Check syscalls that should succeed on a directory with O_PATH specified.
1116 //
1117
1118 LxtCheckErrnoZeroSuccess(close(Fd));
1119 LxtCheckErrno(Fd = open(VFS_ACCESS_OPATH_DIR, O_PATH | O_DIRECTORY));
1120 LxtCheckErrnoZeroSuccess(fchdir(Fd));
1121
1122 //
1123 // Chdir should still fail if execute permissions are removed.
1124 //
1125
1126 LxtCheckErrnoZeroSuccess(chmod(VFS_ACCESS_OPATH_DIR, 0));
1127 LxtCheckErrnoFailure(fchdir(Fd), EACCES);
1128
1129 //
1130 // Check syscalls that take a path should succeed because they do not
1131 // require access to the file, but instead just the path.
1132 //
1133
1134 LxtCheckErrno(chmod(VFS_ACCESS_OPATH_FILE, 0));
1135 LxtCheckErrno(chown(VFS_ACCESS_OPATH_FILE, 0, 0));
1136 LxtCheckErrno(stat(VFS_ACCESS_OPATH_FILE, &StatBuffer));
1137 LxtCheckErrno(statfs(VFS_ACCESS_OPATH_FILE, &StatFsBuffer));
1138 LxtCheckErrno(readlink(VFS_ACCESS_OPATH_FILE_LINK, Buffer, sizeof(Buffer)));
1139
1140 //
1141 // Xattr is not supported on drvfs currently.
1142 //
1143
1144 if (g_UseDrvFs == false)
1145 {
1146 LxtCheckErrno(listxattr(VFS_ACCESS_OPATH_FILE_LINK, Buffer, sizeof(Buffer)));
1147 LxtCheckErrno(llistxattr(VFS_ACCESS_OPATH_FILE_LINK, Buffer, sizeof(Buffer)));
1148 }
1149
1150 Result = LXT_RESULT_SUCCESS;
1151
1152 ErrorExit:
1153 if (Fd != -1)
1154 {
1155 LxtClose(Fd);
1156 }
1157
1158 _exit(Result);
1159 }
1160
1161 int VfsAccessOPath(PLXT_ARGS Args)
1162
1163 /*++
1164 --*/
1165
1166 {
1167
1168 int ChildPid;
1169 int Fd;
1170 int Result;
1171
1172 unlink(VFS_ACCESS_OPATH_FILE);
1173 unlink(VFS_ACCESS_OPATH_FILE_LINK);
1174 LxtCheckErrno(mkdir(VFS_ACCESS_OPATH_DIR, 0111));
1175 LxtCheckErrno(Fd = open(VFS_ACCESS_OPATH_FILE, O_CREAT, 0));
1176 LxtCheckErrno(symlink(VFS_ACCESS_OPATH_FILE, VFS_ACCESS_OPATH_FILE_LINK));
1177 ChildPid = fork();
1178 if (ChildPid == 0)
1179 {
1180 VfsAccessOPathChild();
1181 }
1182
1183 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1184 Result = LXT_RESULT_SUCCESS;
1185
1186 ErrorExit:
1187 if (Fd != -1)
1188 {
1189 LxtClose(Fd);
1190 }
1191
1192 unlink(VFS_ACCESS_OPATH_FILE);
1193 unlink(VFS_ACCESS_OPATH_FILE_LINK);
1194 rmdir(VFS_ACCESS_OPATH_DIR);
1195 return Result;
1196 }
1197
1198 void VfsAccessRenameCapChild(void)
1199
1200 /*++
1201 --*/
1202
1203 {
1204
1205 struct __user_cap_data_struct CapData[2];
1206 struct __user_cap_header_struct CapHeader;
1207 int File;
1208 int Result;
1209
1210 memset(&CapData, 0, sizeof(CapData));
1211 memset(&CapHeader, 0, sizeof(CapHeader));
1212 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1213 CapData[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
1214 CapData[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
1215 CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
1216 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
1217 CapData[0].effective = CapData[0].permitted;
1218 CapData[1].effective = CapData[1].permitted;
1219
1220 //
1221 // Drop privileges so the current process does not have CAP_FOWNER.
1222 //
1223
1224 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1225 LxtCheckErrno(setgid(VFS_ACCESS_UID));
1226 LxtCheckErrno(setuid(VFS_ACCESS_UID));
1227 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1228
1229 //
1230 // Create a file and directory for the current user.
1231 //
1232
1233 LxtCheckErrno(mkdir(VFS_ACCESS_STICKY_BIT_DIR "/userdir1", S_IRWXU));
1234 LxtCheckErrno(File = creat(VFS_ACCESS_STICKY_BIT_DIR "/userfile1", S_IRWXU));
1235 close(File);
1236
1237 //
1238 // Try to rename the file and directory to an existing entry without
1239 // CAP_FOWNER.
1240 //
1241
1242 LxtCheckErrnoFailure(rename(VFS_ACCESS_STICKY_BIT_DIR "/userfile1", VFS_ACCESS_STICKY_BIT_DIR "/file1"), EPERM);
1243
1244 LxtCheckErrnoFailure(rename(VFS_ACCESS_STICKY_BIT_DIR "/userdir1", VFS_ACCESS_STICKY_BIT_DIR "/dir1"), EPERM);
1245
1246 Result = LXT_RESULT_SUCCESS;
1247
1248 ErrorExit:
1249
1250 rmdir(VFS_ACCESS_STICKY_BIT_DIR "/userdir1");
1251 remove(VFS_ACCESS_STICKY_BIT_DIR "/userfile1");
1252 _exit(Result);
1253 }
1254
1255 void VfsAccessRmdirCapChild(void)
1256
1257 /*++
1258 --*/
1259
1260 {
1261
1262 struct __user_cap_data_struct CapData[2];
1263 struct __user_cap_header_struct CapHeader;
1264 int Result;
1265
1266 memset(&CapData, 0, sizeof(CapData));
1267 memset(&CapHeader, 0, sizeof(CapHeader));
1268 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1269 CapData[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
1270 CapData[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
1271 CapData[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
1272 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
1273 CapData[0].effective = CapData[0].permitted;
1274 CapData[1].effective = CapData[1].permitted;
1275
1276 //
1277 // Drop privileges so the current process does not have CAP_FOWNER.
1278 //
1279
1280 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1281 LxtCheckErrno(setgid(VFS_ACCESS_UID));
1282 LxtCheckErrno(setuid(VFS_ACCESS_UID));
1283 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1284
1285 //
1286 // Try to remove the file and directory without CAP_FOWNER.
1287 //
1288
1289 LxtCheckErrnoFailure(remove(VFS_ACCESS_STICKY_BIT_DIR "/file1"), EPERM);
1290 LxtCheckErrnoFailure(remove(VFS_ACCESS_STICKY_BIT_DIR "/dir1"), EPERM);
1291
1292 Result = LXT_RESULT_SUCCESS;
1293
1294 ErrorExit:
1295 _exit(Result);
1296 }
1297
1298 int VfsAccessStickyBit(PLXT_ARGS Args)
1299
1300 /*++
1301 --*/
1302
1303 {
1304
1305 int ChildPid;
1306 int ChildStatus;
1307 int File = 0;
1308 int Result;
1309
1310 //
1311 // Create a directory with the sticky bit set and a file inside.
1312 //
1313
1314 LxtCheckErrno(mkdir(VFS_ACCESS_STICKY_BIT_DIR, S_IRWXU | S_ISVTX));
1315 LxtCheckErrno(mkdir(VFS_ACCESS_STICKY_BIT_DIR "/dir1", S_IRWXU));
1316 LxtCheckErrno(File = creat(VFS_ACCESS_STICKY_BIT_DIR "/file1", S_IRWXU));
1317 ChildPid = fork();
1318 if (ChildPid == 0)
1319 {
1320 VfsAccessRmdirCapChild();
1321 }
1322
1323 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1324 ChildPid = fork();
1325 if (ChildPid == 0)
1326 {
1327 VfsAccessRenameCapChild();
1328 }
1329
1330 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1331 Result = LXT_RESULT_SUCCESS;
1332
1333 ErrorExit:
1334 if (File > 0)
1335 {
1336 close(File);
1337 }
1338
1339 rmdir(VFS_ACCESS_STICKY_BIT_DIR "/dir1");
1340 remove(VFS_ACCESS_STICKY_BIT_DIR "/file1");
1341 rmdir(VFS_ACCESS_STICKY_BIT_DIR);
1342 return Result;
1343 }
1344
1345 int VfsAccessSetUserGroupIdExecveChild(void)
1346
1347 /*++
1348
1349 Routine Description:
1350
1351 This routine runs the child process for VfsAccessSetUserGroupId.
1352
1353 Arguments:
1354
1355 None.
1356
1357 Return Value:
1358
1359 Returns 0 on success, -1 on failure.
1360
1361 --*/
1362
1363 {
1364
1365 uid_t EffectiveGroup;
1366 uid_t FilesystemGroup;
1367 uid_t RealGroup;
1368 uid_t SavedGroup;
1369 int Result = LXT_RESULT_FAILURE;
1370 uid_t EffectiveUser;
1371 uid_t FilesystemUser;
1372 uid_t RealUser;
1373 uid_t SavedUser;
1374
1375 LxtLogInfo("Child executable starting");
1376
1377 //
1378 // Get the user and group id and verify they match the expected.
1379 //
1380
1381 LxtCheckResult(getresuid(&RealUser, &EffectiveUser, &SavedUser));
1382 LxtCheckEqual(EffectiveUser, VFS_ACCESS_UID, "%u");
1383 LxtCheckEqual(SavedUser, VFS_ACCESS_UID, "%u");
1384
1385 FilesystemUser = LxtSetfsuid(-1);
1386 LxtCheckEqual(FilesystemUser, VFS_ACCESS_UID, "%u");
1387
1388 LxtCheckResult(getresgid(&RealGroup, &EffectiveGroup, &SavedGroup));
1389 LxtCheckEqual(EffectiveGroup, VFS_ACCESS_UID, "%u");
1390 LxtCheckEqual(SavedGroup, VFS_ACCESS_UID, "%u");
1391
1392 FilesystemGroup = LxtSetfsgid(-1);
1393 LxtCheckEqual(FilesystemGroup, VFS_ACCESS_UID, "%u");
1394
1395 LxtLogInfo("Child executable finished");
1396 Result = LXT_RESULT_SUCCESS;
1397
1398 ErrorExit:
1399 return Result;
1400 }
1401
1402 void VfsAccessSetUserGroupIdFSetIdChild(int Fd1)
1403
1404 /*++
1405 --*/
1406
1407 {
1408
1409 struct __user_cap_data_struct CapData[2];
1410 struct __user_cap_header_struct CapHeader;
1411 char* Data = "Test data";
1412 int Fd2 = -1;
1413 char Path[PATH_MAX];
1414 int Result;
1415
1416 memset(&CapData, 0, sizeof(CapData));
1417 memset(&CapHeader, 0, sizeof(CapHeader));
1418 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1419
1420 //
1421 // Drop privileges so the current process does not have VFS capabilities
1422 // and is in the other user\group.
1423 //
1424
1425 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1426 LxtCheckErrno(setgid(VFS_ACCESS_UID));
1427 LxtCheckErrno(setuid(VFS_ACCESS_UID));
1428 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1429
1430 // The plan 9 server cannot know about the uid change after open, so reopen
1431 // the file with the new security context.
1432 if (g_LxtFsInfo.FsType == LxtFsTypePlan9)
1433 {
1434 snprintf(Path, sizeof(Path), "/proc/self/fd/%d", Fd1);
1435 LxtCheckResult(Fd2 = open(Path, O_WRONLY));
1436 LxtCheckErrno(write(Fd2, Data, 1));
1437 LxtCheckClose(Fd2);
1438 }
1439 else
1440 {
1441 LxtCheckErrno(write(Fd1, Data, 1));
1442 }
1443 Result = LXT_RESULT_SUCCESS;
1444
1445 ErrorExit:
1446 if (Fd2 >= 0)
1447 {
1448 close(Fd2);
1449 }
1450
1451 _exit(Result);
1452 }
1453
1454 void VfsAccessSetUserGroupIdChmodChild(char* FilePath, uid_t Uid, gid_t Gid)
1455
1456 /*++
1457 --*/
1458
1459 {
1460
1461 struct stat Buffer;
1462 struct __user_cap_data_struct CapData[2];
1463 struct __user_cap_header_struct CapHeader;
1464 int Result;
1465
1466 memset(&CapData, 0, sizeof(CapData));
1467 memset(&CapHeader, 0, sizeof(CapHeader));
1468 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1469 CapData[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
1470 // CapData[CAP_TO_INDEX(CAP_FOWNER)].permitted |= CAP_TO_MASK(CAP_FOWNER);
1471 CapData[0].effective = CapData[0].permitted;
1472 CapData[1].effective = CapData[1].permitted;
1473 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1474 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1475
1476 LxtLogInfo("chown(%s, %d, %d)", FilePath, Uid, Gid);
1477 LxtCheckErrnoFailure(chown(FilePath, Uid, Gid), EPERM);
1478 LxtCheckErrno(stat(FilePath, &Buffer));
1479 LxtCheckEqual((Buffer.st_mode & (S_ISUID | S_ISGID)), (S_ISUID | S_ISGID), "%o");
1480
1481 Result = LXT_RESULT_SUCCESS;
1482
1483 ErrorExit:
1484 _exit(Result);
1485 }
1486
1487 int VfsAccessSetUserGroupId(PLXT_ARGS Args)
1488
1489 /*++
1490 --*/
1491
1492 {
1493
1494 char* Argv[4];
1495 struct stat Buffer;
1496 int ChildPid;
1497 char* Envp[1];
1498 mode_t ExpectedMode;
1499 int Fd1 = 0;
1500 int Fd2 = 0;
1501 int Mode;
1502 int Result;
1503
1504 rmdir(VFS_ACCESS_GROUP_USER_ID_DIR);
1505
1506 //
1507 // Create a directory with the set-group-ID bit set.
1508 //
1509
1510 LxtCheckErrno(mkdir(VFS_ACCESS_GROUP_USER_ID_DIR, S_IRWXU));
1511 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR, &Buffer));
1512 LxtLogInfo("VFS_ACCESS_GROUP_USER_ID_DIR mode after mkdir %o", Buffer.st_mode);
1513
1514 //
1515 // Change the owner of the directory and set the set-group-ID bit.
1516 //
1517
1518 LxtCheckErrno(chown(VFS_ACCESS_GROUP_USER_ID_DIR, VFS_ACCESS_UID, VFS_ACCESS_UID));
1519 LxtCheckErrno(chmod(VFS_ACCESS_GROUP_USER_ID_DIR, S_IRWXU | S_ISGID));
1520 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR, &Buffer));
1521 LxtLogInfo("VFS_ACCESS_GROUP_USER_ID_DIR mode after chmod %o", Buffer.st_mode);
1522
1523 //
1524 // Create some files and child directories.
1525 //
1526
1527 LxtCheckErrno(Fd1 = creat(VFS_ACCESS_GROUP_USER_ID_DIR "/file1", 0777 | S_IRWXU | S_ISGID | S_ISUID));
1528 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR "/file1", &Buffer));
1529 LxtLogInfo("VFS_ACCESS_GROUP_USER_ID_DIR /file1 mode after mkdir %o", Buffer.st_mode);
1530
1531 LxtCheckErrno(mkdir(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1", S_IRWXU));
1532 LxtCheckErrno(Fd2 = creat(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1/file2", S_IRWXU));
1533 LxtCheckErrno(mkdir(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1/dir2", S_IRWXU));
1534
1535 //
1536 // Validate the files and directories have the correct uid and gid.
1537 //
1538
1539 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR "/file1", &Buffer));
1540 if (Buffer.st_gid != VFS_ACCESS_UID)
1541 {
1542 LxtLogError("/file1 gid %u does not match expected %u", Buffer.st_gid, VFS_ACCESS_UID);
1543 }
1544
1545 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1", &Buffer));
1546 if (Buffer.st_gid != VFS_ACCESS_UID)
1547 {
1548 LxtLogError("/dir gid %u does not match expected %u", Buffer.st_gid, VFS_ACCESS_UID);
1549 }
1550
1551 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1/file2", &Buffer));
1552 if (Buffer.st_gid != VFS_ACCESS_UID)
1553 {
1554 LxtLogError("/dir1/file2 gid %u does not match expected %u", Buffer.st_gid, VFS_ACCESS_UID);
1555 }
1556
1557 LxtCheckErrno(stat(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1/dir2", &Buffer));
1558 if (Buffer.st_gid != VFS_ACCESS_UID)
1559 {
1560 LxtLogError("/dir1/dir2 gid %u does not match expected %u", Buffer.st_gid, VFS_ACCESS_UID);
1561 }
1562
1563 //
1564 // Validate the execute behavior of the set user id and group id bits.
1565 // Make a copy of the current binary to use for the test.
1566 //
1567
1568 // change Args->Argv[0] so that it points to the new single test binary design
1569 Args->Argv[0] = WSL_UNIT_TEST_BINARY;
1570
1571 LxtCheckResult(LxtCopyFile(Args->Argv[0], VFS_ACCESS_PARENT_DIR "/wsl_unit_tests"));
1572
1573 LxtCheckErrno(chown(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", VFS_ACCESS_UID, VFS_ACCESS_UID));
1574
1575 LxtCheckErrno(stat(Args->Argv[0], &Buffer));
1576 LxtCheckErrno(chmod(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", (Buffer.st_mode | S_ISUID | S_ISGID)));
1577
1578 ExpectedMode = Buffer.st_mode;
1579
1580 //
1581 // Start the child process.
1582 //
1583
1584 LxtCheckErrno(ChildPid = fork());
1585 if (ChildPid == 0)
1586 {
1587 Argv[0] = VFS_ACCESS_PARENT_DIR "/wsl_unit_tests";
1588 Argv[1] = "vfsaccess";
1589 Argv[2] = "-c";
1590 Argv[3] = Envp[0] = NULL;
1591 LxtCheckErrno(stat(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", &Buffer));
1592 LxtLogInfo("child %o %u %u", Buffer.st_mode, Buffer.st_uid, Buffer.st_gid);
1593 execve(Argv[0], Argv, Envp);
1594 LxtLogError("Execve failed, errno: %d (%s)", errno, strerror(errno));
1595 _exit(LXT_RESULT_FAILURE);
1596 }
1597
1598 //
1599 // Wait for the child to exit.
1600 //
1601
1602 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1603
1604 //
1605 // Set the uid and gid again to make sure the set-user-id and set-group-id
1606 // bits are stripped from the mode.
1607 //
1608
1609 LxtCheckErrno(chown(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", -1, -1));
1610 LxtCheckErrno(stat(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", &Buffer));
1611 LxtCheckEqual(Buffer.st_mode, ExpectedMode, "0%o");
1612
1613 //
1614 // Re-set the set-user-id and set-group-id bits.
1615 //
1616
1617 LxtCheckErrno(chmod(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", (Buffer.st_mode | S_ISUID | S_ISGID)));
1618
1619 // VirtioFs does not currently handle capability flags. There is a new KILLPRIV2 FUSE flag that may address this in the future.
1620 if (g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
1621 {
1622 //
1623 // Fork and drop privileges so the current process does not have CAP_FOWNER
1624 // which is required for changing the owner of a file with the set-user-id
1625 // or set-group-id bits set.
1626 //
1627
1628 LxtCheckErrno(ChildPid = fork());
1629 if (ChildPid == 0)
1630 {
1631 VfsAccessSetUserGroupIdChmodChild(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", VFS_ACCESS_UID, VFS_ACCESS_UID);
1632 }
1633
1634 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1635
1636 LxtCheckErrno(ChildPid = fork());
1637 if (ChildPid == 0)
1638 {
1639 VfsAccessSetUserGroupIdChmodChild(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", VFS_ACCESS_UID, -1);
1640 }
1641
1642 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1643
1644 LxtCheckErrno(ChildPid = fork());
1645 if (ChildPid == 0)
1646 {
1647 VfsAccessSetUserGroupIdChmodChild(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", -1, VFS_ACCESS_UID);
1648 }
1649
1650 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1651
1652 LxtCheckErrno(ChildPid = fork());
1653 if (ChildPid == 0)
1654 {
1655 VfsAccessSetUserGroupIdChmodChild(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests", -1, -1);
1656 }
1657
1658 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1659 }
1660
1661 //
1662 // Validate the behavior of CAP_FSETID for files.
1663 //
1664
1665 LxtLogInfo("Checking CAP_FSETID for files");
1666 LxtCheckErrno(fstat(Fd1, &Buffer));
1667 Mode = Buffer.st_mode;
1668 if ((Mode & (S_ISGID | S_ISUID)) != (S_ISGID | S_ISUID))
1669 {
1670 LxtLogError("Unexpected mode");
1671 Result = LXT_RESULT_FAILURE;
1672 goto ErrorExit;
1673 }
1674
1675 LxtCheckErrno(write(Fd1, &Buffer, sizeof(Buffer)));
1676 LxtCheckErrno(fstat(Fd1, &Buffer));
1677 LxtCheckEqual(Buffer.st_mode, Mode, "%o");
1678
1679 LxtCheckErrno(ChildPid = fork());
1680 if (ChildPid == 0)
1681 {
1682 VfsAccessSetUserGroupIdFSetIdChild(Fd1);
1683 }
1684
1685 //
1686 // Wait for the child to exit and validate that the set id bits were
1687 // silently removed.
1688 //
1689
1690 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
1691 LxtCheckErrno(fstat(Fd1, &Buffer));
1692 LxtCheckEqual(Buffer.st_mode, Mode & ~(S_ISGID | S_ISUID), "%o");
1693
1694 Result = LXT_RESULT_SUCCESS;
1695
1696 ErrorExit:
1697 if (Fd1 > 0)
1698 {
1699 LxtClose(Fd1);
1700 }
1701
1702 if (Fd2 > 0)
1703 {
1704 LxtClose(Fd2);
1705 }
1706
1707 if (ChildPid == 0)
1708 {
1709 _exit(Result);
1710 }
1711
1712 //
1713 // Clean-up created files and directories.
1714 //
1715
1716 unlink(VFS_ACCESS_PARENT_DIR "/wsl_unit_tests");
1717 remove(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1/file2");
1718 rmdir(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1/dir2");
1719 remove(VFS_ACCESS_GROUP_USER_ID_DIR "/file1");
1720 rmdir(VFS_ACCESS_GROUP_USER_ID_DIR "/dir1");
1721 rmdir(VFS_ACCESS_GROUP_USER_ID_DIR);
1722 return Result;
1723 }
1724
1725 void VfsAccessInodeChecksChild(void)
1726
1727 /*++
1728 --*/
1729
1730 {
1731
1732 struct __user_cap_data_struct CapData[2];
1733 struct __user_cap_header_struct CapHeader;
1734 char* CommandLine[] = {NULL, NULL};
1735 int ErrnoExpected;
1736 char FileName[100];
1737 unsigned int Index;
1738 int Result;
1739 int ResultActual;
1740 int ResultExpected;
1741
1742 memset(&CapData, 0, sizeof(CapData));
1743 memset(&CapHeader, 0, sizeof(CapHeader));
1744 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1745
1746 //
1747 // Drop privileges so the current process does not have VFS capabilities
1748 // and is in the other user\group.
1749 //
1750
1751 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1752 LxtCheckErrno(setgid(VFS_ACCESS_UID));
1753 LxtCheckErrno(setuid(VFS_ACCESS_UID));
1754 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1755
1756 //
1757 // For each file, check that read, write and execute is enforced. Similarly
1758 // for directories check that list, create\delete, and search is enforced.
1759 //
1760
1761 for (Index = 0; Index < LXT_COUNT_OF(g_VfsInodeEntries); ++Index)
1762 {
1763 if (S_ISREG(g_VfsInodeEntries[Index].Mode))
1764 {
1765
1766 //
1767 // Check read access.
1768 //
1769
1770 ResultExpected = -1;
1771 if ((g_VfsInodeEntries[Index].Mode & S_IROTH) != 0)
1772 {
1773 ResultExpected = 0;
1774 }
1775
1776 ResultActual = open(g_VfsInodeEntries[Index].Name, O_RDONLY, 0);
1777 if (ResultActual != -1)
1778 {
1779 LxtClose(ResultActual);
1780 ResultActual = 0;
1781 }
1782
1783 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "file open O_RDONLY", Index));
1784
1785 //
1786 // Check write access.
1787 //
1788
1789 ResultExpected = -1;
1790 if ((g_VfsInodeEntries[Index].Mode & S_IWOTH) != 0)
1791 {
1792 ResultExpected = 0;
1793 }
1794
1795 ResultActual = open(g_VfsInodeEntries[Index].Name, O_WRONLY, 0);
1796 if (ResultActual != -1)
1797 {
1798 LxtClose(ResultActual);
1799 ResultActual = 0;
1800 }
1801
1802 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "file open O_WRONLY", Index));
1803
1804 //
1805 // Check read\write access.
1806 //
1807
1808 ResultExpected = -1;
1809 if (((g_VfsInodeEntries[Index].Mode & S_IROTH) != 0) && ((g_VfsInodeEntries[Index].Mode & S_IWOTH) != 0))
1810 {
1811
1812 ResultExpected = 0;
1813 }
1814
1815 ResultActual = open(g_VfsInodeEntries[Index].Name, O_RDWR, 0);
1816 if (ResultActual != -1)
1817 {
1818 LxtClose(ResultActual);
1819 ResultActual = 0;
1820 }
1821
1822 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "file open O_RDWR", Index));
1823
1824 //
1825 // Check no access (open time check for read\write).
1826 //
1827
1828 if (((g_VfsInodeEntries[Index].Mode & S_IROTH) != 0) && ((g_VfsInodeEntries[Index].Mode & S_IWOTH) != 0))
1829 {
1830
1831 ResultExpected = 0;
1832 }
1833
1834 ResultActual = open(g_VfsInodeEntries[Index].Name, O_NOACCESS, 0);
1835 if (ResultActual != -1)
1836 {
1837 LxtClose(ResultActual);
1838 ResultActual = 0;
1839 }
1840
1841 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "file open O_NOACCESS", Index));
1842
1843 //
1844 // Check execute access.
1845 //
1846
1847 ErrnoExpected = EACCES;
1848 ResultExpected = -1;
1849 if ((g_VfsInodeEntries[Index].Mode & S_IXOTH) != 0)
1850 {
1851 ErrnoExpected = ENOEXEC;
1852 }
1853
1854 CommandLine[0] = g_VfsInodeEntries[Index].Name;
1855 ResultActual = execv(CommandLine[0], CommandLine);
1856 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "execv", Index));
1857 }
1858 else
1859 {
1860
1861 //
1862 // Check read access.
1863 //
1864
1865 ResultExpected = -1;
1866 if ((g_VfsInodeEntries[Index].Mode & S_IROTH) != 0)
1867 {
1868 ResultExpected = 0;
1869 }
1870
1871 ResultActual = open(g_VfsInodeEntries[Index].Name, O_RDONLY, 0);
1872 if (ResultActual != -1)
1873 {
1874 LxtClose(ResultActual);
1875 ResultActual = 0;
1876 }
1877
1878 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "directory open O_RDONLY", Index));
1879
1880 //
1881 // Check create\delete (write) access. Execute access is also
1882 // required to create and delete.
1883 //
1884
1885 sprintf(FileName, "%s/%s", g_VfsInodeEntries[Index].Name, VFS_ACCESS_INODE_ENTRY_FILE);
1886
1887 ResultExpected = -1;
1888 if (((g_VfsInodeEntries[Index].Mode & S_IWOTH) != 0) && ((g_VfsInodeEntries[Index].Mode & S_IXOTH) != 0))
1889 {
1890
1891 ResultExpected = 0;
1892 }
1893
1894 ResultActual = open(FileName, O_CREAT | O_RDONLY, S_IRUSR);
1895 if (ResultActual != -1)
1896 {
1897 LxtClose(ResultActual);
1898 ResultActual = 0;
1899 }
1900
1901 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "directory create file", Index));
1902
1903 if (ResultActual == 0)
1904 {
1905 ResultActual = unlink(FileName);
1906 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, EACCES, "directory delete file", Index));
1907 }
1908
1909 //
1910 // Check search (execute) access.
1911 //
1912
1913 ErrnoExpected = EACCES;
1914 ResultExpected = -1;
1915 if ((g_VfsInodeEntries[Index].Mode & S_IXOTH) != 0)
1916 {
1917 ErrnoExpected = ENOENT;
1918 }
1919
1920 ResultActual = open(FileName, O_RDONLY, 0);
1921 if (ResultActual != -1)
1922 {
1923 LxtClose(ResultActual);
1924 ResultActual = 0;
1925 }
1926
1927 LxtCheckResult(VfsAccessCheckResult(ResultActual, ResultExpected, errno, ErrnoExpected, "directory search file", Index));
1928 }
1929 }
1930
1931 Result = LXT_RESULT_SUCCESS;
1932
1933 ErrorExit:
1934 _exit(Result);
1935 }
1936
1937 int VfsAccessInodeChecks(PLXT_ARGS Args)
1938
1939 /*++
1940 --*/
1941
1942 {
1943
1944 int ChildPid;
1945 int Result;
1946
1947 ChildPid = fork();
1948 if (ChildPid == 0)
1949 {
1950 VfsAccessInodeChecksChild();
1951 }
1952
1953 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1954 Result = LXT_RESULT_SUCCESS;
1955
1956 ErrorExit:
1957 return Result;
1958 }
1959
1960 int VfsAccessParseArgs(int Argc, char* Argv[], LXT_ARGS* Args)
1961
1962 /*++
1963
1964 Routine Description:
1965
1966 This routine parses command line arguments for the vfsaccess tests.
1967
1968 Arguments:
1969
1970 Argc - Supplies the number of arguments.
1971
1972 Argv - Supplies an array of arguments.
1973
1974 Return Value:
1975
1976 Returns 0 on success, -1 on failure.
1977
1978 --*/
1979
1980 {
1981
1982 int ArgvIndex;
1983 bool Cleanup;
1984 const char* Name;
1985 int Result;
1986 int ValidArguments;
1987
1988 Result = LXT_RESULT_FAILURE;
1989 ValidArguments = 0;
1990 g_UseDrvFs = false;
1991 Name = LXT_NAME;
1992 Cleanup = true;
1993 if (Argc < 1)
1994 {
1995 goto ErrorExit;
1996 }
1997
1998 umask(0);
1999 for (ArgvIndex = 1; ArgvIndex < Argc; ++ArgvIndex)
2000 {
2001 if (strcmp(Argv[ArgvIndex], "drvfs") == 0)
2002 {
2003 g_UseDrvFs = true;
2004 Name = LXT_NAME_DRVFS;
2005 continue;
2006 }
2007
2008 if (Argv[ArgvIndex][0] != '-')
2009 {
2010 printf("Unexpected character %s", Argv[ArgvIndex]);
2011 goto ErrorExit;
2012 }
2013
2014 switch (Argv[ArgvIndex][1])
2015 {
2016 case 'c':
2017
2018 //
2019 // Run the setusergroupid execve test child
2020 //
2021
2022 ValidArguments = 1;
2023 Cleanup = false;
2024 Result = VfsAccessSetUserGroupIdExecveChild();
2025 goto ErrorExit;
2026
2027 case 'v':
2028 case 'l':
2029
2030 //
2031 // This was already taken care of by LxtInitialize.
2032 //
2033
2034 ++ArgvIndex;
2035
2036 break;
2037
2038 case 'h':
2039 case 'a':
2040 break;
2041
2042 default:
2043 goto ErrorExit;
2044 }
2045 }
2046
2047 //
2048 // If -c was not specified, just run the tests
2049 //
2050
2051 ValidArguments = 1;
2052 LxtCheckResult(LxtInitialize(Argc, Argv, Args, Name));
2053 LxtCheckResult(LxtFsTestSetup(Args, VFS_ACCESS_PARENT_DIR, "/vfsaccesstest", g_UseDrvFs));
2054
2055 if (Args->HelpRequested == false)
2056 {
2057 LxtLogInfo("Creating files.");
2058 LxtCheckResult(VfsAccessFileObjectCreateFiles());
2059 LxtCheckResult(VfsAccessFileObjectCreateSymlinks());
2060 }
2061
2062 //
2063 // Tests must be run forked since some of the tests change the uid and
2064 // don't change it back, which breaks umount during cleanup.
2065 //
2066
2067 LxtCheckResult(LxtRunVariationsForked(Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
2068
2069 ErrorExit:
2070 if (ValidArguments == 0)
2071 {
2072 printf("\nuse: %s <One of the below arguments>\n", Argv[0]);
2073 printf("\t-c : Run %s execve test child (don't use directly)\n", Argv[0]);
2074 }
2075
2076 if (Cleanup != false)
2077 {
2078 VfsAccessFileObjectCleanup();
2079 LxtFsTestCleanup(VFS_ACCESS_PARENT_DIR, "/vfsaccesstest", g_UseDrvFs);
2080 }
2081
2082 return Result;
2083 }
2084
2085 void VfsAccessUTimeCapChild(void)
2086
2087 /*++
2088 --*/
2089
2090 {
2091
2092 struct __user_cap_data_struct CapData[2];
2093 struct __user_cap_header_struct CapHeader;
2094 int Fd;
2095 int Result;
2096 struct timeval Times[2];
2097
2098 memset(&CapData, 0, sizeof(CapData));
2099 memset(&CapHeader, 0, sizeof(CapHeader));
2100 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
2101 CapData[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
2102 CapData[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
2103 CapData[0].effective = CapData[0].permitted;
2104 CapData[1].effective = CapData[1].permitted;
2105
2106 //
2107 // Drop privileges so the current process does not have CAP_FOWNER.
2108 //
2109
2110 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
2111 LxtCheckErrno(setgid(VFS_ACCESS_UID));
2112 LxtCheckErrno(setuid(VFS_ACCESS_UID));
2113 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
2114
2115 //
2116 // Create a file with a different user.
2117 //
2118
2119 unlink(VFS_ACCESS_UTIME_FILE);
2120 LxtCheckErrno(Fd = open(VFS_ACCESS_UTIME_FILE, O_CREAT, 0));
2121 LxtClose(Fd);
2122 LxtCheckErrno(chown(VFS_ACCESS_UTIME_FILE, VFS_ACCESS_UID + 1, VFS_ACCESS_UID + 1));
2123
2124 //
2125 // Try to change the time on the file to 0.
2126 //
2127
2128 memset(Times, 0, sizeof(Times));
2129 LxtCheckErrnoFailure(utimes(VFS_ACCESS_UTIME_FILE, Times), EPERM);
2130
2131 Result = LXT_RESULT_SUCCESS;
2132
2133 ErrorExit:
2134 unlink(VFS_ACCESS_UTIME_FILE);
2135 _exit(Result);
2136 }
2137
2138 int VfsAccessUTimeCap(PLXT_ARGS Args)
2139
2140 /*++
2141 --*/
2142
2143 {
2144
2145 int ChildPid;
2146 int Result;
2147
2148 ChildPid = fork();
2149 if (ChildPid == 0)
2150 {
2151 VfsAccessUTimeCapChild();
2152 }
2153
2154 LxtCheckResult(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
2155 Result = LXT_RESULT_SUCCESS;
2156
2157 ErrorExit:
2158 return Result;
2159 }
2160
2161 int VfsAccessSetFsUid(PLXT_ARGS Args)
2162
2163 /*++
2164 --*/
2165
2166 {
2167
2168 unsigned long long Effective;
2169 struct __user_cap_data_struct CapData[2];
2170 struct __user_cap_header_struct CapHeader;
2171 struct __user_cap_data_struct ExpectedCapData[2];
2172 int Fd;
2173 int Index;
2174 struct passwd* Password;
2175 int Result;
2176
2177 memset(&CapData, 0, sizeof(CapData));
2178 memset(&CapHeader, 0, sizeof(CapHeader));
2179 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
2180
2181 Fd = -1;
2182 Result = LXT_RESULT_FAILURE;
2183
2184 //
2185 // Get the password entry for the 'nobody' user.
2186 //
2187
2188 Password = getpwnam("nobody");
2189 if (Password == NULL)
2190 {
2191 goto ErrorExit;
2192 }
2193
2194 //
2195 // Create a file to be used for access checks.
2196 //
2197
2198 Fd = open(VFS_ACCESS_FSUID_FILE, O_CREAT | O_RDWR, 0644);
2199 if (Fd < 0)
2200 {
2201 goto ErrorExit;
2202 }
2203
2204 //
2205 // Get the original capabilities.
2206 //
2207
2208 LxtCheckErrno(LxtCapGet(&CapHeader, ExpectedCapData));
2209 Effective = (((unsigned long long)ExpectedCapData[0].effective) << 32) | ExpectedCapData[1].effective;
2210 LxtLogInfo("Before setfsuid(nobody) %016llX", Effective);
2211
2212 //
2213 // Set the fsuid and ensure that the correct capabilities are dropped when
2214 // switching from root.
2215 //
2216
2217 if (LxtSetfsuid(Password->pw_uid) < 0)
2218 {
2219 goto ErrorExit;
2220 }
2221
2222 LxtCheckErrno(LxtCapGet(&CapHeader, CapData));
2223 Effective = (((unsigned long long)CapData[0].effective) << 32) | CapData[1].effective;
2224 LxtLogInfo("After setfsuid(nobody) %016llX", Effective);
2225 for (Index = 0; Index < LXT_COUNT_OF(g_VfsSetFsUidCaps); Index++)
2226 {
2227 ExpectedCapData[CAP_TO_INDEX(g_VfsSetFsUidCaps[Index])].effective &= ~CAP_TO_MASK(g_VfsSetFsUidCaps[Index]);
2228 }
2229
2230 if ((CapData[0].effective != ExpectedCapData[0].effective) || (CapData[1].effective != ExpectedCapData[1].effective))
2231 {
2232
2233 LxtLogError("Capabilities do not match expected");
2234 Result = LXT_RESULT_FAILURE;
2235 goto ErrorExit;
2236 }
2237
2238 //
2239 // Verify that opening the file fails since we no longer have the correct fsuid or capabilities.
2240 //
2241
2242 LxtCheckErrnoFailure(open(VFS_ACCESS_FSUID_FILE, O_RDWR), EACCES);
2243
2244 //
2245 // Set the fsuid back to root and verify that the capabilities were correctly restored.
2246 //
2247
2248 LxtCheckErrno(LxtSetfsuid(0));
2249
2250 LxtCheckErrno(LxtCapGet(&CapHeader, CapData));
2251 Effective = (((unsigned long long)CapData[0].effective) << 32) | CapData[1].effective;
2252 LxtLogInfo("After setfsuid(root) %016llX", Effective);
2253 for (Index = 0; Index < LXT_COUNT_OF(g_VfsSetFsUidCaps); Index++)
2254 {
2255 ExpectedCapData[CAP_TO_INDEX(g_VfsSetFsUidCaps[Index])].effective |= CAP_TO_MASK(g_VfsSetFsUidCaps[Index]);
2256 }
2257
2258 if ((CapData[0].effective != ExpectedCapData[0].effective) || (CapData[1].effective != ExpectedCapData[1].effective))
2259 {
2260
2261 LxtLogError("Capabilities do not match expected");
2262 Result = LXT_RESULT_FAILURE;
2263 goto ErrorExit;
2264 }
2265
2266 Result = LXT_RESULT_SUCCESS;
2267
2268 ErrorExit:
2269 if (Fd != -1)
2270 {
2271 LxtClose(Fd);
2272 }
2273
2274 unlink(VFS_ACCESS_FSUID_FILE);
2275 return Result;
2276 }
2277
2278 void getreuid(struct reuid_t* Set)
2279 {
2280 getresuid(&Set->r, &Set->e, &Set->s);
2281 // LxtLogInfo("getresuid(%d,%d,%d)",Set->r,Set->e,Set->s);
2282 }
2283
2284 pid_t fork_wait()
2285 {
2286 pid_t pid;
2287 int status = 0;
2288 if ((pid = fork()) == 0)
2289 {
2290 return pid;
2291 }
2292 else
2293 {
2294 waitpid(pid, &status, 0);
2295 }
2296 return pid;
2297 }
2298
2299 int VfsAccessSetUid(PLXT_ARGS Args)
2300
2301 {
2302
2303 struct reuid_t Original;
2304 struct reuid_t Set;
2305 struct passwd* Nobody;
2306 int Result;
2307
2308 getreuid(&Original);
2309 LxtLogInfo("Current UID: %d", Original.r);
2310 LxtLogInfo("Current EUID: %d", Original.e);
2311 LxtLogInfo("Current SUID: %d", Original.s);
2312
2313 //
2314 // Try setting without changing
2315 //
2316
2317 setreuid(-1, -1);
2318 getreuid(&Set);
2319 LxtCheckEqual(Set.r, Original.r, "%d");
2320 LxtCheckEqual(Set.e, Original.e, "%d");
2321 LxtCheckEqual(Set.s, Original.s, "%d");
2322
2323 //
2324 // More tests possible when run as root.
2325 //
2326
2327 if (Original.r == 0 || Original.e == 0)
2328 {
2329 Nobody = getpwnam("nobody");
2330 if (Nobody == NULL)
2331 {
2332 Result = LXT_RESULT_FAILURE;
2333 LxtLogError("Couldn't get details for user 'nobody'");
2334 goto ErrorExit;
2335 }
2336
2337 LxtLogInfo("Attempting setreuid(%d, -1)", Nobody->pw_uid);
2338 LxtCheckResult(setreuid(Nobody->pw_uid, -1));
2339 getreuid(&Set);
2340 if (Set.r != Nobody->pw_uid || Set.e != 0 || Set.s != 0)
2341 {
2342 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2343 }
2344
2345 //
2346 // reset state to 0, 0, 0
2347 //
2348
2349 LxtLogInfo("setuid(0)");
2350 LxtCheckResult(setuid(0));
2351 getreuid(&Set);
2352 if (Set.r != 0 || Set.e != 0 || Set.s != 0)
2353 {
2354 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2355 return -1; // Fatal, Nobody tests rely on this succeeding
2356 }
2357
2358 //
2359 // This test checks that setuid only touches the ruid and suid values.
2360 //
2361
2362 LxtLogInfo("setresuid(-1, %d, %d)", Nobody->pw_uid, Nobody->pw_uid);
2363 LxtCheckResult(setresuid(-1, Nobody->pw_uid, Nobody->pw_uid));
2364 getreuid(&Set);
2365 if (Set.r != 0 || Set.e != Nobody->pw_uid || Set.s != Nobody->pw_uid)
2366 {
2367 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2368 }
2369
2370 //
2371 // Set state to 0, 0, 65534
2372 //
2373
2374 LxtLogInfo("Attempting setuid(0)");
2375 LxtCheckResult(setuid(0));
2376 getreuid(&Set);
2377 if (Set.r != 0 || Set.e != 0 || Set.s != 65534)
2378 {
2379 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2380 }
2381
2382 //
2383 // This test checks the first transitive property of setreuid wherein
2384 // setting the effective uid also sets the suid
2385 //
2386 // Reset state to 0, 0, 0
2387 //
2388
2389 LxtLogInfo("setresuid(0, 0, 0)");
2390 LxtCheckResult(setresuid(0, 0, 0));
2391 getreuid(&Set);
2392 if (Set.r != 0 || Set.e != 0 || Set.s != 0)
2393 {
2394 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2395 return -1; // Fatal, Other tests rely on this succeeding
2396 }
2397 LxtLogInfo("setreuid(-1, %d)", Nobody->pw_uid);
2398 LxtCheckResult(setreuid(-1, Nobody->pw_uid));
2399 getreuid(&Set);
2400 if (Set.r != 0 || Set.e != Nobody->pw_uid || Set.s != Nobody->pw_uid)
2401 {
2402 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2403 }
2404
2405 //
2406 // Set state to 0, 0, 65534
2407 //
2408
2409 LxtLogInfo("Attempting setuid(0)");
2410 LxtCheckResult(setuid(0));
2411 getreuid(&Set);
2412 if (Set.r != 0 || Set.e != 0 || Set.s != 65534)
2413 {
2414 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2415 }
2416
2417 //
2418 // This test checks the second transitive property of setreuid
2419 // wherein setting the ruid, but not the euid will Set the suid
2420 // to be the euid
2421 //
2422
2423 LxtLogInfo("setresuid(%d, 0, VFS_ACCESS_UID)", Nobody->pw_uid);
2424 LxtCheckResult(setresuid(Nobody->pw_uid, 0, VFS_ACCESS_UID));
2425 getreuid(&Set);
2426 if (Set.r != Nobody->pw_uid || Set.e != 0 || Set.s != VFS_ACCESS_UID)
2427 {
2428 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2429 }
2430 LxtLogInfo("Attempting setreuid(0, -1)");
2431 LxtCheckResult(setreuid(0, -1));
2432 getreuid(&Set);
2433 if (Set.r != 0 || Set.e != 0 || Set.s != 0)
2434 {
2435 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2436 }
2437
2438 //
2439 // This test checks that unprivileged processes can Set the euid
2440 // to the ruid or suid. Need to fork and wait as privileges are
2441 // irreversibly dropped by this syscall
2442 //
2443
2444 if (fork_wait() == 0)
2445 {
2446 LxtLogInfo("setresuid(%d, VFS_ACCESS_UID, 0)", Nobody->pw_uid);
2447 LxtCheckResult(setresuid(Nobody->pw_uid, VFS_ACCESS_UID, 0));
2448 getreuid(&Set);
2449 if (Set.r != Nobody->pw_uid || Set.e != VFS_ACCESS_UID || Set.s != 0)
2450 {
2451 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2452 }
2453 LxtLogInfo("Attempting setreuid(-1, %d)", Nobody->pw_uid);
2454 LxtCheckResult(setreuid(-1, Nobody->pw_uid));
2455 getreuid(&Set);
2456 if (Set.r != Nobody->pw_uid || Set.e != Nobody->pw_uid || Set.s != 0)
2457 {
2458 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2459 }
2460 exit(0);
2461 }
2462
2463 //
2464 // This test checks that unprivileged processes can Set the euid
2465 // to the ruid or suid.
2466 //
2467
2468 LxtLogInfo("setresuid(%d, %d, 0)", Nobody->pw_uid, Nobody->pw_uid);
2469 LxtCheckResult(setresuid(Nobody->pw_uid, Nobody->pw_uid, 0));
2470 getreuid(&Set);
2471 if (Set.r != Nobody->pw_uid || Set.e != Nobody->pw_uid || Set.s != 0)
2472 {
2473 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2474 }
2475 LxtLogInfo("Attempting setreuid(-1, 0)");
2476 LxtCheckResult(setreuid(-1, 0));
2477 getreuid(&Set);
2478 if (Set.r != Nobody->pw_uid || Set.e != 0 || Set.s != 0)
2479 {
2480 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2481 }
2482
2483 //
2484 // Reset state to 0, 0, 0
2485 //
2486
2487 LxtLogInfo("setresuid(0, 0, 0)");
2488 LxtCheckResult(setresuid(0, 0, 0));
2489 getreuid(&Set);
2490 if (Set.r != 0 || Set.e != 0 || Set.s != 0)
2491 {
2492 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2493 return -1; // Fatal, Other tests rely on this succeeding
2494 }
2495
2496 //
2497 // This test validates that unprivileged users can only Set the ruid
2498 // to the ruid or the euid
2499 //
2500
2501 if (fork_wait() == 0)
2502 {
2503 LxtLogInfo("setresuid(%d, VFS_ACCESS_UID, 0)", Nobody->pw_uid);
2504 LxtCheckResult(setresuid(Nobody->pw_uid, VFS_ACCESS_UID, 0));
2505 getreuid(&Set);
2506 if (Set.r != Nobody->pw_uid || Set.e != VFS_ACCESS_UID || Set.s != 0)
2507 {
2508 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2509 }
2510 LxtLogInfo("Attempting setreuid(VFS_ACCESS_UID, -1)");
2511 LxtCheckResult(setreuid(VFS_ACCESS_UID, -1));
2512 getreuid(&Set);
2513 if (Set.r != VFS_ACCESS_UID || Set.e != VFS_ACCESS_UID || Set.s != VFS_ACCESS_UID)
2514 {
2515 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2516 }
2517 exit(0);
2518 }
2519 if (fork_wait() == 0)
2520 {
2521 LxtLogInfo("setresuid(%d, VFS_ACCESS_UID, 0)", Nobody->pw_uid);
2522 LxtCheckResult(setresuid(Nobody->pw_uid, VFS_ACCESS_UID, 0));
2523 getreuid(&Set);
2524 if (Set.r != Nobody->pw_uid || Set.e != VFS_ACCESS_UID || Set.s != 0)
2525 {
2526 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2527 }
2528 LxtLogInfo("Attempting setreuid(0, -1)");
2529 LxtCheckErrnoFailure(setreuid(0, -1), EPERM);
2530 getreuid(&Set);
2531 if (Set.r != Nobody->pw_uid || Set.e != VFS_ACCESS_UID || Set.s != 0)
2532 {
2533 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2534 }
2535 exit(0);
2536 }
2537
2538 //
2539 // Drop all permissions permanently
2540 //
2541
2542 LxtLogInfo("Dropping all permissions");
2543 LxtLogInfo("setresuid(%d, %d, %d)", Nobody->pw_uid, Nobody->pw_uid, Nobody->pw_uid);
2544 LxtCheckResult(setresuid(Nobody->pw_uid, Nobody->pw_uid, Nobody->pw_uid));
2545 getreuid(&Set);
2546 if (Set.r != Nobody->pw_uid || Set.e != Nobody->pw_uid)
2547 {
2548 LxtLogError("uid=%d, euid=%d, suid=%d", Set.r, Set.e, Set.s);
2549 return -1;
2550 }
2551 }
2552
2553 //
2554 // Try to gain root uid
2555 //
2556
2557 LxtLogInfo("Attempting setreuid(0, -1)");
2558 LxtCheckErrnoFailure(setreuid(0, -1), EPERM);
2559 getreuid(&Set);
2560 if (Set.r == 0 || Set.e == 0)
2561 {
2562 LxtLogError("Gained root permissions!");
2563 }
2564 LxtLogInfo("Attempting setreuid(-1, 0)");
2565 LxtCheckErrnoFailure(setreuid(-1, 0), EPERM);
2566 getreuid(&Set);
2567 if (Set.r == 0 || Set.e == 0)
2568 {
2569 LxtLogError("Gained root permissions!");
2570 }
2571 LxtLogInfo("Attempting setreuid(0, 0)");
2572 LxtCheckErrnoFailure(setreuid(0, 0), EPERM);
2573 getreuid(&Set);
2574 if (Set.r == 0 || Set.e == 0)
2575 {
2576 LxtLogError("Gained root permissions!");
2577 }
2578
2579 ErrorExit:
2580 return Result;
2581 }