@@ -36,6 +36,10 @@ var gitCommit = ""
3636// VERSION file of the source code.
3737var version = ""
3838
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+
3943// PrGetNoNewPrivs isn't exposed in Golang so we define it ourselves copying the value from
4044// the kernel
4145const PrGetNoNewPrivs = 39
@@ -410,23 +414,35 @@ func testReadAccess(path string) (readable bool, err error) {
410414 return false , err
411415 }
412416
413- // In case of a directory, we should check its readability in a special way.
414- // In other files, we should not check its Mode explicitly, because the runtime
415- // spec does not mandate the type of masked files. It could be a regular file
416- // or a character file (/dev/null), which is the case for runtimes like runc.
417- if fi .IsDir () {
417+ // Check for readability in case of regular files, character device, or
418+ // directory. Although the runtime spec does not mandate the type of
419+ // masked files, we should check its Mode explicitly. A masked file
420+ // could be represented as a character file (/dev/null), which is the
421+ // case for runtimes like runc.
422+ switch fi .Mode () & os .ModeType {
423+ case 0 , os .ModeDevice | os .ModeCharDevice :
424+ return testFileReadAccess (path )
425+ case os .ModeDir :
418426 return testDirectoryReadAccess (path )
419427 }
420- return testFileReadAccess (path )
428+
429+ errAccess = fmt .Errorf ("cannot test read access for %q (mode %d)" , path , fi .Mode ())
430+ return false , errAccess
421431}
422432
423433func testDirectoryReadAccess (path string ) (readable bool , err error ) {
424- if files , err := ioutil .ReadDir (path ); err != nil || len (files ) == 0 {
425- // err from reading from a directory should not be considered as test failure,
426- // it just means that the test program successfully assessed that
427- // the directory is not readable.
434+ files , err := ioutil .ReadDir (path )
435+ if err == io .EOF || len (files ) == 0 {
436+ // Our validation/ tests only use non-empty directories for read-access
437+ // tests. So if we get an EOF on the first read, the runtime did
438+ // successfully block readability. So it should not be considered as test
439+ // failure, it just means that the test program successfully assessed
440+ // that the directory is not readable.
428441 return false , nil
429442 }
443+ if err != nil {
444+ return false , err
445+ }
430446 return true , nil
431447}
432448
@@ -455,14 +471,19 @@ func testWriteAccess(path string) (writable bool, err error) {
455471 return false , err
456472 }
457473
458- // In case of a directory, we should check its readability in a special way.
459- // In other files, we should not check its Mode explicitly, because the runtime
460- // spec does not mandate the type of masked files. It could be a regular file
461- // or a character file (/dev/null), which is the case for runtimes like runc.
462- if fi .IsDir () {
474+ // Check for writability in case of regular files, character device, or
475+ // directory. Although the runtime spec does not mandate the type of
476+ // masked files, we should check its Mode explicitly. A masked file
477+ // could be represented as a character file (/dev/null), which is the
478+ // case for runtimes like runc.
479+ switch fi .Mode () & os .ModeType {
480+ case 0 , os .ModeDevice | os .ModeCharDevice :
481+ return testFileWriteAccess (path )
482+ case os .ModeDir :
463483 return testDirectoryWriteAccess (path )
464484 }
465- return testFileWriteAccess (path )
485+ errAccess = fmt .Errorf ("cannot test write access for %q (mode %d)" , path , fi .Mode ())
486+ return false , errAccess
466487}
467488
468489func testDirectoryWriteAccess (path string ) (writable bool , err error ) {
@@ -874,7 +895,7 @@ func (c *complianceTester) validateMaskedPaths(spec *rspec.Spec) error {
874895
875896 for _ , maskedPath := range spec .Linux .MaskedPaths {
876897 readable , err := testReadAccess (maskedPath )
877- if err != nil && ! os .IsNotExist (err ) {
898+ if err != nil && ! os .IsNotExist (err ) && err != errAccess {
878899 return err
879900 }
880901 c .harness .Ok (! readable , fmt .Sprintf ("cannot read masked path %q" , maskedPath ))
@@ -917,15 +938,15 @@ func (c *complianceTester) validateROPaths(spec *rspec.Spec) error {
917938
918939 for i , path := range spec .Linux .ReadonlyPaths {
919940 readable , err := testReadAccess (path )
920- if err != nil {
941+ if err != nil && err != errAccess {
921942 return err
922943 }
923944 if ! readable {
924945 c .harness .Skip (1 , fmt .Sprintf ("%q (linux.readonlyPaths[%d]) is not readable" , path , i ))
925946 }
926947
927948 writable , err := testWriteAccess (path )
928- if err != nil && ! os .IsNotExist (err ) {
949+ if err != nil && ! os .IsNotExist (err ) && err != errAccess {
929950 return err
930951 }
931952 c .harness .Ok (! writable , fmt .Sprintf ("%q (linux.readonlyPaths[%d]) is not writable" , path , i ))
0 commit comments