From f971ef977233c77bc2d66b72557a16fe146d2642 Mon Sep 17 00:00:00 2001 From: Avik Rao Date: Fri, 7 Mar 2025 08:28:52 +0000 Subject: [PATCH 1/3] Add support for custom network classifier cgroup in sandbox --- .../sandbox/LinuxSandboxedSpawnRunner.java | 12 ++++++- .../build/lib/sandbox/SandboxOptions.java | 10 ++++++ .../build/lib/sandbox/cgroups/Controller.java | 4 +++ .../lib/sandbox/cgroups/VirtualCGroup.java | 26 ++++++++++++-- .../lib/sandbox/cgroups/v1/LegacyNetCls.java | 35 +++++++++++++++++++ .../lib/sandbox/cgroups/v2/UnifiedNetCls.java | 35 +++++++++++++++++++ 6 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v1/LegacyNetCls.java create mode 100644 src/main/java/com/google/devtools/build/lib/sandbox/cgroups/v2/UnifiedNetCls.java 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..40abbfbc423ba6 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..d205c28922ad37 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,7 @@ public abstract class VirtualCGroup { public abstract Controller.Memory memory(); @Nullable public abstract Controller.CpuAcct cpuacct(); + public abstract Controller.NetCls netCls(); public abstract ImmutableSet paths(); @@ -111,6 +114,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 +161,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 +197,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 +209,7 @@ 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()); + VirtualCGroup vcgroup = new AutoValue_VirtualCGroup(cpu, memory, cpuacct, netCls, paths.build()); Runtime.getRuntime().addShutdownHook(new Thread(() -> vcgroup.delete())); return vcgroup; } @@ -209,6 +223,7 @@ public VirtualCGroup child(String name) throws IOException { Controller.Cpu cpu = Controller.getDefault(Controller.Cpu.class); Controller.Memory memory = Controller.getDefault(Controller.Memory.class); Controller.CpuAcct cpuacct = null; + Controller.NetCls netCls = null; ImmutableSet.Builder paths = ImmutableSet.builder(); if (memory() != null && memory().getPath() != null) { copyControllersToSubtree(memory().getPath()); @@ -232,7 +247,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 = netCls().isLegacy() ? new LegacyNetCls(cgroup) : null; + 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..9c82627e2e9834 --- /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; + + public LegacyNetCls(Path path) { + this.path = path; + } + + @Override + public Path getPath() throws IOException { + 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()); + } +} 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()); + } +} From 909116ac46909a23f165533e6fe72cea55dd788f Mon Sep 17 00:00:00 2001 From: Avik Rao Date: Fri, 7 Mar 2025 21:04:27 +0000 Subject: [PATCH 2/3] Change nulls --- .../build/lib/sandbox/cgroups/VirtualCGroup.java | 6 ++++-- .../build/lib/sandbox/cgroups/v1/LegacyNetCls.java | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) 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 d205c28922ad37..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 @@ -55,6 +55,7 @@ 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(); @@ -209,6 +210,7 @@ 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); + 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; @@ -222,8 +224,8 @@ 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.CpuAcct cpuacct = null; Controller.NetCls netCls = null; + Controller.CpuAcct cpuacct = null; ImmutableSet.Builder paths = ImmutableSet.builder(); if (memory() != null && memory().getPath() != null) { copyControllersToSubtree(memory().getPath()); @@ -251,7 +253,7 @@ public VirtualCGroup child(String name) throws IOException { copyControllersToSubtree(netCls().getPath()); Path cgroup = netCls().getPath().resolve(name); cgroup.toFile().mkdirs(); - netCls = netCls().isLegacy() ? new LegacyNetCls(cgroup) : null; + netCls = new LegacyNetCls(cgroup); paths.add(cgroup); } VirtualCGroup child = new AutoValue_VirtualCGroup(cpu, memory, cpuacct, netCls, paths.build()); 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 index 9c82627e2e9834..7ac4a05d356a34 100644 --- 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 @@ -1,23 +1,23 @@ 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; - public LegacyNetCls(Path path) { - this.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"); @@ -32,4 +32,4 @@ public void setNetCls(int netCls) throws IOException { public int getNetCls() throws IOException { return Integer.parseInt(Files.readString(path.resolve("net_cls.classid")).trim()); } -} +} \ No newline at end of file From 3378a97c6f1bda82cbbed37ca0d9537c1f68a0ab Mon Sep 17 00:00:00 2001 From: Avik Rao Date: Sun, 9 Mar 2025 03:13:53 +0000 Subject: [PATCH 3/3] Fix tag requirement --- .../devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 40abbfbc423ba6..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 @@ -262,7 +262,7 @@ private Optional getCgroup(Spawn spawn, SpawnExecutionContext con cgroup.cpu().setCpus(cpuLimit); } - if (requiresNetwork && sandboxOptions.cgroupNetCls != 0) { + if (!requiresNetwork && sandboxOptions.cgroupNetCls != 0) { if (cgroup == null) { cgroup = VirtualCGroup.getInstance(this.reporter).child(scope); }