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>

Reply via email to