summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net
diff options
context:
space:
mode:
authorBobby Eshleman <bobbyeshleman@meta.com>2026-06-02 18:37:32 -0700
committerJakub Kicinski <kuba@kernel.org>2026-06-05 18:10:31 -0700
commit78c1930198fc63f2d4761848cbe148c5b2958b01 (patch)
treebbf1a023974baf2eb96140b202903b6a8d781e21 /tools/testing/selftests/net
parente302aa3d00fb1bcbc1137a42615b1c54ca51d785 (diff)
downloadlinux-next-78c1930198fc63f2d4761848cbe148c5b2958b01.tar.gz
linux-next-78c1930198fc63f2d4761848cbe148c5b2958b01.zip
selftests: drv-net: add userns devmem RX test
Add userns_devmem.py, which mirrors nk_devmem.py but places the netkit guest in a netns whose owning user_ns is non-init. ncdevmem is ran there via nsenter so the bind-rx call is issued with creds that hold CAP_NET_ADMIN only in the child user_ns. Without the preceding GENL_UNS_ADMIN_PERM patch the test fails at bind-rx with EPERM, but with the patch the transfer completes and tests pass. Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20260602-nl-prov-v2-2-ad721142c641@meta.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'tools/testing/selftests/net')
-rw-r--r--tools/testing/selftests/net/lib/py/__init__.py4
-rw-r--r--tools/testing/selftests/net/lib/py/netns.py75
-rw-r--r--tools/testing/selftests/net/lib/py/utils.py7
3 files changed, 82 insertions, 4 deletions
diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py
index 64a8c1ed4950..e58bdbdc58ee 100644
--- a/tools/testing/selftests/net/lib/py/__init__.py
+++ b/tools/testing/selftests/net/lib/py/__init__.py
@@ -10,7 +10,7 @@ from .ksft import KsftFailEx, KsftSkipEx, KsftXfailEx, ksft_pr, ksft_eq, \
ksft_ge, ksft_gt, ksft_lt, ksft_raises, ksft_busy_wait, \
ktap_result, ksft_disruptive, ksft_setup, ksft_run, ksft_exit, \
ksft_variants, KsftNamedVariant
-from .netns import NetNS, NetNSEnter
+from .netns import NetNS, NetNSEnter, UserNetNS
from .nsim import NetdevSim, NetdevSimDev
from .utils import CmdExitFailure, fd_read_timeout, cmd, bkg, defer, \
bpftool, ip, ethtool, bpftrace, rand_port, rand_ports, wait_port_listen, \
@@ -26,7 +26,7 @@ __all__ = ["KSRC",
"ksft_is", "ksft_ge", "ksft_gt", "ksft_lt", "ksft_raises",
"ksft_busy_wait", "ktap_result", "ksft_disruptive", "ksft_setup",
"ksft_run", "ksft_exit", "ksft_variants", "KsftNamedVariant",
- "NetNS", "NetNSEnter",
+ "NetNS", "NetNSEnter", "UserNetNS",
"CmdExitFailure", "fd_read_timeout", "cmd", "bkg", "defer",
"bpftool", "ip", "ethtool", "bpftrace", "rand_port", "rand_ports",
"wait_port_listen", "wait_file", "tool", "tc",
diff --git a/tools/testing/selftests/net/lib/py/netns.py b/tools/testing/selftests/net/lib/py/netns.py
index 8e9317044eef..526f6aa80077 100644
--- a/tools/testing/selftests/net/lib/py/netns.py
+++ b/tools/testing/selftests/net/lib/py/netns.py
@@ -1,9 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
-from .utils import ip
import ctypes
+import os
import random
import string
+import subprocess
+import time
+from pathlib import Path
+
+from .utils import ip
libc = ctypes.cdll.LoadLibrary('libc.so.6')
@@ -34,6 +39,74 @@ class NetNS:
return f"NetNS({self.name})"
+class UserNetNS:
+ """Network namespace owned by a non-init user namespace."""
+
+ def __init__(self):
+ self.name = ''.join(
+ random.choice(string.ascii_lowercase) for _ in range(8))
+ self.user_ns_path = f"/run/userns/{self.name}"
+ self.net_ns_path = f"/run/netns/{self.name}"
+ self._user_mounted = False
+ self._net_mounted = False
+
+ os.makedirs("/run/userns", exist_ok=True)
+ os.makedirs("/run/netns", exist_ok=True)
+
+ Path(self.user_ns_path).touch()
+ Path(self.net_ns_path).touch()
+
+ with subprocess.Popen(
+ ["unshare", "--user", "--net", "--map-root-user",
+ "sleep", "infinity"]) as proc:
+ try:
+ pid = proc.pid
+ init_user = os.readlink("/proc/self/ns/user")
+ for _ in range(200):
+ try:
+ if os.readlink(f"/proc/{pid}/ns/user") != init_user:
+ break
+ except OSError:
+ pass
+ time.sleep(0.01)
+ else:
+ raise RuntimeError("unshare child did not create userns")
+
+ subprocess.run(["mount", "--bind", f"/proc/{pid}/ns/user",
+ self.user_ns_path], check=True)
+ self._user_mounted = True
+ subprocess.run(["mount", "--bind", f"/proc/{pid}/ns/net",
+ self.net_ns_path], check=True)
+ self._net_mounted = True
+ finally:
+ proc.kill()
+
+ def __del__(self):
+ if self._net_mounted:
+ subprocess.run(["umount", self.net_ns_path], check=False)
+ self._net_mounted = False
+ if self._user_mounted:
+ subprocess.run(["umount", self.user_ns_path], check=False)
+ self._user_mounted = False
+ for path in (self.net_ns_path, self.user_ns_path):
+ try:
+ os.unlink(path)
+ except OSError:
+ pass
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, ex_type, ex_value, ex_tb):
+ self.__del__()
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return f"UserNetNS({self.name})"
+
+
class NetNSEnter:
def __init__(self, ns_name):
self.ns_path = f"/run/netns/{ns_name}"
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index be9408a77168..87eae79d01c1 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -47,7 +47,12 @@ class cmd:
background=False, host=None, timeout=5, ksft_ready=None,
ksft_wait=None):
if ns:
- comm = f'ip netns exec {ns} ' + comm
+ if hasattr(ns, 'user_ns_path'):
+ comm = (f'nsenter --user={ns.user_ns_path} '
+ f'--net={ns.net_ns_path} --setuid=0 --setgid=0 -- '
+ + comm)
+ else:
+ comm = f'ip netns exec {ns} ' + comm
self.stdout = None
self.stderr = None