blob: a6a000b968439060277c641577ce09d1fd50ee61 [file] [log] [blame]
// Copyright 2019 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 (
"bufio"
"context"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"time"
upstartcommon "chromiumos/tast/common/upstart"
"chromiumos/tast/errors"
"chromiumos/tast/local/upstart"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: SELinuxAuditBasic,
Desc: "Checks SELinux audit works as intended",
Contacts: []string{"fqj@chromium.org", "jorgelo@chromium.org", "chromeos-security@google.com"},
SoftwareDeps: []string{"selinux"},
Attr: []string{"group:mainline"},
})
}
func SELinuxAuditBasic(ctx context.Context, s *testing.State) {
// Directory name should keep in sync with platform2/sepolicy/policy/chromeos/dev/cros_ssh_session
const markerDirName = "cros_selinux_audit_basic_test"
s.Log("Waiting for auditd job to be running")
if err := upstart.WaitForJobStatus(ctx, "auditd", upstartcommon.StartGoal, upstartcommon.RunningState, upstart.RejectWrongGoal, 30*time.Second); err != nil {
s.Fatal("Failed waiting for auditd to start: ", err)
}
hasLineMatch := func(r io.Reader, re *regexp.Regexp) (bool, error) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Text()
if re.MatchString(line) {
return true, nil
}
}
return false, scanner.Err()
}
// Generate an audit event by creating a file inside markerDirectory
td, err := ioutil.TempDir("/tmp", "tast.security.SELinuxAuditBasic.")
if err != nil {
s.Fatal("Failed to create temporary directory for testing: ", err)
}
defer os.RemoveAll(td)
markerDirectory := filepath.Join(td, markerDirName)
if err := os.Mkdir(markerDirectory, 0700); err != nil {
s.Fatal("Failed to create marker directory for testing: ", err)
}
f, err := ioutil.TempFile(markerDirectory, "audit-marker-")
if err != nil {
s.Fatal("Failed to create marker file: ", err)
}
fileName := path.Base(f.Name())
f.Close()
// Checks log can be found in audit.log for file name.
// TODO(yoshiki): Replace this with croslog command.
f, err = os.Open("/var/log/audit/audit.log")
if err != nil {
s.Fatal("Failed to open audit.log: ", err)
}
defer f.Close()
// Try reading multiple times, since there is a possibility of delay in
// auditd's wriging to the log file.
const (
retryTimeout = 10 * time.Second
retryInterval = 1 * time.Second
)
wantedLine, err := regexp.Compile("granted.*" + fileName)
if err != nil {
s.Fatal("Regexp compile error. The path of temporary file may be wrong: ", err)
}
if err = testing.Poll(ctx, func(ctx context.Context) error {
if match, err := hasLineMatch(f, wantedLine); err != nil {
// Failed: something is wrong in reading the log file.
return testing.PollBreak(errors.Wrap(err, "failed to read audit.log"))
} else if !match {
// Retry after sleep.
return errors.New("expected audit message is not found in audit.log")
}
// Succeeded: the log entry is found.
return nil
}, &testing.PollOptions{Timeout: retryTimeout, Interval: retryInterval}); err != nil {
// Failed: the retry count exceeded.
s.Error("Expected audit message in audit.log but not found: ", err)
}
}