Skip to content

Commit

Permalink
runc run: fix ro /dev
Browse files Browse the repository at this point in the history
Commit fb4c27c (went into v1.0.0-rc93) fixed a bug with
read-only tmpfs, but introduced a bug with read-only /dev.

This happens because /dev is a tmpfs mount and is therefore remounted
read-only a bit earlier than before.

To fix,

1. Revert the part of the above commit which remounts all tmpfs mounts
   as read-only in mountToRootfs.

2. Reuse finalizeRootfs (which is already used to remount /dev
   read-only) to also remount all ro tmpfs mounts that were previously
   mounted rw in mountPropagate.

3. Remove the break in finalizeRootfs, as now we have more than one
   mount to care about.

4. Reorder the if statements in finalizeRootfs to perform the fast check
   (for ro flag) first, and compare the strings second. Since /dev is
   most probably also a tmpfs mount, do the m.Device check first.

Add a test case to validate the fix and prevent future regressions;
make sure it fails before the fix:

 ✗ runc run [ro /dev mount]
   (in test file tests/integration/mounts.bats, line 45)
     `[ "$status" -eq 0 ]' failed
   runc spec (status=0):

   runc run test_busybox (status=1):
   time="2021-11-12T12:19:48-08:00" level=error msg="runc run failed: unable to start container process: error during container init: error mounting \"devpts\" to rootfs at \"/dev/pts\": mkdir /tmp/bats-run-VJXQk7/runc.0Fj70w/bundle/rootfs/dev/pts: read-only file system"

Fixes: fb4c27c
Signed-off-by: Kir Kolyshkin <[email protected]>
(cherry picked from commit 356c171)
Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Nov 12, 2021
1 parent a572412 commit 0f99754
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 14 deletions.
21 changes: 7 additions & 14 deletions libcontainer/rootfs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,14 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
// finalizeRootfs sets anything to ro if necessary. You must call
// prepareRootfs first.
func finalizeRootfs(config *configs.Config) (err error) {
// remount dev as ro if specified
// Remount /dev and tmpfs mounts as ro if specified.
for _, m := range config.Mounts {
if utils.CleanPath(m.Destination) == "/dev" {
if m.Flags&unix.MS_RDONLY == unix.MS_RDONLY {
if m.Flags&unix.MS_RDONLY == unix.MS_RDONLY {
if m.Device == "tmpfs" || utils.CleanPath(m.Destination) == "/dev" {
if err := remountReadonly(m); err != nil {
return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination)
}
}
break
}
}

Expand Down Expand Up @@ -431,12 +430,6 @@ func mountToRootfs(m *configs.Mount, c *mountConfig) error {
return err
}
}
// Initially mounted rw in mountPropagate, remount to ro if flag set.
if m.Flags&unix.MS_RDONLY != 0 {
if err := remount(m, rootfs); err != nil {
return err
}
}
return nil
case "bind":
if err := prepareBindMount(m, rootfs); err != nil {
Expand Down Expand Up @@ -1046,10 +1039,10 @@ func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error {
flags = m.Flags
)
// Delay mounting the filesystem read-only if we need to do further
// operations on it. We need to set up files in "/dev" and tmpfs mounts may
// need to be chmod-ed after mounting. The mount will be remounted ro later
// in finalizeRootfs() if necessary.
if utils.CleanPath(m.Destination) == "/dev" || m.Device == "tmpfs" {
// operations on it. We need to set up files in "/dev", and other tmpfs
// mounts may need to be chmod-ed after mounting. These mounts will be
// remounted ro later in finalizeRootfs(), if necessary.
if m.Device == "tmpfs" || utils.CleanPath(m.Destination) == "/dev" {
flags &= ^unix.MS_RDONLY
}

Expand Down
10 changes: 10 additions & 0 deletions tests/integration/mounts.bats
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ function teardown() {
[[ "${lines[0]}" == *'ro,'* ]]
}

# https://github.com/opencontainers/runc/issues/3248
@test "runc run [ro /dev mount]" {
update_config ' .mounts |= map((select(.destination == "/dev") | .options += ["ro"]) // .)
| .process.args |= ["grep", "^tmpfs /dev", "/proc/mounts"]'

runc run test_busybox
[ "$status" -eq 0 ]
[[ "${lines[0]}" == *'ro,'* ]]
}

# https://github.com/opencontainers/runc/issues/2683
@test "runc run [tmpfs mount with absolute symlink]" {
# in container, /conf -> /real/conf
Expand Down

0 comments on commit 0f99754

Please sign in to comment.