diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java index cab0ca1e815380..0dd31c127ffe25 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java @@ -190,6 +190,7 @@ private Optional getCgroup(Spawn spawn, SpawnExecutionContext con VirtualCGroup cgroup = null; long memoryLimit = sandboxOptions.memoryLimitMb * 1024L * 1024L; float cpuLimit = sandboxOptions.cpuLimit; + boolean requiresNetwork = false; if (sandboxOptions.executionInfoLimit) { ExecutionRequirements.ParseableRequirement requirement = ExecutionRequirements.RESOURCES; @@ -198,7 +199,9 @@ private Optional getCgroup(Spawn spawn, SpawnExecutionContext con requirement = ExecutionRequirements.RESOURCES; String name = null; Float value = null; - + if (tag.equals(ExecutionRequirements.REQUIRES_NETWORK)) { + requiresNetwork = true; + } String extras = requirement.parseIfMatches(tag); if (extras != null) { int index = extras.indexOf(":"); @@ -259,6 +262,13 @@ private Optional getCgroup(Spawn spawn, SpawnExecutionContext con cgroup.cpu().setCpus(cpuLimit); } + if (!requiresNetwork && sandboxOptions.cgroupNetCls != 0) { + if (cgroup == null) { + cgroup = VirtualCGroup.getInstance(this.reporter).child(scope); + } + cgroup.netCls().setNetCls(sandboxOptions.cgroupNetCls); + } + cgroups.put(context.getId(), Optional.ofNullable(cgroup)); return cgroups.get(context.getId()); diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java index b40ef63e9f5094..48103949d9f0e2 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxOptions.java @@ -429,6 +429,16 @@ public ImmutableSet getInaccessiblePaths(FileSystem fs) { + " Requires cgroups v1 or v2 and permissions for the users to the cgroups dir.") public float cpuLimit; + @Option( + name = "experimental_sandbox_cgroup_net_cls", + defaultValue = "0", + documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY, + effectTags = {OptionEffectTag.EXECUTION}, + help = + "If set, any target not tagged with requires-network will run its actions " + + "inside a sandbox with the given netcls for filtering by iptables firewalls.") + public int cgroupNetCls; + @Option( name = "experimental_sandbox_execution_info_limit", defaultValue = "false", diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/Controller.java b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/Controller.java index f40387001e5648..26cc8a8c305d6a 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/Controller.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/Controller.java @@ -59,4 +59,8 @@ interface Cpu extends Controller { interface CpuAcct extends Controller { long getUsage() throws IOException; } + interface NetCls extends Controller { + void setNetCls(int netCls) throws IOException; + int getNetCls() throws IOException; + } } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/VirtualCGroup.java b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/VirtualCGroup.java index d641f69704fbb7..205dbd93215f1c 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/VirtualCGroup.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/VirtualCGroup.java @@ -13,8 +13,10 @@ import com.google.devtools.build.lib.sandbox.cgroups.v1.LegacyCpu; import com.google.devtools.build.lib.sandbox.cgroups.v1.LegacyCpuAcct; import com.google.devtools.build.lib.sandbox.cgroups.v1.LegacyMemory; +import com.google.devtools.build.lib.sandbox.cgroups.v1.LegacyNetCls; import com.google.devtools.build.lib.sandbox.cgroups.v2.UnifiedCpu; import com.google.devtools.build.lib.sandbox.cgroups.v2.UnifiedMemory; +import com.google.devtools.build.lib.sandbox.cgroups.v2.UnifiedNetCls; import javax.annotation.Nullable; import java.io.BufferedReader; @@ -53,6 +55,8 @@ public abstract class VirtualCGroup { public abstract Controller.Memory memory(); @Nullable public abstract Controller.CpuAcct cpuacct(); + @Nullable + public abstract Controller.NetCls netCls(); public abstract ImmutableSet paths(); @@ -111,6 +115,7 @@ static VirtualCGroup create(File procMounts, File procCgroup, EventHandler repor Controller.Memory memory = null; Controller.Cpu cpu = null; Controller.CpuAcct cpuacct = null; + Controller.NetCls netCls = null; ImmutableSet.Builder paths = ImmutableSet.builder(); for (Mount m: mounts) { @@ -157,6 +162,11 @@ static VirtualCGroup create(File procMounts, File procCgroup, EventHandler repor logger.atInfo().log("Found cgroup v2 cpu controller at %s", cgroup); cpu = new UnifiedCpu(cgroup); break; + case "net_cls": + if (netCls != null) continue; + logger.atInfo().log("Found cgroup v2 net_cls controller at %s", cgroup); + netCls = new UnifiedNetCls(cgroup); + break; } } } else { @@ -188,6 +198,11 @@ static VirtualCGroup create(File procMounts, File procCgroup, EventHandler repor logger.atInfo().log("Found cgroup v1 cpuacct controller at %s", cgroup); cpuacct = new LegacyCpuAcct(cgroup); break; + case "net_cls": + if (netCls != null) continue; + logger.atInfo().log("Found cgroup v1 net_cls controller at %s", cgroup); + netCls = new LegacyNetCls(cgroup); + break; } } } @@ -195,7 +210,8 @@ static VirtualCGroup create(File procMounts, File procCgroup, EventHandler repor cpu = cpu != null ? cpu : Controller.getDefault(Controller.Cpu.class); memory = memory != null ? memory : Controller.getDefault(Controller.Memory.class); - VirtualCGroup vcgroup = new AutoValue_VirtualCGroup(cpu, memory, cpuacct, paths.build()); + netCls = netCls != null ? netCls : Controller.getDefault(Controller.NetCls.class); + VirtualCGroup vcgroup = new AutoValue_VirtualCGroup(cpu, memory, cpuacct, netCls, paths.build()); Runtime.getRuntime().addShutdownHook(new Thread(() -> vcgroup.delete())); return vcgroup; } @@ -208,6 +224,7 @@ public void delete() { public VirtualCGroup child(String name) throws IOException { Controller.Cpu cpu = Controller.getDefault(Controller.Cpu.class); Controller.Memory memory = Controller.getDefault(Controller.Memory.class); + Controller.NetCls netCls = null; Controller.CpuAcct cpuacct = null; ImmutableSet.Builder paths = ImmutableSet.builder(); if (memory() != null && memory().getPath() != null) { @@ -232,7 +249,14 @@ public VirtualCGroup child(String name) throws IOException { cpuacct = new LegacyCpuAcct(cgroup); paths.add(cgroup); } - VirtualCGroup child = new AutoValue_VirtualCGroup(cpu, memory, cpuacct, paths.build()); + if (netCls() != null && netCls().getPath() != null) { + copyControllersToSubtree(netCls().getPath()); + Path cgroup = netCls().getPath().resolve(name); + cgroup.toFile().mkdirs(); + netCls = new LegacyNetCls(cgroup); + paths.add(cgroup); + } + VirtualCGroup child = new AutoValue_VirtualCGroup(cpu, memory, cpuacct, netCls, paths.build()); this.children.add(child); return child; } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v1/LegacyNetCls.java b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v1/LegacyNetCls.java new file mode 100644 index 00000000000000..7ac4a05d356a34 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v1/LegacyNetCls.java @@ -0,0 +1,35 @@ +package com.google.devtools.build.lib.sandbox.cgroups.v1; + +import com.google.devtools.build.lib.sandbox.cgroups.Controller; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class LegacyNetCls implements Controller.NetCls { + private final Path path; + + @Override + public Path getPath() throws IOException { + return path; + } + + public LegacyNetCls(Path path) { + this.path = path; + } + + @Override + public Path statFile() throws IOException { + return path.resolve("net_cls.stat"); + } + + @Override + public void setNetCls(int netCls) throws IOException { + Files.writeString(path.resolve("net_cls.classid"), Integer.toString(netCls)); + } + + @Override + public int getNetCls() throws IOException { + return Integer.parseInt(Files.readString(path.resolve("net_cls.classid")).trim()); + } +} \ No newline at end of file diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v2/UnifiedNetCls.java b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v2/UnifiedNetCls.java new file mode 100644 index 00000000000000..73f2384bf9699b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v2/UnifiedNetCls.java @@ -0,0 +1,35 @@ +package com.google.devtools.build.lib.sandbox.cgroups.v2; + +import com.google.devtools.build.lib.sandbox.cgroups.Controller; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class UnifiedNetCls implements Controller.NetCls { + private final Path path; + + public UnifiedNetCls(Path path) throws IOException { + this.path = path; + } + + @Override + public Path getPath() { + return path; + } + + @Override + public Path statFile() throws IOException { + return path.resolve("net_cls.stat"); + } + + @Override + public void setNetCls(int netCls) throws IOException { + Files.writeString(path.resolve("net_cls.classid"), Integer.toString(netCls)); + } + + @Override + public int getNetCls() throws IOException { + return Integer.parseInt(Files.readString(path.resolve("net_cls.classid")).trim()); + } +}