@@ -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
@@ -411,10 +415,37 @@ func testReadAccess(path string) (readable bool, err error) {
411415 if err != nil {
412416 return false , err
413417 }
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 :
415426 return testFileReadAccess (path )
427+ case os .ModeDir :
428+ return testDirectoryReadAccess (path )
416429 }
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
418449}
419450
420451func testFileReadAccess (path string ) (readable bool , err error ) {
@@ -441,12 +472,20 @@ func testWriteAccess(path string) (writable bool, err error) {
441472 if err != nil {
442473 return false , err
443474 }
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 :
447483 return testFileWriteAccess (path )
484+ case os .ModeDir :
485+ return testDirectoryWriteAccess (path )
448486 }
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
450489}
451490
452491func testDirectoryWriteAccess (path string ) (writable bool , err error ) {
@@ -858,7 +897,7 @@ func (c *complianceTester) validateMaskedPaths(spec *rspec.Spec) error {
858897
859898 for _ , maskedPath := range spec .Linux .MaskedPaths {
860899 readable , err := testReadAccess (maskedPath )
861- if err != nil && ! os .IsNotExist (err ) {
900+ if err != nil && ! os .IsNotExist (err ) && err != errAccess {
862901 return err
863902 }
864903 c .harness .Ok (! readable , fmt .Sprintf ("cannot read masked path %q" , maskedPath ))
@@ -901,15 +940,15 @@ func (c *complianceTester) validateROPaths(spec *rspec.Spec) error {
901940
902941 for i , path := range spec .Linux .ReadonlyPaths {
903942 readable , err := testReadAccess (path )
904- if err != nil {
943+ if err != nil && err != errAccess {
905944 return err
906945 }
907946 if ! readable {
908947 c .harness .Skip (1 , fmt .Sprintf ("%q (linux.readonlyPaths[%d]) is not readable" , path , i ))
909948 }
910949
911950 writable , err := testWriteAccess (path )
912- if err != nil && ! os .IsNotExist (err ) {
951+ if err != nil && ! os .IsNotExist (err ) && err != errAccess {
913952 return err
914953 }
915954 c .harness .Ok (! writable , fmt .Sprintf ("%q (linux.readonlyPaths[%d]) is not writable" , path , i ))
0 commit comments