Skip to content

Commit 54bd724

Browse files
authored
Merge pull request #1847 from giuseppe/do-not-chown-dev-null
linux: never chown devices
2 parents 20d4da7 + a9d1299 commit 54bd724

File tree

5 files changed

+183
-47
lines changed

5 files changed

+183
-47
lines changed

src/libcrun/container.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,15 +1017,27 @@ send_sync_cb (void *data, libcrun_error_t *err)
10171017
}
10181018

10191019
static int
1020-
maybe_chown_std_streams (uid_t container_uid, gid_t container_gid,
1021-
libcrun_error_t *err)
1020+
maybe_chown_std_streams (uid_t container_uid, gid_t container_gid, libcrun_error_t *err)
10221021
{
10231022
int ret, i;
10241023

10251024
for (i = 0; i < 3; i++)
10261025
{
10271026
if (! isatty (i))
10281027
{
1028+
struct stat statbuf;
1029+
ret = fstat (i, &statbuf);
1030+
if (UNLIKELY (ret < 0))
1031+
{
1032+
if (errno == EBADF)
1033+
continue;
1034+
return crun_make_error (err, errno, "fstat fd `%d`", i);
1035+
}
1036+
1037+
/* Skip chown for device files */
1038+
if (S_ISCHR (statbuf.st_mode) || S_ISBLK (statbuf.st_mode))
1039+
continue;
1040+
10291041
ret = fchown (i, container_uid, container_gid);
10301042
if (UNLIKELY (ret < 0))
10311043
{

tests/test_devices.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,48 @@ def test_net_devices():
248248

249249
for specify_broadcast in [True, False]:
250250
for specify_name in [True, False]:
251-
subprocess.run(["ip", "link", "add", "testdevice", "type", "dummy"])
251+
sys.stderr.write("# test_net_devices: creating testdevice with specify_broadcast=%s, specify_name=%s\n" % (specify_broadcast, specify_name))
252+
result = subprocess.run(["ip", "link", "add", "testdevice", "type", "dummy"], capture_output=True, text=True)
253+
if result.returncode != 0:
254+
sys.stderr.write("# ip link add failed: %s\n" % result.stderr)
255+
return -1
252256
if specify_broadcast:
253-
subprocess.run(["ip", "addr", "add", "10.1.2.3/24", "brd", "10.1.2.254", "dev", "testdevice"])
257+
result = subprocess.run(["ip", "addr", "add", "10.1.2.3/24", "brd", "10.1.2.254", "dev", "testdevice"], capture_output=True, text=True)
258+
if result.returncode != 0:
259+
sys.stderr.write("# ip addr add with broadcast failed: %s\n" % result.stderr)
260+
return -1
254261
else:
255-
subprocess.run(["ip", "addr", "add", "10.1.2.3/24", "dev", "testdevice"])
262+
result = subprocess.run(["ip", "addr", "add", "10.1.2.3/24", "dev", "testdevice"], capture_output=True, text=True)
263+
if result.returncode != 0:
264+
sys.stderr.write("# ip addr add without broadcast failed: %s\n" % result.stderr)
265+
return -1
256266

257267
conf = base_config()
258268
add_all_namespaces(conf)
269+
270+
# Add network capabilities needed for network device operations
271+
conf['process']['capabilities'] = {
272+
"bounding": [
273+
"CAP_NET_ADMIN",
274+
"CAP_NET_RAW",
275+
"CAP_SYS_ADMIN"
276+
],
277+
"effective": [
278+
"CAP_NET_ADMIN",
279+
"CAP_NET_RAW",
280+
"CAP_SYS_ADMIN"
281+
],
282+
"inheritable": [
283+
"CAP_NET_ADMIN",
284+
"CAP_NET_RAW",
285+
"CAP_SYS_ADMIN"
286+
],
287+
"permitted": [
288+
"CAP_NET_ADMIN",
289+
"CAP_NET_RAW",
290+
"CAP_SYS_ADMIN"
291+
]
292+
}
259293
if specify_name:
260294
conf['process']['args'] = ['/init', 'ip', 'newtestdevice']
261295
conf['linux']['netDevices'] = {
@@ -272,19 +306,28 @@ def test_net_devices():
272306

273307
try:
274308
out = run_and_get_output(conf)
309+
sys.stderr.write("# test_net_devices: specify_broadcast=%s, specify_name=%s\n" % (specify_broadcast, specify_name))
310+
sys.stderr.write("# test_net_devices: output: %s\n" % repr(out[0]))
275311
if "address: 10.1.2.3" not in out[0]:
276312
sys.stderr.write("# address not found in output\n")
313+
sys.stderr.write("# full output: %s\n" % repr(out[0]))
277314
return 1
278315
if specify_broadcast:
279316
if "broadcast: 10.1.2.254" not in out[0]:
280317
sys.stderr.write("# broadcast address not found in output\n")
318+
sys.stderr.write("# full output: %s\n" % repr(out[0]))
281319
return 1
282320
else:
283321
if "broadcast" in out[0]:
284-
sys.stderr.write("# broadcast address found in output\n")
322+
sys.stderr.write("# broadcast address found in output when it shouldn't be\n")
323+
sys.stderr.write("# full output: %s\n" % repr(out[0]))
285324
return 1
286325
except Exception as e:
326+
sys.stderr.write("# test_net_devices exception: %s\n" % str(e))
287327
return -1
328+
finally:
329+
# Clean up the test device
330+
subprocess.run(["ip", "link", "del", "testdevice"], capture_output=True)
288331
finally:
289332
os.setns(current_netns, os.CLONE_NEWNET)
290333
os.close(current_netns)

tests/test_mounts.py

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
from tests_utils import *
2222
import tempfile
2323
import re
24+
from typing import List, Optional
2425

2526
try:
2627
import libmount
2728
except Exception:
2829
print("1..0")
2930
sys.exit(0)
3031

31-
def helper_mount(options, tmpfs=True, userns=False, is_file=False):
32+
def helper_mount(options: str, tmpfs: bool = True, userns: bool = False, is_file: bool = False) -> List[Optional[str]]:
3233
conf = base_config()
3334
conf['process']['args'] = ['/init', 'cat', '/proc/self/mountinfo']
3435
add_all_namespaces(conf, userns=userns)
@@ -54,12 +55,12 @@ def helper_mount(options, tmpfs=True, userns=False, is_file=False):
5455
sys.stderr.write("# helper_mount failed: mount target '%s' not found in mountinfo\n" % target)
5556
sys.stderr.write("# mount options: %s, tmpfs=%s, userns=%s, is_file=%s\n" % (options, tmpfs, userns, is_file))
5657
sys.stderr.write("# mountinfo output: %s\n" % out[:300])
57-
return -1
58+
return [None, None]
5859
return [m.vfs_options, m.fs_options]
5960
except Exception as e:
6061
sys.stderr.write("# helper_mount failed with exception: %s\n" % str(e))
6162
sys.stderr.write("# mount options: %s, tmpfs=%s, userns=%s, is_file=%s\n" % (options, tmpfs, userns, is_file))
62-
return -1
63+
return [None, None]
6364

6465
def test_mount_symlink():
6566
conf = base_config()
@@ -285,157 +286,157 @@ def test_mount_path_with_multiple_slashes():
285286
def test_mount_ro():
286287
for userns in [True, False]:
287288
a = helper_mount("ro", userns=userns, is_file=True)[0]
288-
if "ro" not in a:
289+
if a is None or "ro" not in a:
289290
return -1
290291
a = helper_mount("ro", userns=userns)[0]
291-
if "ro" not in a:
292+
if a is None or "ro" not in a:
292293
return -1
293294
a = helper_mount("ro", userns=userns, tmpfs=False)[0]
294-
if "ro" not in a:
295+
if a is None or "ro" not in a:
295296
return -1
296297
return 0
297298

298299
def test_mount_rro():
299300
for userns in [True, False]:
300301
a = helper_mount("rro", userns=userns, is_file=True)[0]
301-
if "ro" not in a:
302+
if a is None or "ro" not in a:
302303
return -1
303304
a = helper_mount("rro", userns=userns)[0]
304-
if "ro" not in a:
305+
if a is None or "ro" not in a:
305306
return -1
306307
a = helper_mount("rro", userns=userns, tmpfs=False)[0]
307-
if "ro" not in a:
308+
if a is None or "ro" not in a:
308309
return -1
309310
return 0
310311

311312
def test_mount_rw():
312313
for userns in [True, False]:
313314
a = helper_mount("rw", tmpfs=False, userns=userns)[0]
314-
if "rw" not in a:
315+
if a is None or "rw" not in a:
315316
return -1
316317
a = helper_mount("rw", userns=userns, is_file=True)[0]
317-
if "rw" not in a:
318+
if a is None or "rw" not in a:
318319
return -1
319320
a = helper_mount("rw", userns=userns)[0]
320-
if "rw" not in a:
321+
if a is None or "rw" not in a:
321322
return -1
322323
return 0
323324

324325
def test_mount_relatime():
325326
for userns in [True, False]:
326327
a = helper_mount("relatime", tmpfs=False, userns=userns)[0]
327-
if "relatime" not in a:
328+
if a is None or "relatime" not in a:
328329
return -1
329330
a = helper_mount("relatime", is_file=True, userns=userns)[0]
330-
if "relatime" not in a:
331+
if a is None or "relatime" not in a:
331332
return -1
332333
a = helper_mount("relatime", userns=userns)[0]
333-
if "relatime" not in a:
334+
if a is None or "relatime" not in a:
334335
return -1
335336
return 0
336337

337338
def test_mount_strictatime():
338339
for userns in [True, False]:
339340
a = helper_mount("strictatime", is_file=True, userns=userns)[0]
340-
if "relatime" not in a:
341+
if a is None or "relatime" not in a:
341342
return 0
342343
a = helper_mount("strictatime", tmpfs=False, userns=userns)[0]
343-
if "relatime" not in a:
344+
if a is None or "relatime" not in a:
344345
return 0
345346
a = helper_mount("strictatime", userns=userns)[0]
346-
if "relatime" not in a:
347+
if a is None or "relatime" not in a:
347348
return 0
348349
return -1
349350

350351
def test_mount_exec():
351352
for userns in [True, False]:
352353
a = helper_mount("exec", is_file=True, userns=userns)[0]
353-
if "noexec" in a:
354+
if a is not None and "noexec" in a:
354355
return -1
355356
a = helper_mount("exec", tmpfs=False, userns=userns)[0]
356-
if "noexec" in a:
357+
if a is not None and "noexec" in a:
357358
return -1
358359
a = helper_mount("exec", userns=userns)[0]
359-
if "noexec" in a:
360+
if a is not None and "noexec" in a:
360361
return -1
361362
return 0
362363

363364
def test_mount_noexec():
364365
for userns in [True, False]:
365366
a = helper_mount("noexec", is_file=True, userns=userns)[0]
366-
if "noexec" not in a:
367+
if a is None or "noexec" not in a:
367368
return -1
368369
a = helper_mount("noexec", tmpfs=False, userns=userns)[0]
369-
if "noexec" not in a:
370+
if a is None or "noexec" not in a:
370371
return -1
371372
a = helper_mount("noexec", userns=userns)[0]
372-
if "noexec" not in a:
373+
if a is None or "noexec" not in a:
373374
return -1
374375
return 0
375376

376377
def test_mount_suid():
377378
for userns in [True, False]:
378379
a = helper_mount("suid", is_file=True, userns=userns)[0]
379-
if "nosuid" in a:
380+
if a is not None and "nosuid" in a:
380381
return -1
381382
a = helper_mount("suid", tmpfs=False, userns=userns)[0]
382-
if "nosuid" in a:
383+
if a is not None and "nosuid" in a:
383384
return -1
384385
a = helper_mount("suid", userns=userns)[0]
385-
if "nosuid" in a:
386+
if a is not None and "nosuid" in a:
386387
return -1
387388
return 0
388389

389390
def test_mount_nosuid():
390391
for userns in [True, False]:
391392
a = helper_mount("nosuid", is_file=True, userns=userns)[0]
392-
if "nosuid" not in a:
393+
if a is None or "nosuid" not in a:
393394
return -1
394395
a = helper_mount("nosuid", tmpfs=False, userns=userns)[0]
395-
if "nosuid" not in a:
396+
if a is None or "nosuid" not in a:
396397
return -1
397398
a = helper_mount("nosuid", userns=userns)[0]
398-
if "nosuid" not in a:
399+
if a is None or "nosuid" not in a:
399400
return -1
400401
return 0
401402

402403
def test_mount_sync():
403404
for userns in [True, False]:
404405
a = helper_mount("sync", userns=userns)[1]
405-
if "sync" not in a:
406+
if a is None or "sync" not in a:
406407
return -1
407408
return 0
408409

409410
def test_mount_dirsync():
410411
for userns in [True, False]:
411412
a = helper_mount("dirsync", userns=userns)[1]
412-
if "dirsync" not in a:
413+
if a is None or "dirsync" not in a:
413414
return -1
414415
return 0
415416

416417
def test_mount_nodev():
417418
for userns in [True, False]:
418419
a = helper_mount("nodev", is_file=True)[0]
419-
if "nodev" not in a:
420+
if a is None or "nodev" not in a:
420421
return -1
421422
a = helper_mount("nodev", tmpfs=False)[0]
422-
if "nodev" not in a:
423+
if a is None or "nodev" not in a:
423424
return -1
424425
a = helper_mount("nodev", userns=userns)[0]
425-
if "nodev" not in a:
426+
if a is None or "nodev" not in a:
426427
return -1
427428
return 0
428429

429430
def test_mount_dev():
430431
for userns in [True, False]:
431432
a = helper_mount("dev", userns=userns, tmpfs=False)[0]
432-
if "nodev" in a:
433+
if a is not None and "nodev" in a:
433434
return -1
434435
a = helper_mount("dev", userns=userns, is_file=True)[0]
435-
if "nodev" in a:
436+
if a is not None and "nodev" in a:
436437
return -1
437438
a = helper_mount("dev", userns=userns)[0]
438-
if "nodev" in a:
439+
if a is not None and "nodev" in a:
439440
return -1
440441
return 0
441442

0 commit comments

Comments
 (0)