After going through the pam_mount code I believe I know what is
going on. The situation arises mainly from two issues:
From mount.c
in the pam_mount repo:
128 xcmp = fstype2_icase(vpt->type) ? strcasecmp : strcmp;
129 if (source != NULL)
130 result = xcmp(vpt->volume, source) == 0;
131 if (target != NULL)
132 result &= strcmp(vpt->mountpoint, target) == 0;
That’s it. The values for source and target are supplied by
libmount from util-linux. Unfortunately, libmount is able to
determine the original source path of a bind mount only if it
appears in /run/mount/utab
. PAM mountpoints don’t. Thus it’s
not sufficient for extending the above check.
However, for the bind mount
<volume
options="bind,nodev,exec,nosuid"
user="yourstruly"
mountpoint="/nix"
path="/mnt/local/nix"
/>
the kernel generates an entry in /proc/mounts
as follows:
/dev/mapper/VolGroup00-local /nix ext4 rw,relatime 0 0
where the source obviously doesn’t match the path we specified in
the mount(8) command line. Instead, it gives the underlying
volume as the source, causing the check by pam_mount to fail.
The source path information is lost. A bit better is
/proc/self/mountinfo
:
934 654 253:6 /nix /nix rw,relatime shared:33 - ext4 /dev/mapper/VolGroup00-local rw
Also according to the
libmount source
the first /nix
(arg index 4) corresponds to the “root of
the mount within the FS”. (The second one is the mountpoint in
VFS.) Thus, the original path passed to mount(8) is
substituted by the location inside the volume. With the volume
being mounted at /mnt/local
we end up with merely /nix
.
This value can be queried using an API (mnt_table_get_fs_root()
)
but it’s useless for pam_mount because the latter doesn’t strip
the mountpoint from the source value when performing the check.
pam_exec
could do it, but it sounds like you can't change the PAM configuration either.