30
30
CLONE_NEWUSER = 0x10000000
31
31
EPERM = 1
32
32
ENOENT = 2
33
+ ENOSYS = 38
33
34
F_GETFD = 1
34
35
F_SETFD = 2
35
36
FD_CLOEXEC = 1
@@ -99,13 +100,24 @@ class cap_user_data_t(ctypes.Structure):
99
100
libc .fcntl .argtypes = (ctypes .c_int , ctypes .c_int , ctypes .c_int )
100
101
101
102
102
- def oserror (filename : str = "" ) -> None :
103
+ ENOSYS_MSG = """
104
+ mkosi was unable to invoke the {syscall}() system call.
105
+
106
+ This probably means either the system call is not implemented by the running kernel version ({kver}) 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 = syscall , kver = os .uname ().version ), file = sys .stderr )
114
+
103
115
raise OSError (ctypes .get_errno (), os .strerror (ctypes .get_errno ()), filename or None )
104
116
105
117
106
118
def unshare (flags : int ) -> None :
107
119
if libc .unshare (flags ) < 0 :
108
- oserror ()
120
+ oserror ("unshare" )
109
121
110
122
111
123
def statfs (path : str ) -> int :
@@ -115,7 +127,7 @@ def statfs(path: str) -> int:
115
127
buffer = (ctypes .c_long * 15 )()
116
128
117
129
if libc .statfs (path .encode (), ctypes .byref (buffer )) < 0 :
118
- oserror (path )
130
+ oserror ("statfs" , path )
119
131
120
132
return int (buffer [0 ])
121
133
@@ -125,12 +137,12 @@ def mount(src: str, dst: str, type: str, flags: int, options: str) -> None:
125
137
typeb = type .encode () if type else None
126
138
optionsb = options .encode () if options else None
127
139
if libc .mount (srcb , dst .encode (), typeb , flags , optionsb ) < 0 :
128
- oserror (dst )
140
+ oserror ("mount" , dst )
129
141
130
142
131
143
def umount2 (path : str , flags : int = 0 ) -> None :
132
144
if libc .umount2 (path .encode (), flags ) < 0 :
133
- oserror (path )
145
+ oserror ("umount2" , path )
134
146
135
147
136
148
def cap_permitted_to_ambient () -> None :
@@ -146,13 +158,13 @@ def cap_permitted_to_ambient() -> None:
146
158
payload = (cap_user_data_t * LINUX_CAPABILITY_U32S_3 )()
147
159
148
160
if libc .capget (ctypes .addressof (header ), ctypes .byref (payload )) < 0 :
149
- oserror ()
161
+ oserror ("capget" )
150
162
151
163
payload [0 ].inheritable = payload [0 ].permitted
152
164
payload [1 ].inheritable = payload [1 ].permitted
153
165
154
166
if libc .capset (ctypes .addressof (header ), ctypes .byref (payload )) < 0 :
155
- oserror ()
167
+ oserror ("capset" )
156
168
157
169
effective = payload [1 ].effective << 32 | payload [0 ].effective
158
170
@@ -166,7 +178,7 @@ def cap_permitted_to_ambient() -> None:
166
178
break
167
179
168
180
if effective & (1 << cap ) and libc .prctl (PR_CAP_AMBIENT , PR_CAP_AMBIENT_RAISE , cap , 0 , 0 ) < 0 :
169
- oserror ()
181
+ oserror ("prctl" )
170
182
171
183
172
184
def have_effective_cap (capability : int ) -> bool :
@@ -225,7 +237,7 @@ def join_new_session_keyring() -> None:
225
237
226
238
keyring = libkeyutils .keyctl_join_session_keyring (None )
227
239
if keyring == - 1 :
228
- oserror ()
240
+ oserror ("keyctl" )
229
241
230
242
231
243
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:
245
257
fd = libc .syscall (NR_open_tree , AT_FDCWD , src .encode (), flags )
246
258
247
259
if fd < 0 :
248
- oserror (src )
260
+ oserror ("open_tree" , src )
249
261
250
262
try :
251
263
attr = mount_attr ()
@@ -274,7 +286,7 @@ def mount_rbind(src: str, dst: str, attrs: int = 0) -> None:
274
286
r = libc .syscall (NR_mount_setattr , fd , b"" , flags , ctypes .addressof (attr ), MOUNT_ATTR_SIZE_VER0 )
275
287
276
288
if r < 0 :
277
- oserror (src )
289
+ oserror ("mount_setattr" , src )
278
290
279
291
try :
280
292
libc .move_mount .argtypes = (
@@ -297,7 +309,7 @@ def mount_rbind(src: str, dst: str, attrs: int = 0) -> None:
297
309
r = libc .syscall (NR_move_mount , fd , b"" , AT_FDCWD , dst .encode (), MOVE_MOUNT_F_EMPTY_PATH )
298
310
299
311
if r < 0 :
300
- oserror (dst )
312
+ oserror ("move_mount" , dst )
301
313
finally :
302
314
os .close (fd )
303
315
@@ -325,7 +337,7 @@ def become_user(uid: int, gid: int) -> None:
325
337
326
338
event = libc .eventfd (0 , 0 )
327
339
if event < 0 :
328
- oserror ()
340
+ oserror ("eventfd" )
329
341
330
342
pid = os .fork ()
331
343
if pid == 0 :
@@ -896,7 +908,7 @@ def main() -> None:
896
908
# We're guaranteed to have / be a mount when we get here, so pivot_root() won't fail anymore,
897
909
# even if we're in the initramfs.
898
910
if libc .pivot_root (b"." , b"." ) < 0 :
899
- oserror ()
911
+ oserror ("pivot_root" )
900
912
901
913
# As documented in the pivot_root() man page, this will unmount the old rootfs.
902
914
umount2 ("." , MNT_DETACH )
0 commit comments