[PATCH] do not mount the same filesystem on the same mount point

From: Andries Brouwer (aeb@veritas.com)
Date: Sun Sep 10 2000 - 15:43:46 EST


Dear Linus, Al, all:

Below a patch to prevent mounting the same filesystem
repeatedly on the same mount point. This 4-line patch is

+ /* Refuse the same filesystem on the same mount point */
+ retval = -EBUSY;
+ if (nd.mnt && nd.mnt->mnt_sb == sb
+ && nd.mnt->mnt_root == nd.dentry)
+ goto fail;

(If the user really wants to, she can still do this.
This patch is not needed for correctness or security,
but just to prevent the confusion that would arise when
each GUI click mounted the same fs on the same mount point.)

This patch also changes "-t bind" into "--bind",
i.e., recognizes a bind mount by the MS_BIND flags bit
rather than the "bind" type. Mount(8) already supports this.

(I do not think it is necessary to leave the "-t bind"
version for backwards compatibility. It has only existed
since 2.3.99-pre6. For the moment it is #ifdef'ed out.)

Here there is a security aspect: I did not change the
fact that every user can do this, but worry a little
about the fact that she could do this a million times,
running the kernel out of memory. It seems to me that
either capabilities should be required, or the memory
used should be charged to the user.

I also discarded the 0xC0ED magic, making it impossible
to use a pre-0.97 version of mount(8) together with a
2.4 kernel, and freeing up 16 more flag bits, in case
we should need them.

The rest is layout polishing.

Andries

---------------------------------------------------------
diff -u --recursive --new-file ../linux-2.4.0test8/linux/fs/super.c ./linux/fs/super.c
--- ../linux-2.4.0test8/linux/fs/super.c Thu Aug 24 14:05:01 2000
+++ ./linux/fs/super.c Sun Sep 10 20:37:56 2000
@@ -1303,20 +1303,21 @@
  * information (or be NULL).
  *
  * NOTE! As pre-0.97 versions of mount() didn't use this setup, the
- * flags have to have a special 16-bit magic number in the high word:
- * 0xC0ED. If this magic word isn't present, the flags and data info
- * aren't used, as the syscall assumes we are talking to an older
- * version that didn't understand them.
+ * flags used to have a special 16-bit magic number in the high word:
+ * 0xC0ED. If this magic number is present, the high word is discarded.
  */
 long do_mount(char * dev_name, char * dir_name, char *type_page,
- unsigned long new_flags, void *data_page)
+ unsigned long flags, void *data_page)
 {
         struct file_system_type * fstype;
         struct nameidata nd;
         struct vfsmount *mnt = NULL;
         struct super_block *sb;
         int retval = 0;
- unsigned long flags = 0;
+
+ /* Discard magic */
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
  
         /* Basic sanity checks */
 
@@ -1328,21 +1329,25 @@
         /* OK, looks good, now let's see what do they want */
 
         /* just change the flags? - capabilities are checked in do_remount() */
- if ((new_flags & (MS_MGC_MSK|MS_REMOUNT)) == (MS_MGC_VAL|MS_REMOUNT))
- return do_remount(dir_name, new_flags&~(MS_MGC_MSK|MS_REMOUNT),
- (char *) data_page);
-
- if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
- flags = new_flags & ~MS_MGC_MSK;
+ if (flags & MS_REMOUNT)
+ return do_remount(dir_name, flags & ~MS_REMOUNT,
+ (char *) data_page);
+
+ /* "mount --bind"? Equivalent to older "mount -t bind" */
+ /* No capabilities? What if users do thousands of these? */
+ if (flags & MS_BIND)
+ return do_loopback(dev_name, dir_name);
 
         /* For the rest we need the type */
 
         if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
                 return -EINVAL;
 
+#if 0 /* Can be deleted again. Introduced in patch-2.3.99-pre6 */
         /* loopback mount? This is special - requires fewer capabilities */
         if (strcmp(type_page, "bind")==0)
                 return do_loopback(dev_name, dir_name);
+#endif
 
         /* for the rest we _really_ need capabilities... */
         if (!capable(CAP_SYS_ADMIN))
@@ -1354,7 +1359,8 @@
                 return -ENODEV;
 
         /* ... and mountpoint. Do the lookup first to force automounting. */
- if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
+ if (path_init(dir_name,
+ LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd))
                 retval = path_walk(dir_name, &nd);
         if (retval)
                 goto fs_out;
@@ -1363,7 +1369,7 @@
         if (fstype->fs_flags & FS_NOMOUNT)
                 sb = ERR_PTR(-EINVAL);
         else if (fstype->fs_flags & FS_REQUIRES_DEV)
- sb = get_sb_bdev(fstype, dev_name,flags, data_page);
+ sb = get_sb_bdev(fstype, dev_name, flags, data_page);
         else if (fstype->fs_flags & FS_SINGLE)
                 sb = get_sb_single(fstype, flags, data_page);
         else
@@ -1376,6 +1382,13 @@
         /* Something was mounted here while we slept */
         while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
                 ;
+
+ /* Refuse the same filesystem on the same mount point */
+ retval = -EBUSY;
+ if (nd.mnt && nd.mnt->mnt_sb == sb
+ && nd.mnt->mnt_root == nd.dentry)
+ goto fail;
+
         retval = -ENOENT;
         if (!nd.dentry->d_inode)
                 goto fail;
@@ -1403,7 +1416,7 @@
 }
 
 asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
- unsigned long new_flags, void * data)
+ unsigned long flags, void * data)
 {
         int retval;
         unsigned long data_page;
@@ -1423,14 +1436,18 @@
         retval = copy_mount_options (dev_name, &dev_page);
         if (retval < 0)
                 goto out2;
+
         retval = copy_mount_options (data, &data_page);
- if (retval >= 0) {
- lock_kernel();
- retval = do_mount((char*)dev_page,dir_page,(char*)type_page,
- new_flags, (void*)data_page);
- unlock_kernel();
- free_page(data_page);
- }
+ if (retval < 0)
+ goto out3;
+
+ lock_kernel();
+ retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
+ flags, (void*)data_page);
+ unlock_kernel();
+ free_page(data_page);
+
+out3:
         free_page(dev_page);
 out2:
         putname(dir_page);
diff -u --recursive --new-file ../linux-2.4.0test8/linux/include/linux/fs.h ./linux/include/linux/fs.h
--- ../linux-2.4.0test8/linux/include/linux/fs.h Sat Sep 9 15:04:20 2000
+++ ./linux/include/linux/fs.h Sun Sep 10 09:27:32 2000
@@ -93,7 +93,7 @@
                                   * as nfs_rename() will be cleaned up
                                   */
 /*
- * These are the fs-independent mount-flags: up to 16 flags are supported
+ * These are the fs-independent mount-flags: up to 32 flags are supported
  */
 #define MS_RDONLY 1 /* Mount read-only */
 #define MS_NOSUID 2 /* Ignore suid and sgid bits */
@@ -104,6 +104,7 @@
 #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
 #define MS_NOATIME 1024 /* Do not update access times. */
 #define MS_NODIRATIME 2048 /* Do not update directory access times */
+#define MS_BIND 4096
 
 /*
  * Flags that can be altered by MS_REMOUNT
diff -u --recursive --new-file ../linux-2.4.0test8/linux/include/linux/mount.h ./linux/include/linux/mount.h
--- ../linux-2.4.0test8/linux/include/linux/mount.h Sat Jul 29 02:59:11 2000
+++ ./linux/include/linux/mount.h Sun Sep 10 09:01:36 2000
@@ -27,8 +27,7 @@
         struct list_head mnt_child; /* and going through their mnt_child */
         atomic_t mnt_count;
         int mnt_flags;
-
- char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
+ char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
         struct list_head mnt_list;
         uid_t mnt_owner;
 };

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Sep 15 2000 - 21:00:13 EST