Skip to content

Commit 09c53e1

Browse files
committed
sandbox: Show better error on ENOSYS
1 parent 10918a9 commit 09c53e1

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

mkosi/sandbox.py

+26-14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
CLONE_NEWUSER = 0x10000000
3131
EPERM = 1
3232
ENOENT = 2
33+
ENOSYS = 38
3334
F_GETFD = 1
3435
F_SETFD = 2
3536
FD_CLOEXEC = 1
@@ -99,13 +100,24 @@ class cap_user_data_t(ctypes.Structure):
99100
libc.fcntl.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.c_int)
100101

101102

102-
def oserror(filename: str = "") -> None:
103+
ENOSYS_MSG = """
104+
mkosi was unable to invoke the {}() system call.
105+
106+
This probably means either the system call is not implemented by the running kernel version ({}) or the
107+
system call is prohibited via seccomp if mkosi is being executed inside a containerized environment.
108+
"""
109+
110+
111+
def oserror(syscall: str, filename: str = "") -> None:
112+
if ctypes.get_errno() == ENOSYS:
113+
print(ENOSYS_MSG.format(syscall, os.uname().version), file=sys.stderr)
114+
103115
raise OSError(ctypes.get_errno(), os.strerror(ctypes.get_errno()), filename or None)
104116

105117

106118
def unshare(flags: int) -> None:
107119
if libc.unshare(flags) < 0:
108-
oserror()
120+
oserror("unshare")
109121

110122

111123
def statfs(path: str) -> int:
@@ -115,7 +127,7 @@ def statfs(path: str) -> int:
115127
buffer = (ctypes.c_long * 15)()
116128

117129
if libc.statfs(path.encode(), ctypes.byref(buffer)) < 0:
118-
oserror(path)
130+
oserror("statfs", path)
119131

120132
return int(buffer[0])
121133

@@ -125,12 +137,12 @@ def mount(src: str, dst: str, type: str, flags: int, options: str) -> None:
125137
typeb = type.encode() if type else None
126138
optionsb = options.encode() if options else None
127139
if libc.mount(srcb, dst.encode(), typeb, flags, optionsb) < 0:
128-
oserror(dst)
140+
oserror("mount", dst)
129141

130142

131143
def umount2(path: str, flags: int = 0) -> None:
132144
if libc.umount2(path.encode(), flags) < 0:
133-
oserror(path)
145+
oserror("umount2", path)
134146

135147

136148
def cap_permitted_to_ambient() -> None:
@@ -146,13 +158,13 @@ def cap_permitted_to_ambient() -> None:
146158
payload = (cap_user_data_t * LINUX_CAPABILITY_U32S_3)()
147159

148160
if libc.capget(ctypes.addressof(header), ctypes.byref(payload)) < 0:
149-
oserror()
161+
oserror("capget")
150162

151163
payload[0].inheritable = payload[0].permitted
152164
payload[1].inheritable = payload[1].permitted
153165

154166
if libc.capset(ctypes.addressof(header), ctypes.byref(payload)) < 0:
155-
oserror()
167+
oserror("capset")
156168

157169
effective = payload[1].effective << 32 | payload[0].effective
158170

@@ -166,7 +178,7 @@ def cap_permitted_to_ambient() -> None:
166178
break
167179

168180
if effective & (1 << cap) and libc.prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0:
169-
oserror()
181+
oserror("prctl")
170182

171183

172184
def have_effective_cap(capability: int) -> bool:
@@ -225,7 +237,7 @@ def join_new_session_keyring() -> None:
225237

226238
keyring = libkeyutils.keyctl_join_session_keyring(None)
227239
if keyring == -1:
228-
oserror()
240+
oserror("keyctl")
229241

230242

231243
def mount_rbind(src: str, dst: str, attrs: int = 0) -> None:
@@ -245,7 +257,7 @@ def mount_rbind(src: str, dst: str, attrs: int = 0) -> None:
245257
fd = libc.syscall(NR_open_tree, AT_FDCWD, src.encode(), flags)
246258

247259
if fd < 0:
248-
oserror(src)
260+
oserror("open_tree", src)
249261

250262
try:
251263
attr = mount_attr()
@@ -274,7 +286,7 @@ def mount_rbind(src: str, dst: str, attrs: int = 0) -> None:
274286
r = libc.syscall(NR_mount_setattr, fd, b"", flags, ctypes.addressof(attr), MOUNT_ATTR_SIZE_VER0)
275287

276288
if r < 0:
277-
oserror(src)
289+
oserror("mount_setattr", src)
278290

279291
try:
280292
libc.move_mount.argtypes = (
@@ -297,7 +309,7 @@ def mount_rbind(src: str, dst: str, attrs: int = 0) -> None:
297309
r = libc.syscall(NR_move_mount, fd, b"", AT_FDCWD, dst.encode(), MOVE_MOUNT_F_EMPTY_PATH)
298310

299311
if r < 0:
300-
oserror(dst)
312+
oserror("move_mount", dst)
301313
finally:
302314
os.close(fd)
303315

@@ -325,7 +337,7 @@ def become_user(uid: int, gid: int) -> None:
325337

326338
event = libc.eventfd(0, 0)
327339
if event < 0:
328-
oserror()
340+
oserror("eventfd")
329341

330342
pid = os.fork()
331343
if pid == 0:
@@ -896,7 +908,7 @@ def main() -> None:
896908
# We're guaranteed to have / be a mount when we get here, so pivot_root() won't fail anymore,
897909
# even if we're in the initramfs.
898910
if libc.pivot_root(b".", b".") < 0:
899-
oserror()
911+
oserror("pivot_root")
900912

901913
# As documented in the pivot_root() man page, this will unmount the old rootfs.
902914
umount2(".", MNT_DETACH)

0 commit comments

Comments
 (0)