Package: libpam-mount
Version: 2.14-1.1
Severity: minor
1. libpam_mount considers something "already mounted" if it can find a
mount in libmount's iterator where both the source (device) and
target (mountpoint) match.
This is the code responsible:
libpam-mount/src/mount.c:149:pmt_already_mounted()
libpam-mount/src/mount.c:125:pmt_utabent_matches()
THE PROBLEM
====================
2. If pam_mount.conf.xml has
<volume fstype="nfs" server="nfs" path="~" mountpoint="~" options="...">
then "already mounted?" fails because it compares nfs:/home/prisoners/p to
/home/prisoners/p. I think.
command: 'mount' '-onfsvers=3,intr,bg,nodev,noexec,nosuid' '-tnfs'
'nfs:/home/prisoners/p' '/home/prisoners/p'
(mount.c:72): Messages from underlying mount program:
(mount.c:76): mount.nfs: access denied by server while mounting (null)
The odd error from mount.nfs is because nfs:/home is root_squash and user
nobody can't read it:
# mkdir x y
# mount -tnfs nfs:/home x
# mount -tnfs nfs:/home x
mount.nfs: /root/x is busy or already mounted
# mount -tnfs nfs:/home/prisoners/p y
# mount -tnfs nfs:/home/prisoners/p y
mount.nfs: access denied by server while mounting (null)
# ls -ld x y
drwxr-x--x 8 root root 1024 Nov 12 2014 x
drwx------ 13 p p 4096 Sep 22 12:35 y
# ls -ld x/prisoners
drwxr-x--x 24 root root 1024 Sep 21 17:09 x/prisoners
WORKAROUNDS DON'T WORK
==============================
3. If pam_mount.conf.xml has
<volume fstype="nfs" path="nfs:~" mountpoint="~" options="...">
then mounting fails because the nfs:~ is not expanded.
command: 'mount' '-onfsvers=3,intr,bg,nodev,noexec,nosuid' '-tnfs' 'nfs:~'
'/home/prisoners/p'
(mount.c:72): Messages from underlying mount program:
(mount.c:76): mount.nfs: access denied by server while mounting nfs:~
4. If pam_mount.conf.xml has
<volume fstype="nfs" path="nfs:/home/prisoners/p" mountpoint="~"
options="...">
then mounting & detection both work:
(mount.c:628): nfs:/home/prisoners/p already seems to be mounted at
/home/prisoners/p, skipping
...but now I have to list every user's login individually, which is not
feasible.
5. If pam_mount.conf.xml has
<volume fstype="nfs" path="nfs:/home/prisoners/%(USER)" mountpoint="~"
options="...">
the source is wrong path for staff users.
Constructing $HOME from $USER also fails for setups like
~ajking2 ==> /home/students/a/j/ajking2/
which used to be common in large universities.
I could probably get away with this, but it feels awful:
<volume group="prisoners" fstype="nfs" path="nfs:/home/prisoners/%(USER)"
mountpoint="~" options="...">
<volume group="staff" fstype="nfs" path="nfs:/home/staff/%(USER)"
mountpoint="~" options="...">
IMPACT
====================
This is not an immediate problem for me,
because the duplicate mount fails & the login succeeds.
But! If the *first* mount fails (e.g. when NFS is down),
the user get a working login with $HOME on the local root filesystem.
If I fix that by making PAM abort when the mount fails,
the problem in pmt_utabent_matches() will break the user's second
concurrent login (e.g. GUI desktop + ssh).
I'm too dumb to see exactly how to patch this,
but I hope it's a one-line change. :-)
POSTSCRIPT
====================
I pulled out pmt_already_mounted() into the following stand-alone script,
to confirm that libmount could see the mountpoint:
bash4$ cat mount-test.c
/* #!/usr/bin/tcc -run -I/usr/include/libmount -I/usr/include/blkid
-I/usr/include/uuid -lmount */
/* bash4$ pkg-config --cflags --libs mount */
/* -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/uuid -lmount
*/
#include <libmount.h>
main()
{
struct libmnt_context *ctx;
struct libmnt_table *table;
struct libmnt_iter *iter;
struct libmnt_fs *fs;
const char *source, *target;
ctx = mnt_new_context();
if (ctx == NULL)
return -1;
if (mnt_context_get_mtab(ctx, &table) != 0)
goto out;
iter = mnt_new_iter(MNT_ITER_BACKWARD);
if (iter == NULL)
goto out;
while (mnt_table_next_fs(table, iter, &fs) == 0)
{
source = mnt_fs_get_source(fs);
target = mnt_fs_get_target(fs);
printf("source<%s> target<%s>\n",
source ?: "NULL",
target ?: "NULL");
}
out:
mnt_free_context(ctx);
return 0;
}
bash4$ cc mount-test.c $(pkg-config --cflags --libs mount)
bash4$ cat a.out | ssh x 'cat >a.out && chmod +x a.out && ./a.out'
Warning: Permanently added 'het' (ECDSA) to the list of known hosts.
source<tmpfs> target</run/user/10242>
source<nfs:/home/prisoners/p> target</home/prisoners/p>
source<tmpfs> target</run/user/0>
source<nfs:/srv/share> target</srv/share>
source<tmpfs> target</lib/live/mount>
source<tmpfs> target</tmp>
source<tmpfs> target</var/tmp>
source<pstore> target</sys/fs/pstore>
source<cgroup> target</sys/fs/cgroup/systemd>
source<tmpfs> target</sys/fs/cgroup>
source<tmpfs> target</run/lock>
source<devpts> target</dev/pts>
source<tmpfs> target</dev/shm>
source<securityfs> target</sys/kernel/security>
source<devtmpfs> target</dev>
source<aufs> target</>
source<tmpfs> target</lib/live/mount/overlay>
source</dev/loop0> target</lib/live/mount/rootfs/filesystem.squashfs>
source<10.128.0.1:/srv/netboot/images> target</lib/live/mount/medium>
source<tmpfs> target</run>
source<proc> target</proc>
source<sysfs> target</sys>
The full pam_mount.conf.xml I used for these tests was:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE pam_mount SYSTEM "pam_mount.conf.xml.dtd">
<pam_mount>
<debug enable="1" />
<volume fstype="nfs"
server="nfs"
path="~"
mountpoint="~"
options="nfsvers=3,intr,bg,nodev,noexec,nosuid">
<uid>1000-29999</uid>
</volume>
<mkmountpoint enable="1" remove="false" />
</pam_mount>