blob: 7cb576a2451b3ede097c335eee89b098a7c60c6d [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package security
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"syscall"
"chromiumos/tast/local/bundles/cros/security/filesetup"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: StatefulPartitionHardening,
Desc: "Tests access behavior of symlinks and FIFOs",
Contacts: []string{
"jorgelo@chromium.org", // Security team
"ejcaruso@chromium.org", // Tast port author
"chromeos-security@google.com",
},
Attr: []string{"group:mainline"},
})
}
func StatefulPartitionHardening(ctx context.Context, s *testing.State) {
generateTempFilename := func(parent, fileType string) string {
template := fmt.Sprintf("tast.security.StatefulPartitionHardening.%v.", fileType)
tempFile, err := ioutil.TempFile(parent, template)
if err != nil {
s.Fatalf("Could not generate temp %v in %v", fileType, parent)
}
if err := tempFile.Close(); err != nil {
s.Errorf("Failed to close %v: %v", tempFile.Name(), err)
}
if err := os.Remove(tempFile.Name()); err != nil {
s.Errorf("Failed to remove %v: %v", tempFile.Name(), err)
}
return tempFile.Name()
}
expectAccess := func(path string, expected bool) {
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_NONBLOCK, 0777)
if err == nil {
if err := syscall.Close(fd); err != nil {
s.Errorf("Failed to close FD %v: %v", fd, err)
}
if !expected {
s.Errorf("Opening %v unexpectedly succeeded", path)
}
} else if expected {
s.Errorf("Opening %v failed: %v", path, err)
}
}
expectFIFOAccess := func(parent string, expected bool) {
path := generateTempFilename(parent, "fifo")
if err := syscall.Mkfifo(path, 0666); err != nil {
s.Fatalf("Failed to create FIFO at %v: %v", path, err)
}
defer os.Remove(path)
expectAccess(path, expected)
}
expectSymlinkAccess := func(parent string, expected bool) {
path := generateTempFilename(parent, "symlink")
filesetup.CreateSymlink("/dev/null", path, os.Getuid())
defer os.Remove(path)
expectAccess(path, expected)
path = generateTempFilename(parent, "symlink")
filesetup.CreateSymlink("/dev", path, os.Getuid())
defer os.Remove(path)
expectAccess(filepath.Join(path, "null"), expected)
}
var blockedLocations = []string{
"/mnt/stateful_partition",
"/var",
}
var allowedLocations = []string{
"/tmp",
}
var symlinkExceptions = []string{
"/var/cache/echo",
"/var/cache/vpd",
"/var/lib/timezone",
"/var/log",
}
// We also need to make sure that the restrictions apply to subdirectories, unless they are
// treated specially (like the symlinkExceptions).
for _, locs := range []*[]string{&blockedLocations, &allowedLocations, &symlinkExceptions} {
for _, loc := range *locs {
path, err := ioutil.TempDir(loc, "tast.security.StatefulPartitionHardening.")
if err != nil {
s.Fatal("Failed to create temp directory in ", loc)
}
defer os.RemoveAll(path)
*locs = append(*locs, path)
}
}
for _, loc := range blockedLocations {
s.Log("Checking that symlinks and FIFOs are blocked in ", loc)
expectSymlinkAccess(loc, false)
expectFIFOAccess(loc, false)
}
for _, loc := range allowedLocations {
s.Log("Checking that symlinks and FIFOs are allowed in ", loc)
expectSymlinkAccess(loc, true)
expectFIFOAccess(loc, true)
}
for _, loc := range symlinkExceptions {
s.Log("Checking that symlinks are allowed in ", loc)
expectSymlinkAccess(loc, true)
}
}