@@ -36,6 +36,10 @@ var gitCommit = ""
36
36
// VERSION file of the source code.
37
37
var version = ""
38
38
39
+ // errAccess will be used for defining either a read error or a write error
40
+ // from any type of files.
41
+ var errAccess error
42
+
39
43
// PrGetNoNewPrivs isn't exposed in Golang so we define it ourselves copying the value from
40
44
// the kernel
41
45
const PrGetNoNewPrivs = 39
@@ -411,10 +415,37 @@ func testReadAccess(path string) (readable bool, err error) {
411
415
if err != nil {
412
416
return false , err
413
417
}
414
- if fi .Mode ()& os .ModeType == 0 {
418
+
419
+ // Check for readability in case of regular files, character device, or
420
+ // directory. Although the runtime spec does not mandate the type of
421
+ // masked files, we should check its Mode explicitly. A masked file
422
+ // could be represented as a character file (/dev/null), which is the
423
+ // case for runtimes like runc.
424
+ switch fi .Mode () & os .ModeType {
425
+ case 0 , os .ModeDevice | os .ModeCharDevice :
415
426
return testFileReadAccess (path )
427
+ case os .ModeDir :
428
+ return testDirectoryReadAccess (path )
416
429
}
417
- return false , fmt .Errorf ("cannot test read access for %q (mode %d)" , path , fi .Mode ())
430
+
431
+ errAccess = fmt .Errorf ("cannot test read access for %q (mode %d)" , path , fi .Mode ())
432
+ return false , errAccess
433
+ }
434
+
435
+ func testDirectoryReadAccess (path string ) (readable bool , err error ) {
436
+ files , err := ioutil .ReadDir (path )
437
+ if err == io .EOF || len (files ) == 0 {
438
+ // Our validation/ tests only use non-empty directories for read-access
439
+ // tests. So if we get an EOF on the first read, the runtime did
440
+ // successfully block readability. So it should not be considered as test
441
+ // failure, it just means that the test program successfully assessed
442
+ // that the directory is not readable.
443
+ return false , nil
444
+ }
445
+ if err != nil {
446
+ return false , err
447
+ }
448
+ return true , nil
418
449
}
419
450
420
451
func testFileReadAccess (path string ) (readable bool , err error ) {
@@ -441,12 +472,20 @@ func testWriteAccess(path string) (writable bool, err error) {
441
472
if err != nil {
442
473
return false , err
443
474
}
444
- if fi .IsDir () {
445
- return testDirectoryWriteAccess (path )
446
- } else if fi .Mode ()& os .ModeType == 0 {
475
+
476
+ // Check for writability in case of regular files, character device, or
477
+ // directory. Although the runtime spec does not mandate the type of
478
+ // masked files, we should check its Mode explicitly. A masked file
479
+ // could be represented as a character file (/dev/null), which is the
480
+ // case for runtimes like runc.
481
+ switch fi .Mode () & os .ModeType {
482
+ case 0 , os .ModeDevice | os .ModeCharDevice :
447
483
return testFileWriteAccess (path )
484
+ case os .ModeDir :
485
+ return testDirectoryWriteAccess (path )
448
486
}
449
- return false , fmt .Errorf ("cannot test write access for %q (mode %d)" , path , fi .Mode ())
487
+ errAccess = fmt .Errorf ("cannot test write access for %q (mode %d)" , path , fi .Mode ())
488
+ return false , errAccess
450
489
}
451
490
452
491
func testDirectoryWriteAccess (path string ) (writable bool , err error ) {
@@ -858,7 +897,7 @@ func (c *complianceTester) validateMaskedPaths(spec *rspec.Spec) error {
858
897
859
898
for _ , maskedPath := range spec .Linux .MaskedPaths {
860
899
readable , err := testReadAccess (maskedPath )
861
- if err != nil && ! os .IsNotExist (err ) {
900
+ if err != nil && ! os .IsNotExist (err ) && err != errAccess {
862
901
return err
863
902
}
864
903
c .harness .Ok (! readable , fmt .Sprintf ("cannot read masked path %q" , maskedPath ))
@@ -901,15 +940,15 @@ func (c *complianceTester) validateROPaths(spec *rspec.Spec) error {
901
940
902
941
for i , path := range spec .Linux .ReadonlyPaths {
903
942
readable , err := testReadAccess (path )
904
- if err != nil {
943
+ if err != nil && err != errAccess {
905
944
return err
906
945
}
907
946
if ! readable {
908
947
c .harness .Skip (1 , fmt .Sprintf ("%q (linux.readonlyPaths[%d]) is not readable" , path , i ))
909
948
}
910
949
911
950
writable , err := testWriteAccess (path )
912
- if err != nil && ! os .IsNotExist (err ) {
951
+ if err != nil && ! os .IsNotExist (err ) && err != errAccess {
913
952
return err
914
953
}
915
954
c .harness .Ok (! writable , fmt .Sprintf ("%q (linux.readonlyPaths[%d]) is not writable" , path , i ))
0 commit comments