Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 141 additions & 7 deletions validation/linux_readonly_paths.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
package main

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/opencontainers/runtime-tools/validation/util"
"golang.org/x/sys/unix"
)

func main() {
func checkReadonlyPaths() error {
g, err := util.GetDefaultGenerator()
if err != nil {
util.Fatal(err)
return err
}
g.AddLinuxReadonlyPaths("/readonly-dir")
g.AddLinuxReadonlyPaths("/readonly-file")

readonlyDir := "readonly-dir"
readonlySubDir := "readonly-subdir"
readonlyFile := "readonly-file"

readonlyDirTop := filepath.Join("/", readonlyDir)
readonlyFileTop := filepath.Join("/", readonlyFile)

readonlyDirSub := filepath.Join(readonlyDirTop, readonlySubDir)
readonlyFileSub := filepath.Join(readonlyDirTop, readonlyFile)
readonlyFileSubSub := filepath.Join(readonlyDirSub, readonlyFile)

g.AddLinuxReadonlyPaths(readonlyDirTop)
g.AddLinuxReadonlyPaths(readonlyFileTop)
g.AddLinuxReadonlyPaths(readonlyDirSub)
g.AddLinuxReadonlyPaths(readonlyFileSub)
g.AddLinuxReadonlyPaths(readonlyFileSubSub)
err = util.RuntimeInsideValidate(g, func(path string) error {
testDir := filepath.Join(path, "readonly-dir")
testDir := filepath.Join(path, readonlyDirSub)
err = os.MkdirAll(testDir, 0777)
if err != nil {
return err
Expand All @@ -28,13 +45,130 @@ func main() {
}
defer os.Remove(tmpfile.Name())

testFile := filepath.Join(path, "readonly-file")

// runtimetest cannot check the readability of empty files, so
// write something.
testSubSubFile := filepath.Join(path, readonlyFileSubSub)
if err := ioutil.WriteFile(testSubSubFile, []byte("immutable"), 0777); err != nil {
return err
}

testSubFile := filepath.Join(path, readonlyFileSub)
if err := ioutil.WriteFile(testSubFile, []byte("immutable"), 0777); err != nil {
return err
}

testFile := filepath.Join(path, readonlyFile)
return ioutil.WriteFile(testFile, []byte("immutable"), 0777)
})
return err
}

func checkReadonlyRelPaths() error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
}

// Deliberately set a relative path to be read-only, and expect an error
readonlyRelPath := "readonly-relpath"

g.AddLinuxReadonlyPaths(readonlyRelPath)
err = util.RuntimeInsideValidate(g, func(path string) error {
testFile := filepath.Join(path, readonlyRelPath)
if _, err := os.Stat(testFile); err != nil && os.IsNotExist(err) {
return err
}

return nil
})
if err != nil {
return nil
}
return fmt.Errorf("expected: err != nil, actual: err == nil")
}

func checkReadonlySymlinks() error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
}

// Deliberately create a read-only symlink that points an invalid file,
// and expect an error.
readonlySymlink := "/readonly-symlink"

g.AddLinuxReadonlyPaths(readonlySymlink)
err = util.RuntimeInsideValidate(g, func(path string) error {
testFile := filepath.Join(path, readonlySymlink)
// ln -s .. /readonly-symlink ; readlink -f /readonly-symlink; ls -L /readonly-symlink
if err := os.Symlink("../readonly-symlink", testFile); err != nil {
return err
}
rPath, errR := os.Readlink(testFile)
if errR != nil {
return errR
}
_, errS := os.Stat(rPath)
if errS != nil && os.IsNotExist(errS) {
return errS
}

return nil
})
if err != nil {
return nil
}
return fmt.Errorf("expected: err != nil, actual: err == nil")
}

func checkReadonlyDeviceNodes(mode uint32) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
}

readonlyDevice := "/readonly-device"

g.AddLinuxReadonlyPaths(readonlyDevice)
return util.RuntimeInsideValidate(g, func(path string) error {
testFile := filepath.Join(path, readonlyDevice)

if err := unix.Mknod(testFile, mode, 0); err != nil {
return err
}

if _, err := os.Stat(testFile); err != nil && os.IsNotExist(err) {
return err
}

return nil
})
}

func main() {
if err := checkReadonlyPaths(); err != nil {
util.Fatal(err)
}

if err := checkReadonlyRelPaths(); err != nil {
util.Fatal(err)
}

if err := checkReadonlySymlinks(); err != nil {
util.Fatal(err)
}

// test creation of different type of devices, i.e. block device,
// character device, and FIFO.
modes := []uint32{
unix.S_IFBLK | 0666,
unix.S_IFCHR | 0666,
unix.S_IFIFO | 0666,
}

for _, m := range modes {
if err := checkReadonlyDeviceNodes(m); err != nil {
util.Fatal(err)
}
}
}