Skip to content
Open
Show file tree
Hide file tree
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
34 changes: 18 additions & 16 deletions pkg/securitypolicy/framework.rego
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,17 @@ command_ok(command) if {
}
}

exec_process_matches(container) if {
some process in container.exec_processes
command_ok(process.command)
}

exec_process_signal_matches(container) if {
some process in container.exec_processes
command_ok(process.command)
signal_ok(process.signals)
}

# An env rule can be of two forms:
# {
# "pattern": "name=value",
Expand Down Expand Up @@ -933,8 +944,7 @@ exec_in_container := {"metadata": [updateMatches],
workingDirectory_ok(container.working_dir)
noNewPrivileges_ok(container.no_new_privileges)
user_ok(container.user)
some process in container.exec_processes
command_ok(process.command)
exec_process_matches(container)
]

count(possible_after_initial_containers) > 0
Expand Down Expand Up @@ -985,8 +995,7 @@ exec_in_container := {"metadata": [updateMatches],
# the narrowing process.
workingDirectory_ok(container.working_dir)
user_ok(container.user)
some process in container.exec_processes
command_ok(process.command)
exec_process_matches(container)
]

count(possible_after_initial_containers) > 0
Expand Down Expand Up @@ -1047,9 +1056,7 @@ signal_container_process := {"metadata": [updateMatches], "allowed": true} if {
not input.isInitProcess
containers := [container |
container := data.metadata.matches[input.containerID][_]
some process in container.exec_processes
command_ok(process.command)
signal_ok(process.signals)
exec_process_signal_matches(container)
]

count(containers) > 0
Expand Down Expand Up @@ -2037,8 +2044,7 @@ command_matches if {
command_matches if {
input.rule == "exec_in_container"
some container in data.metadata.matches[input.containerID]
some process in container.exec_processes
command_ok(process.command)
exec_process_matches(container)
}

command_matches if {
Expand Down Expand Up @@ -2126,8 +2132,7 @@ errors contains "missing required environment variable" if {
noNewPrivileges_ok(container.no_new_privileges)
user_ok(container.user)
workingDirectory_ok(container.working_dir)
some process in container.exec_processes
command_ok(process.command)
exec_process_matches(container)
]

count(possible_containers) > 0
Expand Down Expand Up @@ -2243,9 +2248,7 @@ signal_allowed if {
signal_allowed if {
not input.isInitProcess
some container in data.metadata.matches[input.containerID]
some process in container.exec_processes
command_ok(process.command)
signal_ok(process.signals)
exec_process_signal_matches(container)
}

errors contains "target isn't allowed to receive the signal" if {
Expand Down Expand Up @@ -2686,8 +2689,7 @@ errors contains "capabilities don't match" if {
workingDirectory_ok(container.working_dir)
noNewPrivileges_ok(container.no_new_privileges)
user_ok(container.user)
some process in container.exec_processes
command_ok(process.command)
exec_process_matches(container)
]

count(possible_after_initial_containers) > 0
Expand Down
74 changes: 74 additions & 0 deletions pkg/securitypolicy/regopolicy_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2656,6 +2656,80 @@ func Test_Rego_ExecInContainerPolicy(t *testing.T) {
}
}

func Test_Rego_ExecInContainerPolicy_DuplicatedCommand(t *testing.T) {
const execCount = 100

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be bigger? Other than that it looks fine to me.


constraints := generateConstraints(testRand, 1)
container := constraints.containers[0]
process := generateContainerExecProcess(testRand)
container.ExecProcesses = []containerExecProcess{process.clone(), process.clone()}

tc, err := setupRegoRunningContainerTest(constraints, false)
if err != nil {
t.Fatal(err)
}

running := tc.runningContainers[0]
capabilities := container.Capabilities.toExternal()
user := buildIDNameFromConfig(container.User.UserIDName, testRand)
groups := buildGroupIDNamesFromUser(container.User, testRand)

for i := 0; i < execCount; i++ {
_, _, _, err := tc.policy.EnforceExecInContainerPolicy(constraints.ctx, running.containerID, process.Command, running.envList, container.WorkingDir, container.NoNewPrivileges, user, groups, container.User.Umask, &capabilities)
if err != nil {
t.Fatalf("exec %d failed: %v", i+1, err)
}

rawMatches, err := tc.policy.rego.GetMetadataMapValue("matches", running.containerID)
if err != nil {
t.Fatalf("get matches metadata after exec %d: %v", i+1, err)
}
matches, ok := rawMatches.([]interface{})
if !ok {
t.Fatalf("matches metadata has type %T, want []interface{}", rawMatches)
}
if len(matches) != 1 {
t.Fatalf("matches metadata has %d entries after exec %d, want 1", len(matches), i+1)
}
}
}

func Test_Rego_SignalContainerProcessPolicy_DuplicatedCommand(t *testing.T) {
const signalCount = 100

constraints := generateConstraints(testRand, 1)
container := constraints.containers[0]
process := generateContainerExecProcess(testRand)
process.Signals = generateListOfSignals(testRand, 1, 4)
container.ExecProcesses = []containerExecProcess{process.clone(), process.clone()}

tc, err := setupRegoRunningContainerTest(constraints, false)
if err != nil {
t.Fatal(err)
}

running := tc.runningContainers[0]
signal := selectSignalFromSignals(testRand, process.Signals)

for i := 0; i < signalCount; i++ {
if err := tc.policy.EnforceSignalContainerProcessPolicy(constraints.ctx, running.containerID, signal, false, process.Command); err != nil {
t.Fatalf("signal %d failed: %v", i+1, err)
}

rawMatches, err := tc.policy.rego.GetMetadataMapValue("matches", running.containerID)
if err != nil {
t.Fatalf("get matches metadata after signal %d: %v", i+1, err)
}
matches, ok := rawMatches.([]interface{})
if !ok {
t.Fatalf("matches metadata has type %T, want []interface{}", rawMatches)
}
if len(matches) != 1 {
t.Fatalf("matches metadata has %d entries after signal %d, want 1", len(matches), i+1)
}
}
}

func Test_Rego_ExecInContainerPolicy_No_Matches(t *testing.T) {
f := func(p *generatedConstraints) bool {
tc, err := setupRegoRunningContainerTest(p, false)
Expand Down
76 changes: 76 additions & 0 deletions pkg/securitypolicy/regopolicy_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,82 @@ func Test_Rego_ExecInContainerPolicy_Windows(t *testing.T) {
}
}

func Test_Rego_ExecInContainerPolicy_DuplicatedCommand_Windows(t *testing.T) {
const execCount = 100

constraints := generateWindowsConstraints(testRand, 1)
container := constraints.containers[0]
process := generateWindowsContainerExecProcess(testRand)
container.ExecProcesses = []windowsContainerExecProcess{process, process}

tc, err := setupRegoRunningWindowsContainerTest(constraints)
if err != nil {
t.Fatal(err)
}

running := tc.runningContainers[0]
user := IDName{Name: container.User}
commandLine := []string{process.Command}

for i := 0; i < execCount; i++ {
_, _, _, err := tc.policy.EnforceExecInContainerPolicyV2(constraints.ctx, running.containerID, commandLine, running.envList, container.WorkingDir, user, nil)
if err != nil {
t.Fatalf("exec %d failed: %v", i+1, err)
}

rawMatches, err := tc.policy.rego.GetMetadataMapValue("matches", running.containerID)
if err != nil {
t.Fatalf("get matches metadata after exec %d: %v", i+1, err)
}
matches, ok := rawMatches.([]interface{})
if !ok {
t.Fatalf("matches metadata has type %T, want []interface{}", rawMatches)
}
if len(matches) != 1 {
t.Fatalf("matches metadata has %d entries after exec %d, want 1", len(matches), i+1)
}
}
}

func Test_Rego_SignalContainerProcessPolicy_DuplicatedCommand_Windows(t *testing.T) {
const signalCount = 100

constraints := generateWindowsConstraints(testRand, 1)
container := constraints.containers[0]
process := generateWindowsContainerExecProcess(testRand)
container.ExecProcesses = []windowsContainerExecProcess{process, process}

tc, err := setupRegoRunningWindowsContainerTest(constraints)
if err != nil {
t.Fatal(err)
}

running := tc.runningContainers[0]
signal := selectSignalFromWindowsSignals(testRand, process.Signals)
opts := &SignalContainerOptions{
WindowsSignal: signal,
WindowsCommand: []string{process.Command},
}

for i := 0; i < signalCount; i++ {
if err := tc.policy.EnforceSignalContainerProcessPolicyV2(constraints.ctx, running.containerID, opts); err != nil {
t.Fatalf("signal %d failed: %v", i+1, err)
}

rawMatches, err := tc.policy.rego.GetMetadataMapValue("matches", running.containerID)
if err != nil {
t.Fatalf("get matches metadata after signal %d: %v", i+1, err)
}
matches, ok := rawMatches.([]interface{})
if !ok {
t.Fatalf("matches metadata has type %T, want []interface{}", rawMatches)
}
if len(matches) != 1 {
t.Fatalf("matches metadata has %d entries after signal %d, want 1", len(matches), i+1)
}
}
}

func Test_Rego_ExecInContainerPolicy_No_Matches_Windows(t *testing.T) {
f := func(p *generatedWindowsConstraints) bool {
tc, err := setupRegoRunningWindowsContainerTest(p)
Expand Down
Loading