[projects/pld-builder.new] Use unshare for blocking network access instead of hack with resolv.conf blocked via acl.
arekm
arekm at pld-linux.org
Mon Mar 16 23:10:33 CET 2026
commit a3e592a91a9c7392e33ad3cab29e24d7b1bc5cbe
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Mon Mar 16 21:09:01 2026 +0100
Use unshare for blocking network access instead of hack with resolv.conf blocked via acl.
PLD_Builder/build.py | 2 +-
PLD_Builder/chroot.py | 15 +++++++++------
PLD_Builder/config.py | 1 +
PLD_Builder/install.py | 7 ++++---
PLD_Builder/rpm_builder.py | 3 +--
PLD_Builder/srpm_builder.py | 6 +++---
bin/chroot-nonet | 5 +++++
config/builder.conf.dist | 4 ++++
doc/README.bin-builder | 8 +++++++-
doc/user-manual.txt | 15 ++++++++++-----
10 files changed, 45 insertions(+), 21 deletions(-)
---
diff --git a/PLD_Builder/build.py b/PLD_Builder/build.py
index fecbf97..22b4255 100644
--- a/PLD_Builder/build.py
+++ b/PLD_Builder/build.py
@@ -47,7 +47,7 @@ def run_command(batch):
user = "root"
if "as-builder" in batch.command_flags:
user = None
- return chroot.run(command, logfile = batch.logfile, user = user)
+ return chroot.run(command, logfile = batch.logfile, user = user, nonet=False)
def build_all(r, build_fnc):
status.email = r.requester_email
diff --git a/PLD_Builder/chroot.py b/PLD_Builder/chroot.py
index e214ae1..1643daa 100644
--- a/PLD_Builder/chroot.py
+++ b/PLD_Builder/chroot.py
@@ -12,11 +12,14 @@ from config import config
def quote(cmd):
return re.sub("([\"\\\\$`])", r"\\\1", cmd)
-def command(cmd, user = None, nostdin=""):
+def command(cmd, user = None, nostdin="", nonet=True):
if user == None:
user = config.builder_user
if nostdin:
nostdin = "exec < /dev/null; "
+ if nonet:
+ return "%s sudo unshare -n %s %s su - %s -c \"export LC_ALL=C; %s %s\"" \
+ % (config.sudo_chroot_wrapper, config.nonet_chroot, config.chroot, user, nostdin, quote(cmd))
return "%s sudo chroot %s su - %s -c \"export LC_ALL=C; %s %s\"" \
% (config.sudo_chroot_wrapper, config.chroot, user, nostdin, quote(cmd))
@@ -24,17 +27,17 @@ def command_sh(cmd):
return "%s sudo chroot %s /bin/sh -c \"export LC_ALL=C; exec < /dev/null; %s\"" \
% (config.sudo_chroot_wrapper, config.chroot, quote(cmd))
-def popen(cmd, user = "builder", mode = "r", encoding = None):
+def popen(cmd, user = "builder", mode = "r", encoding = None, nonet=True):
if mode == "r":
- p = subprocess.Popen(command(cmd, user), shell=True, stdout=subprocess.PIPE, close_fds=True, encoding=encoding)
+ p = subprocess.Popen(command(cmd, user, nonet=nonet), shell=True, stdout=subprocess.PIPE, close_fds=True, encoding=encoding)
f = p.stdout
else:
- p = subprocess.Popen(command(cmd, user), shell=True, stdin=subprocess.PIPE, close_fds=True, encoding=encoding)
+ p = subprocess.Popen(command(cmd, user, nonet=nonet), shell=True, stdin=subprocess.PIPE, close_fds=True, encoding=encoding)
f = p.stdin
return f
-def run(cmd, user = "builder", logfile = None, logstdout = None):
- c = command(cmd, user, nostdin=True)
+def run(cmd, user = "builder", logfile = None, logstdout = None, nonet=True):
+ c = command(cmd, user, nostdin=True, nonet=nonet)
if logfile != None:
if logstdout != None:
c = "%s 2>&1 | /usr/bin/tee -a %s" % (c, logfile)
diff --git a/PLD_Builder/config.py b/PLD_Builder/config.py
index f9cba84..e107047 100644
--- a/PLD_Builder/config.py
+++ b/PLD_Builder/config.py
@@ -109,6 +109,7 @@ class Builder_Conf:
self.rpm_cache_dir = get("rpm_cache_dir", "/spools/ready")
self.builder_user = get("builder_user", "builder")
self.sudo_chroot_wrapper = get("sudo_chroot_wrapper", "")
+ self.nonet_chroot = get("nonet_chroot", "/usr/local/bin/chroot-nonet")
# Available php versions in the distro
self.php_versions = get("php_versions", "4 5.2 5.3 5.4 5.5 5.6 7.0 7.1 7.2 7.3 7.4 8.0 8.1 8.2").split(" ")
self.nice = get("nice", "0")
diff --git a/PLD_Builder/install.py b/PLD_Builder/install.py
index 5cf2190..acbf58a 100644
--- a/PLD_Builder/install.py
+++ b/PLD_Builder/install.py
@@ -163,10 +163,10 @@ def install_br(r, b):
nbr = nbr + " " + re.escape(bre)
br = nbr.strip()
b.log_line("updating poldek cache...")
- chroot.run("poldek --up --upa", user = "root", logfile = b.logfile)
+ chroot.run("poldek --up --upa", user = "root", logfile = b.logfile, nonet=False)
# check conflicts in BRed packages
b.log_line("checking conflicting packages in BRed packages")
- f = chroot.popen("poldek --test --test --noask --caplookup -Q -v %s --pmopt='--nodigest' --upgrade %s" % (b.ignores(), br), user = "root", encoding = "utf-8")
+ f = chroot.popen("poldek --test --test --noask --caplookup -Q -v %s --pmopt='--nodigest' --upgrade %s" % (b.ignores(), br), user = "root", encoding = "utf-8", nonet=False)
# phonon-devel-4.3.1-1.i686 conflicts with qt4-phonon-devel-4.5.0-6.i686
# jdbc-stdext >= 2.0 is required by installed java-struts-1.3.10-1.noarch
# jmx is needed by (installed) java-commons-modeler-2.0-1.noarch
@@ -200,7 +200,8 @@ def install_br(r, b):
b.log_line("installing BR: %s" % br)
res = chroot.run("set -x; poldek --noask --caplookup -Q -v %s --pmopt='--nodigest' --upgrade %s" % (b.ignores(), br),
user = "root",
- logfile = b.logfile)
+ logfile = b.logfile,
+ nonet=False)
if res != 0:
b.log_line("error: BR installation failed")
return False
diff --git a/PLD_Builder/rpm_builder.py b/PLD_Builder/rpm_builder.py
index 361ccf7..91014d5 100644
--- a/PLD_Builder/rpm_builder.py
+++ b/PLD_Builder/rpm_builder.py
@@ -164,8 +164,7 @@ def prepare_env(logfile = None):
test -f $db && chmod a+r $db
done
- # try to limit network access for builder account
- /bin/setfacl -m u:builder:--- /etc/resolv.conf
+ # network access is blocked via unshare -n for rpmbuild calls
""", 'root', logfile = logfile)
def build_rpm(r, b):
diff --git a/PLD_Builder/srpm_builder.py b/PLD_Builder/srpm_builder.py
index 55d164e..442f258 100644
--- a/PLD_Builder/srpm_builder.py
+++ b/PLD_Builder/srpm_builder.py
@@ -108,7 +108,7 @@ def build_srpm(r, b):
util.append_to(b.logfile, "request from: %s" % r.requester)
util.append_to(b.logfile, "started at: %s" % time.asctime())
util.append_to(b.logfile, "building SRPM using: %s\n" % cmd)
- res = chroot.run(cmd, logfile = b.logfile)
+ res = chroot.run(cmd, logfile = b.logfile, nonet=False)
util.append_to(b.logfile, "exit status %d" % res)
files = util.collect_files(b.logfile)
if len(files) > 0:
@@ -126,14 +126,14 @@ def build_srpm(r, b):
for pref in config.tag_prefixes:
util.append_to(b.logfile, "Tagging with prefix: %s" % pref)
res = chroot.run("cd rpm/packages; ./builder -bs %s -r %s -Tp %s -Tv %s %s" % \
- (b.bconds_string(), b.branch, pref, b.defines_string(), b.spec), logfile = b.logfile)
+ (b.bconds_string(), b.branch, pref, b.defines_string(), b.spec), logfile = b.logfile, nonet=False)
if res == 0:
transfer_file(r, b)
packagename = b.spec[:-5]
packagedir = "rpm/packages/%s" % packagename
chroot.run("rpm/packages/builder -m %s" % \
- (b.spec,), logfile = b.logfile)
+ (b.spec,), logfile = b.logfile, nonet=False)
chroot.run("rm -rf %s" % packagedir, logfile = b.logfile)
status.pop()
diff --git a/bin/chroot-nonet b/bin/chroot-nonet
new file mode 100755
index 0000000..5298d44
--- /dev/null
+++ b/bin/chroot-nonet
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Wrapper for chroot that brings up loopback in a network namespace.
+# Used with: sudo unshare -n /usr/local/bin/chroot-nonet /path/to/chroot ...
+ip link set lo up
+exec chroot "$@"
diff --git a/config/builder.conf.dist b/config/builder.conf.dist
index 16612c8..eeabaa7 100644
--- a/config/builder.conf.dist
+++ b/config/builder.conf.dist
@@ -24,6 +24,10 @@ syslog =
#sudo_chroot_wrapper = sparc32
sudo_chroot_wrapper =
+# Path to chroot-nonet wrapper for network-isolated builds (rpmbuild calls).
+# Used with: sudo unshare -n <nonet_chroot> <chroot_path> ...
+#nonet_chroot = /usr/local/bin/chroot-nonet
+
# Keep rpms in /spools/ready inside chroots for how long (in hours).
max_keep_time = 168
diff --git a/doc/README.bin-builder b/doc/README.bin-builder
index 2699cbc..c51dddd 100644
--- a/doc/README.bin-builder
+++ b/doc/README.bin-builder
@@ -78,7 +78,13 @@ also you need to setup password that is used to authenticate in rsync-passwords
sudo access
~~~~~~~~~~~
make sure builder user (who runs crons) can sudo chroot to the chroots:
-builder ALL=(ALL) NOPASSWD: /usr/sbin/chroot /home/users/builder/chroot-th *
+builder ALL=(root) NOPASSWD: \
+ /usr/sbin/chroot /home/users/builder/chroot-th *, \
+ /usr/bin/unshare -n /usr/local/bin/chroot-nonet /home/users/builder/chroot-th *
+
+the unshare rule is for network-isolated rpmbuild calls (loopback only).
+install the wrapper script:
+install -m 755 bin/chroot-nonet /usr/local/bin/chroot-nonet
testing
~~~~~~~
diff --git a/doc/user-manual.txt b/doc/user-manual.txt
index e8a4e61..6b5791b 100644
--- a/doc/user-manual.txt
+++ b/doc/user-manual.txt
@@ -29,12 +29,17 @@ bin_builder:
access to chroots via sudo (sudoers):
-srpms_builder ALL = NOPASSWD: \
+srpms_builder ALL=(root) NOPASSWD: \
/usr/sbin/chroot /path/to/chroot *
-
-bin_builder ALL = NOPASSWD: \
- /usr/sbin/chroot /path/to/chroot1 *, \
- /usr/sbin/chroot /path/to/chroot2 *
+
+bin_builder ALL=(root) NOPASSWD: \
+ /usr/sbin/chroot /path/to/chroot *, \
+ /usr/bin/unshare -n /usr/local/bin/chroot-nonet /path/to/chroot *
+
+the unshare rule is for network-isolated rpmbuild calls (loopback only).
+chroot-nonet wrapper (bin/chroot-nonet) brings up loopback in the namespace.
+install it:
+ install -m 755 bin/chroot-nonet /usr/local/bin/chroot-nonet
3. Scripts installations
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/projects/pld-builder.new.git/commitdiff/a3e592a91a9c7392e33ad3cab29e24d7b1bc5cbe
More information about the pld-cvs-commit
mailing list