From c103287c48e52264266a1457111c24cd8b827bf7 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Thu, 11 Nov 2021 19:55:28 +0900 Subject: [PATCH] Support recursive read-only (RRO) mounts: `nerdctl run -v /foo:/bar:rro,rprivate` `nerdctl run -v /foo:/bar:rro,rprivate` appends "rro" (in addition to "ro") to the OCI mount option string slice. Requires crun >= 1.4 or runc >= 1.1 (opencontainers/runc PR 3272). Older version of runc just ignores "rro" option. The "rro" option string conforms to the proposal in util-linux/util-linux Issue 1501. Signed-off-by: Akihiro Suda --- README.md | 10 +++++++++- pkg/mountutil/mountutil_linux.go | 25 +++++++++++++++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e3f78c8840c..6582d99c10d 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ Major: - [On-demand image pulling (lazy-pulling) using Stargz Snapshotter](./docs/stargz.md): `nerdctl --snapshotter=stargz run IMAGE` . - [Image encryption and decryption using ocicrypt (imgcrypt)](./docs/ocicrypt.md): `nerdctl image (encrypt|decrypt) SRC DST` - [P2P image distribution using IPFS](./docs/ipfs.md): `nerdctl run ipfs://CID` +- Recursive read-only (RRO) bind-mount: `nerdctl run -v /mnt:/mnt:rro` (make children such as `/mnt/usb` to be read-only, too). + Requires kernel >= 5.12, and crun >= 1.4 or runc >= 1.1 (PR [#3272](https://github.com/opencontainers/runc/pull/3272)). Minor: - Namespacing: `nerdctl --namespace= ps` . @@ -339,7 +341,13 @@ Runtime flags: - :whale: `--sysctl`: Sysctl options, e.g \"net.ipv4.ip_forward=1\" Volume flags: -- :whale: :blue_square: `-v, --volume`: Bind mount a volume +- :whale: :blue_square: `-v, --volume :[:]`: Bind mount a volume, e.g., `-v /mnt:/mnt:rro,rprivate` + - :whale: option `rw` : Read/Write (when writable) + - :whale: option `ro` : Non-recursive read-only + - :nerd_face: option `rro`: Recursive read-only. Should be used in conjunction with `rprivate`. e.g., `-v /mnt:/mnt:rro,rprivate` makes children such as `/mnt/usb` to be read-only, too. + Requires kernel >= 5.12, and crun >= 1.4 or runc >= 1.1 (PR [#3272](https://github.com/opencontainers/runc/pull/3272)). With older runc, `rro` just works as `ro`. + - :whale: option `shared`, `slave`, `private`: Non-recursive "shared" / "slave" / "private" propagation + - :whale: option `rshared`, `rslave`, `rprivate`: Recursive "shared" / "slave" / "private" propagation - :whale: `--tmpfs`: Mount a tmpfs directory Rootfs flags: diff --git a/pkg/mountutil/mountutil_linux.go b/pkg/mountutil/mountutil_linux.go index b6a5fbd9e1e..449d03a7034 100644 --- a/pkg/mountutil/mountutil_linux.go +++ b/pkg/mountutil/mountutil_linux.go @@ -94,9 +94,7 @@ func parseVolumeOptionsWithMountInfo(vType, src, optsRaw string, getMountInfoFun ) for _, opt := range strings.Split(optsRaw, ",") { switch opt { - case "rw": - writeModeRawOpts = append(writeModeRawOpts, opt) - case "ro": + case "rw", "ro", "rro": writeModeRawOpts = append(writeModeRawOpts, opt) case "private", "rprivate", "shared", "rshared", "slave", "rslave": propagationRawOpts = append(propagationRawOpts, opt) @@ -112,9 +110,24 @@ func parseVolumeOptionsWithMountInfo(vType, src, optsRaw string, getMountInfoFun if len(writeModeRawOpts) > 1 { return nil, nil, fmt.Errorf("duplicated read/write volume option: %+v", writeModeRawOpts) - } else if len(writeModeRawOpts) > 0 && writeModeRawOpts[0] == "ro" { - opts = append(opts, "ro") - } // No need to return option when "rw" + } else if len(writeModeRawOpts) > 0 { + switch writeModeRawOpts[0] { + case "ro": + opts = append(opts, "ro") + case "rro": + // Mount option "rro" is supported since crun v1.4 / runc v1.1 (https://github.com/opencontainers/runc/pull/3272), with kernel >= 5.12. + // Older version of runc just ignores "rro", so we have to add "ro" too, to our best effort. + opts = append(opts, "ro", "rro") + if len(propagationRawOpts) != 1 || propagationRawOpts[0] != "rprivate" { + logrus.Warn("Mount option \"rro\" should be used in conjunction with \"rprivate\"") + } + case "rw": + // NOP + default: + // NOTREACHED + return nil, nil, fmt.Errorf("unexpected writeModeRawOpts[0]=%q", writeModeRawOpts[0]) + } + } if len(propagationRawOpts) > 1 { return nil, nil, fmt.Errorf("duplicated volume propagation option: %+v", propagationRawOpts)