Skip to content

Commit e5e96a3

Browse files
authored
Merge pull request #2061 from jnovy/fix-readonly-console
libcrun: fall back to bind mount for /dev/console on read-only file systems
2 parents a718a92 + 4c530d4 commit e5e96a3

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

src/libcrun/linux.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3951,7 +3951,18 @@ libcrun_set_terminal (libcrun_container_t *container, libcrun_error_t *err)
39513951
{
39523952
ret = unlink ("/dev/console");
39533953
if (UNLIKELY (ret < 0 && errno != ENOENT))
3954-
return crun_make_error (err, errno, "unlink `/dev/console`");
3954+
{
3955+
if (errno == EROFS)
3956+
{
3957+
/* If the file system is read-only, fall back to a bind mount. */
3958+
ret = do_mount (container, pty, -1, "/dev/console", NULL, MS_BIND, NULL, LABEL_MOUNT, err);
3959+
if (UNLIKELY (ret < 0))
3960+
return ret;
3961+
3962+
return get_and_reset (&fd);
3963+
}
3964+
return crun_make_error (err, errno, "unlink `/dev/console`");
3965+
}
39553966

39563967
ret = symlink (pty, "/dev/console");
39573968
if (UNLIKELY (ret < 0))

tests/test_terminal.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,32 @@ def test_terminal_zero_size():
379379
return -1
380380

381381

382+
def test_terminal_readonly_rootfs_no_dev_tmpfs():
383+
"""Test terminal with readonly rootfs and no /dev tmpfs (issue #1745)."""
384+
if os.isatty(1) == False:
385+
return (77, "requires TTY")
386+
387+
conf = base_config()
388+
add_all_namespaces(conf, userns=True)
389+
conf['process']['terminal'] = True
390+
conf['process']['args'] = ['/init', 'true']
391+
conf['root']['readonly'] = True
392+
393+
# Remove the /dev tmpfs mount so /dev/console lives on the read-only rootfs.
394+
# Keep /dev/pts which is needed for terminal allocation.
395+
conf['mounts'] = [m for m in conf['mounts']
396+
if m['destination'] != '/dev'
397+
and m['destination'] != '/dev/shm'
398+
and m['destination'] != '/dev/mqueue']
399+
400+
try:
401+
out, _ = run_and_get_output(conf, hide_stderr=True)
402+
return 0
403+
except Exception as e:
404+
logger.info("test failed: %s", e)
405+
return -1
406+
407+
382408
all_tests = {
383409
"terminal-allocation": test_terminal_allocation,
384410
"terminal-size": test_terminal_size,
@@ -392,6 +418,7 @@ def test_terminal_zero_size():
392418
"terminal-exec": test_terminal_exec,
393419
"terminal-exec-no-tty": test_terminal_exec_no_tty,
394420
"terminal-env-term": test_terminal_env_term,
421+
"terminal-readonly-rootfs-no-dev-tmpfs": test_terminal_readonly_rootfs_no_dev_tmpfs,
395422
}
396423

397424
if __name__ == "__main__":

0 commit comments

Comments
 (0)