diff --git a/src/tools/genpolicy/genpolicy-settings.json b/src/tools/genpolicy/genpolicy-settings.json index 75a4463cc1..b00e200f6b 100644 --- a/src/tools/genpolicy/genpolicy-settings.json +++ b/src/tools/genpolicy/genpolicy-settings.json @@ -347,6 +347,14 @@ "^127\\.(?:[0-9]{1,3}\\.){2}[0-9]{1,3}$" ] }, + "AddARPNeighborsRequest": { + "forbidden_device_names": [ + "lo" + ], + "forbidden_cidrs_regex": [ + "^127\\.(?:[0-9]{1,3}\\.){2}[0-9]{1,3}$" + ] + }, "CloseStdinRequest": false, "ReadStreamRequest": false, "UpdateEphemeralMountsRequest": false, diff --git a/src/tools/genpolicy/rules.rego b/src/tools/genpolicy/rules.rego index b402b1c5ec..721a6072ac 100644 --- a/src/tools/genpolicy/rules.rego +++ b/src/tools/genpolicy/rules.rego @@ -1400,6 +1400,25 @@ UpdateInterfaceRequest if { print("UpdateInterfaceRequest: true") } +AddARPNeighborsRequest if { + p_defaults := policy_data.request_defaults.AddARPNeighborsRequest + print("AddARPNeighborsRequest: policy =", p_defaults) + + every i_neigh in input.neighbors.ARPNeighbors { + print("AddARPNeighborsRequest: i_neigh =", i_neigh) + + not i_neigh.device in p_defaults.forbidden_device_names + i_neigh.toIPAddress.mask == "" + every p_cidr in p_defaults.forbidden_cidrs_regex { + not regex.match(p_cidr, i_neigh.toIPAddress.address) + } + i_neigh.state == 128 + bits.or(i_neigh.flags, 136) == 136 + } + + print("AddARPNeighborsRequest: true") +} + CloseStdinRequest if { policy_data.request_defaults.CloseStdinRequest == true } diff --git a/src/tools/genpolicy/src/policy.rs b/src/tools/genpolicy/src/policy.rs index d029acd0a2..f899a24bb2 100644 --- a/src/tools/genpolicy/src/policy.rs +++ b/src/tools/genpolicy/src/policy.rs @@ -355,6 +355,16 @@ pub struct UpdateInterfaceRequestDefaults { forbidden_hw_addrs: Vec, } +/// UpdateInterfaceRequest settings from genpolicy-settings.json. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AddARPNeighborsRequestDefaults { + /// Explicitly blocked interface names. Intent is to block changes to loopback interface. + forbidden_device_names: Vec, + /// Explicitly blocked IP address ranges. + /// Should include loopback addresses and other CIDRs that should not be routed outside the VM. + forbidden_cidrs_regex: Vec, +} + /// Settings specific to each kata agent endpoint, loaded from /// genpolicy-settings.json. #[derive(Clone, Debug, Serialize, Deserialize)] @@ -374,6 +384,9 @@ pub struct RequestDefaults { /// Allow the host to configure only used raw_flags and reject names/mac addresses of the loopback. pub UpdateInterfaceRequest: UpdateInterfaceRequestDefaults, + /// Allow the host to configure only used raw_flags and reject names/mac addresses of the loopback. + pub AddARPNeighborsRequest: AddARPNeighborsRequestDefaults, + /// Allow the Host to close stdin for a container. Typically used with WriteStreamRequest. pub CloseStdinRequest: bool, diff --git a/src/tools/genpolicy/tests/policy/main.rs b/src/tools/genpolicy/tests/policy/main.rs index 4f5fe0c83f..b494e39259 100644 --- a/src/tools/genpolicy/tests/policy/main.rs +++ b/src/tools/genpolicy/tests/policy/main.rs @@ -13,8 +13,8 @@ mod tests { use std::str; use protocols::agent::{ - CopyFileRequest, CreateContainerRequest, CreateSandboxRequest, ExecProcessRequest, - RemoveContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest, + AddARPNeighborsRequest, CopyFileRequest, CreateContainerRequest, CreateSandboxRequest, + ExecProcessRequest, RemoveContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest, }; use serde::{Deserialize, Serialize}; @@ -32,6 +32,7 @@ mod tests { RemoveContainer(RemoveContainerRequest), UpdateInterface(UpdateInterfaceRequest), UpdateRoutes(UpdateRoutesRequest), + AddARPNeighbors(AddARPNeighborsRequest), } impl Display for TestRequest { @@ -44,6 +45,7 @@ mod tests { TestRequest::RemoveContainer(_) => write!(f, "RemoveContainerRequest"), TestRequest::UpdateInterface(_) => write!(f, "UpdateInterfaceRequest"), TestRequest::UpdateRoutes(_) => write!(f, "UpdateRoutesRequest"), + TestRequest::AddARPNeighbors(_) => write!(f, "AddARPNeighborsRequest"), } } } @@ -240,6 +242,11 @@ mod tests { runtests("updateinterface").await; } + #[tokio::test] + async fn test_add_arp_neighbors() { + runtests("addarpneighbors").await; + } + #[tokio::test] async fn test_create_container_network_namespace() { runtests("createcontainer/network_namespace").await; diff --git a/src/tools/genpolicy/tests/policy/testdata/addarpneighbors/pod.yaml b/src/tools/genpolicy/tests/policy/testdata/addarpneighbors/pod.yaml new file mode 100644 index 0000000000..7ac6554ed9 --- /dev/null +++ b/src/tools/genpolicy/tests/policy/testdata/addarpneighbors/pod.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Pod +metadata: + name: dummy +spec: + runtimeClassName: kata-cc-isolation + containers: + - name: dummy + image: registry.k8s.io/pause:3.6@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db diff --git a/src/tools/genpolicy/tests/policy/testdata/addarpneighbors/testcases.json b/src/tools/genpolicy/tests/policy/testdata/addarpneighbors/testcases.json new file mode 100644 index 0000000000..d607d6f2d1 --- /dev/null +++ b/src/tools/genpolicy/tests/policy/testdata/addarpneighbors/testcases.json @@ -0,0 +1,156 @@ +[ + { + "description": "compliant neighbors", + "allowed": true, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "10.0.0.1", + "mask": "" + }, + "device": "eth0", + "lladdr": "00:00:5e:00:53:01", + "state": 128, + "flags": 0 + } + ] + } + } + }, + { + "description": "allowed flags: NTF_PROXY", + "allowed": true, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "10.0.0.1", + "mask": "" + }, + "device": "eth0", + "lladdr": "00:00:5e:00:53:01", + "state": 128, + "flags": 8 + } + ] + } + } + }, + { + "description": "allowed flags: NTF_ROUTER", + "allowed": true, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "10.0.0.1", + "mask": "" + }, + "device": "eth0", + "lladdr": "00:00:5e:00:53:01", + "state": 128, + "flags": 128 + } + ] + } + } + }, + { + "description": "bad interface", + "allowed": false, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "10.0.0.1", + "mask": "" + }, + "device": "lo", + "lladdr": "00:00:5e:00:53:01", + "state": 128, + "flags": 0 + } + ] + } + } + }, + { + "description": "bad IP", + "allowed": false, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "127.1.2.3", + "mask": "" + }, + "device": "eth0", + "lladdr": "00:00:5e:00:53:01", + "state": 128, + "flags": 0 + } + ] + } + } + }, + { + "description": "bad state", + "allowed": false, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "10.0.0.1", + "mask": "" + }, + "device": "eth0", + "lladdr": "00:00:5e:00:53:01", + "state": 0, + "flags": 0 + } + ] + } + } + }, + { + "description": "bad flags", + "allowed": false, + "request": { + "type": "AddARPNeighbors", + "neighbors": { + "ARPNeighbors": [ + { + "toIPAddress": { + "family": 0, + "address": "10.0.0.1", + "mask": "" + }, + "device": "eth0", + "lladdr": "00:00:5e:00:53:01", + "state": 128, + "flags": 5 + } + ] + } + } + } +]