You are not logged in.

#1 2017-04-06 09:31:00

lastchancetosee
Member
From: Berlin
Registered: 2009-02-19
Posts: 129

[Solved] Overlaying a tmpfs using overlayfs and pam_mount

<edit: See my updated solution below.>

Hi,
I'm setting up a Guest account on my computer and want to use overlayfs to overlay a writeable tmpfs on a read-only home directory (derived from a squashfs). Ultimately, I'd like to use pam_mount to mount and unmount these filesystems, so that any changes the guest user has made, as well as his data, are automatically wiped upon logout.

Without using pam_mount, this is my setup, which works fine:

mkdir /tmp/guest
mount -t tmpfs -o size=100M none /tmp/guest
mkdir /tmp/guest/upper /tmp/guest/lower /tmp/guest/work
mount -t squashfs -o loop /home/guest.squashfs /tmp/guest/lower
mount -t overlay overlay -o lowerdir=/tmp/guest/lower,upperdir=/tmp/guest/upper,workdir=/tmp/guest/work /home/guest

Unfortunately, overlayfs needs workdir to be on the same filesystem as upperdir. So if upper is going to be on a tmpfs, I need to mount it first, then create the workdir and upperdir within it, then do the rest of the mounting. Directory creation is no problem with pam_exec, but pam_mount would have to hold off on mounting the overlay until after the dirs are created. Alternatively, pam_mount can create the mountpoints itself, but it then can't create workdir.

Any ideas how to work around that?

Another question: I've thought about using unionfs instead of overlayfs, because it does not need a workdir. According to the wiki, it is in the kernel as well, but if I try to use it, mount complains about unknown filesystem type. Do I have to load its module manually, and if so, how is it called?

Last edited by lastchancetosee (2017-04-14 12:18:30)


My ship don't crash! She crashes, you crashed her!

Offline

#2 2017-04-13 17:28:13

lastchancetosee
Member
From: Berlin
Registered: 2009-02-19
Posts: 129

Re: [Solved] Overlaying a tmpfs using overlayfs and pam_mount

OK, I figured it out.

Firstoff, I tried doing it with unionfs-fuse (which does not need a workdir), but ran into a whole hell of permission issues, so that was no fun.

The whole problem arises from wanting the overlayed data to be in a temporary file system that is removed when the user logs out, so that they do not leave any data behind for others to look at.

Stupid me: There is already such a filesystem. XDG_RUNTIME_DIR is created (at /run/user/<uid> by default) as a tmpfs by systemd and removed again after logout. Which means I can use pam_exec to create upperdir, lowerdir and workdir under XDG_RUNTIME_DIR, use pam_mount to mount the squashed home directory image to lowerdir and lowerdir and upperdir to the Guest account's  home directory with overlayfs.

Works flawlessly.

For future reference (edit names, uids and paths as needed):

Add to the end of /etc/security/pam_mount.conf.xml before </pam_mount>:

<!-- pam_mount parameters: Volume-related -->
<volume user="guest" fstype="squashfs" path="/home/guest.squashfs" mountpoint="/run/user/1001/home-overlay/basedir" options="noatime" />
<volume user="guest" fstype="overlay" path="overlay" mountpoint="/home/guest" options="lowerdir=/run/user/1001/home-overlay/basedir,upperdir=/run/user/1001/home-overlay/overlaydir,workdir=/run/user/1001/home-overlay/workdir" />
<mkmountpoint enable="1" remove="true" />

</pam_mount>

Create script /usr/local/bin/prepare-home-overlay to create mountpoints:

#!/bin/bash

# check to see if XDG_RUNTIME_DIR is set up properly
if [[ -d $XDG_RUNTIME_DIR ]]
then
  # create directories for overlayfs
  mkdir -p $XDG_RUNTIME_DIR/home-overlay/overlaydir
  mkdir $XDG_RUNTIME_DIR/home-overlay/basedir
  mkdir -p $XDG_RUNTIME_DIR/home-overlay/workdir
  # change ownership of dirs to PAM_USER and their group
  chown -R $PAM_USER:$(id -g $PAM_USER) $XDG_RUNTIME_DIR/home-overlay
  # other people should not be able to read these
  chmod -R go-rwx $XDG_RUNTIME_DIR/home-overlay
  exit 0
else
  # if XDG_RUNTIME_DIR does not exist, the script was probably called before systemd set it up
  >&2 echo "XDG runtime directory does not exist, this is a problem."
  >&2 echo "Maybe this script was called too early in the pam stack."
  exit 1
fi

As per the wiki, the call to pam_mount needs to be in a separate file to ensure proper unmounting. Create /etc/pam.d/guesthome:

#%PAM-1.0

auth      optional                   pam_exec.so seteuid /usr/local/bin/prepare-home-overlay
auth      optional                   pam_mount.so
password  optional                   pam_exec.so seteuid /usr/local/bin/prepare-home/overlay
password  optional                   pam_mount.so
session   optional                   pam_exec.so seteuid /usr/local/bin/prepare-home-overlay
session   optional                   pam_mount.so

and call it in /etc/pam.d/system-local-login, /etc/pam.d/system-lremote-login and potentially /etc/pam.d/<your display manager>:

#%PAM-1.0

auth      include   system-login
auth      include   guesthome
account   include   system-login
account   include   guesthome
password  include   system-login
password  include   guesthome
session   include   system-login
session   include   guesthome

Last edited by lastchancetosee (2017-04-13 19:28:02)


My ship don't crash! She crashes, you crashed her!

Offline

#3 2017-04-14 12:16:43

lastchancetosee
Member
From: Berlin
Registered: 2009-02-19
Posts: 129

Re: [Solved] Overlaying a tmpfs using overlayfs and pam_mount

You don't even need pam_mount, because pam_exec exports PAM_TYPE which can be, among others, open_session and close_session. Thus we can mount and unmount via pam_exec.

Script called by pam_exec:

#!/bin/bash

# check if we're opening or closing the session
case $PAM_TYPE in
open_session)
	# if XDG_RUNTIME_DIR is not set, we can't do anything
	if [[ ! -d $XDG_RUNTIME_DIR ]]; then exit 12; fi
	# create directories
	mkdir -p $XDG_RUNTIME_DIR/guestacc/upper
	mkdir $XDG_RUNTIME_DIR/guestacc/lower
	mkdir $XDG_RUNTIME_DIR/guestacc/work
	mkdir $XDG_RUNTIME_DIR/guestacc/merged
	# set ownership/permissions
	chown -R $PAM_USER:$(id -g $PAM_USER) $XDG_RUNTIME_DIR/guestacc
	chmod -R go-rwx $XDG_RUNTIME_DIR/guestacc
	# mount the account image and the overlay
	mount -t squashfs -o loop,noatime /home/$PAM_USER.squashfs $XDG_RUNTIME_DIR/guestacc/lower
	mount -t overlay overlay -o lowerdir=$XDG_RUNTIME_DIR/guestacc/lower,upperdir=$XDG_RUNTIME_DIR/guestacc/upper,workdir=$XDG_RUNTIME_DIR/guestacc/work $XDG_RUNTIME_DIR/guestacc/merged
	exit 0
	;;
close_session)
	# only unmount/remove stuff if it was mounted/present
	if mountpoint -q $XDG_RUNTIME_DIR/guestacc/merged; then umount $XDG_RUNTIME_DIR/guestacc/merged; fi
	if mountpoint -q $XDG_RUNTIME_DIR/guestacc/lower; then umount $XDG_RUNTIME_DIR/guestacc/lower; fi
	if [[ -d $XDG_RUNTIME_DIR/guestacc ]]; then rm -r $XDG_RUNTIME_DIR/guestacc; fi
	exit 0
	;;
*)
	# not in session stack, do nothing but don't fail
	exit 0
	;;
esac

Put this in /etc/pam.d/<filename called in system-local-login etc.> to make the script only run when a guest user logs in:

session [default=1 success=ignore] pam_succeed_if.so quiet user ingroup guestacc
session optional                   pam_exec seteuid /path/to/script

Add guest user to group 'guestacc', set their home directory to /run/user/<their uid>/guestacc/merged


My ship don't crash! She crashes, you crashed her!

Offline

Board footer

Powered by FluxBB