Skip to content

Commit

Permalink
Add support for ramfs as well as tmpfs in volume mounts
Browse files Browse the repository at this point in the history
Users want to mount a tmpfs file system with secrets, and make
sure the secret is never saved into swap. They can do this either
by using a ramfs tmpfs mount or by passing `noswap` option to
a tmpfs mount.

Fixes: containers#19659

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
  • Loading branch information
rhatdan committed Aug 21, 2023
1 parent 84447c0 commit 8901962
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 22 deletions.
23 changes: 13 additions & 10 deletions docs/source/markdown/options/mount.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,28 @@

Attach a filesystem mount to the container

Current supported mount TYPEs are **bind**, **devpts**, **glob**, **image**, **tmpfs** and **volume**. <sup>[[1]](#Footnote1)</sup>
Current supported mount TYPEs are **bind**, **devpts**, **glob**, **image**, **ramfs**, **tmpfs** and **volume**. <sup>[[1]](#Footnote1)</sup>

e.g.

type=bind,source=/path/on/host,destination=/path/in/container

type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared

type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true

type=devpts,destination=/dev/pts

type=glob,src=/usr/lib/libfoo*,destination=/usr/lib,ro=true

type=volume,source=vol1,destination=/path/in/container,ro=true
type=image,source=fedora,destination=/fedora-image,rw=true

type=ramfs,tmpfs-size=512M,destination=/path/in/container

type=tmpfs,tmpfs-size=512M,destination=/path/in/container

type=image,source=fedora,destination=/fedora-image,rw=true
type=tmpfs,destination=/path/in/container,noswap

type=devpts,destination=/dev/pts
type=volume,source=vol1,destination=/path/in/container,ro=true

Common Options:

Expand Down Expand Up @@ -72,17 +75,17 @@ Current supported mount TYPEs are **bind**, **devpts**, **glob**, **image**, **t

. U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container.

Options specific to tmpfs:
Options specific to tmpfs and ramfs:

· ro, readonly: true or false (default).

· tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux.
· tmpfs-size: Size of the tmpfs/ramfs mount in bytes. Unlimited by default in Linux.

· tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux.
· tmpfs-mode: File mode of the tmpfs/ramfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux.

· tmpcopyup: Enable copyup from the image directory at the same location to the tmpfs. Used by default.
· tmpcopyup: Enable copyup from the image directory at the same location to the tmpfs/ramfs. Used by default.

· notmpcopyup: Disable copying files from the image to the tmpfs.
· notmpcopyup: Disable copying files from the image to the tmpfs/ramfs.

. U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container.

Expand Down
10 changes: 6 additions & 4 deletions libpod/define/mount.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package define

const (
// TypeVolume is the type for named volumes
TypeVolume = "volume"
// TypeTmpfs is the type for mounting tmpfs
TypeTmpfs = "tmpfs"
// TypeDevpts is the type for creating a devpts
TypeDevpts = "devpts"
// TypeTmpfs is the type for mounting tmpfs
TypeTmpfs = "tmpfs"
// TypeRamfs is the type for mounting ramfs
TypeRamfs = "ramfs"
// TypeVolume is the type for named volumes
TypeVolume = "volume"
)
24 changes: 17 additions & 7 deletions pkg/specgenutil/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/parse"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -211,8 +212,8 @@ func Mounts(mountFlag []string, configMounts []string) (map[string]spec.Mount, m
}
finalMounts[mount.Destination] = mount
}
case define.TypeTmpfs:
mount, err := getTmpfsMount(tokens)
case define.TypeTmpfs, define.TypeRamfs:
mount, err := parseMemoryMount(tokens, mountType)
if err != nil {
return err
}
Expand Down Expand Up @@ -282,7 +283,7 @@ func Mounts(mountFlag []string, configMounts []string) (map[string]spec.Mount, m
}

func parseMountOptions(mountType string, args []string) (*spec.Mount, error) {
var setTmpcopyup, setRORW, setSuid, setDev, setExec, setRelabel, setOwnership bool
var setTmpcopyup, setRORW, setSuid, setDev, setExec, setRelabel, setOwnership, setSwap bool

mnt := spec.Mount{}
for _, val := range args {
Expand Down Expand Up @@ -359,6 +360,15 @@ func parseMountOptions(mountType string, args []string) (*spec.Mount, error) {
}
setSuid = true
mnt.Options = append(mnt.Options, kv[0])
case "noswap":
if setSwap {
return nil, fmt.Errorf("cannot pass 'noswap' mnt.Options more than once: %w", errOptionArg)
}
if rootless.IsRootless() {
return nil, fmt.Errorf("the 'noswap' option is only allowed with rootful tmpfs mounts: %w", errOptionArg)
}
setSwap = true
mnt.Options = append(mnt.Options, kv[0])
case "relabel":
if setRelabel {
return nil, fmt.Errorf("cannot pass 'relabel' option more than once: %w", errOptionArg)
Expand Down Expand Up @@ -525,11 +535,11 @@ func getBindMount(args []string) (spec.Mount, error) {
return newMount, nil
}

// Parse a single tmpfs mount entry from the --mount flag
func getTmpfsMount(args []string) (spec.Mount, error) {
// Parse a single tmpfs/ramfs mount entry from the --mount flag
func parseMemoryMount(args []string, mountType string) (spec.Mount, error) {
newMount := spec.Mount{
Type: define.TypeTmpfs,
Source: define.TypeTmpfs,
Type: mountType,
Source: mountType,
}

var err error
Expand Down
17 changes: 16 additions & 1 deletion pkg/util/mountOpts.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/rootless"
)

var (
Expand All @@ -27,7 +28,7 @@ type defaultMountOptions struct {
// The sourcePath variable, if not empty, contains a bind mount source.
func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string, error) {
var (
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ, foundU, foundOverlay, foundIdmap, foundCopy bool
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ, foundU, foundOverlay, foundIdmap, foundCopy, foundNoSwap bool
)

newOptions := make([]string, 0, len(options))
Expand Down Expand Up @@ -133,6 +134,20 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
foundCopyUp = true
// do not propagate notmpcopyup to the OCI runtime
continue
case "noswap":

if !isTmpfs {
return nil, fmt.Errorf("the 'noswap' option is only allowed with tmpfs mounts: %w", ErrBadMntOption)
}
if rootless.IsRootless() {
return nil, fmt.Errorf("the 'noswap' option is only allowed with rootful tmpfs mounts: %w", ErrBadMntOption)
}
if foundNoSwap {
return nil, fmt.Errorf("the 'tmpswap' option can only be set once: %w", ErrDupeMntOption)
}
foundNoSwap = true
newOptions = append(newOptions, opt)
continue
case define.TypeBind, "rbind":
if isTmpfs {
return nil, fmt.Errorf("the 'bind' and 'rbind' options are not allowed with tmpfs mounts: %w", ErrBadMntOption)
Expand Down
14 changes: 14 additions & 0 deletions test/system/060-mount.bats
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,18 @@ EOF
is "$output" "bar1.*bar2.*bar3" "Should match multiple source files on single destination directory"
}

@test "podman mount noswap memory mounts" {
# if volumes source and dest match then pass
run_podman run --rm --mount type=ramfs,destination=${PODMAN_TMPDIR} $IMAGE stat -f -c "%T" ${PODMAN_TMPDIR}
is "$output" "ramfs" "ramfs mounted"

if is_rootless; then
run_podman 125 run --rm --mount type=tmpfs,destination=${PODMAN_TMPDIR},noswap $IMAGE stat -f -c "%T" ${PODMAN_TMPDIR}
is "$output" "Error: the 'noswap' option is only allowed with rootful tmpfs mounts: must provide an argument for option" "noswap not supported in rootless mode"
else
run_podman run --rm --mount type=tmpfs,destination=${PODMAN_TMPDIR},noswap $IMAGE sh -c "mount| grep ${PODMAN_TMPDIR}"
is "$output" ".*noswap" "tmpfs noswap mounted"
fi
}

# vim: filetype=sh

0 comments on commit 8901962

Please sign in to comment.