Messages in this thread Patch in this message | | | Date | Wed, 23 Jul 1997 18:18:18 +0200 | From | "Volker.Lendecke" <> | Subject | fmount system call |
| |
-----BEGIN PGP SIGNED MESSAGE-----
Linus,
during the smbfs-rewrite I remembered the security problem in smbmount and ncpmount. Both programs are designed to let the user mount remote file systems of his own. This is necessary because the remote file systems are per-user password protected. To do this, they check whether the user has write permissions on the mount point and then mount the file. Playing with links between the check and the real mount creates quite well-known races.
As far as I can see this problem can be removed by a system call that accepts a file descriptor as a mount point. The following patch implements a fmount system call that does exactly this. It is a quick hack that has to be cleaned up. Before putting more work into this, I would like to ask whether this has could get into the standard kernel.
Regards,
Volker
diff -urN 2.1.46/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S - --- 2.1.46/arch/i386/kernel/entry.S Thu Jul 10 16:20:34 1997 +++ linux/arch/i386/kernel/entry.S Wed Jul 23 16:33:55 1997 @@ -528,6 +528,7 @@ .long SYMBOL_NAME(sys_nfsservctl) .long SYMBOL_NAME(sys_setresgid) /* 170 */ .long SYMBOL_NAME(sys_getresgid) - - .rept NR_syscalls-171 + .long SYMBOL_NAME(sys_fmount) + .rept NR_syscalls-172 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -urN 2.1.46/fs/super.c linux/fs/super.c - --- 2.1.46/fs/super.c Sat Jul 19 21:10:37 1997 +++ linux/fs/super.c Wed Jul 23 17:28:31 1997 @@ -89,7 +89,7 @@ /* NOTREACHED */ } - -struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name) +static struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name) { struct vfsmount *lptr; char *tmp; @@ -123,7 +123,7 @@ return (lptr); } - -void remove_vfsmnt(kdev_t dev) +static void remove_vfsmnt(kdev_t dev) { struct vfsmount *lptr, *tofree; @@ -945,6 +945,157 @@ } } retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page); + free_page(page); + if (retval && fops && fops->release) { + fops->release(inode, NULL); + put_unnamed_dev(dev); + } +dput_and_out: + dput(dentry); +out: + unlock_kernel(); + return retval; +} + +int do_fmount(kdev_t dev, const char * dev_name, struct dentry *dir_d, const char * type, int flags, void * data) +{ + struct super_block * sb; + struct vfsmount *vfsmnt; + int error; + + if (!(flags & MS_RDONLY) && dev && is_read_only(dev)) + return -EACCES; + /*flags |= MS_RDONLY;*/ + + dir_d = dget(dir_d); + error = PTR_ERR(dir_d); + if (IS_ERR(dir_d)) + return error; + + if (dir_d->d_covers != dir_d) { + dput(dir_d); + return -EBUSY; + } + if (!S_ISDIR(dir_d->d_inode->i_mode)) { + dput(dir_d); + return -ENOTDIR; + } + if (!fs_may_mount(dev)) { + dput(dir_d); + return -EBUSY; + } + sb = read_super(dev,type,flags,data,0); + if (!sb) { + dput(dir_d); + return -EINVAL; + } + if (sb->s_root->d_covers != sb->s_root) { + dput(dir_d); + return -EBUSY; + } + vfsmnt = add_vfsmnt(dev, dev_name, NULL); + if (vfsmnt) { + vfsmnt->mnt_sb = sb; + vfsmnt->mnt_flags = flags; + } + d_mount(dir_d, sb->s_root); + return 0; /* we don't dput(dir) - see umount */ +} + +asmlinkage int sys_fmount(char * dev_name, unsigned int fd, char * type, + unsigned long new_flags, void * data) +{ + struct file_system_type * fstype; + struct dentry * dentry = NULL; + struct inode * inode = NULL; + struct file_operations * fops; + kdev_t dev; + int retval = -EPERM; + const char * t; + unsigned long flags = 0; + unsigned long page = 0; + + struct file * dir_file; + struct dentry * dir_dentry; + + lock_kernel(); + if (!suser()) + goto out; + + if (fd >= NR_OPEN || + !(dir_file = current->files->fd[fd]) || + !(dir_dentry = dir_file->f_dentry)) { + retval = -EBADF; + goto out; + } + + if ((new_flags & + (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { + /* remounting is not possible here */ + retval = -EINVAL; + goto out; + } + retval = copy_mount_options (type, &page); + if (retval < 0) + goto out; + fstype = get_fs_type((char *) page); + free_page(page); + retval = -ENODEV; + if (!fstype) + goto out; + t = fstype->name; + fops = NULL; + if (fstype->fs_flags & FS_REQUIRES_DEV) { + dentry = namei(dev_name); + retval = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out; + + inode = dentry->d_inode; + retval = -ENOTBLK; + if (!S_ISBLK(inode->i_mode)) + goto dput_and_out; + + retval = -EACCES; + if (IS_NODEV(inode)) + goto dput_and_out; + + dev = inode->i_rdev; + retval = -ENXIO; + if (MAJOR(dev) >= MAX_BLKDEV) + goto dput_and_out; + + fops = get_blkfops(MAJOR(dev)); + retval = -ENOTBLK; + if (!fops) + goto dput_and_out; + + if (fops->open) { + struct file dummy; /* allows read-write or read-only flag */ + memset(&dummy, 0, sizeof(dummy)); + dummy.f_dentry = dentry; + dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3; + retval = fops->open(inode, &dummy); + if (retval) + goto dput_and_out; + } + + } else { + retval = -EMFILE; + if (!(dev = get_unnamed_dev())) + goto out; + } + + page = 0; + if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) { + flags = new_flags & ~MS_MGC_MSK; + retval = copy_mount_options(data, &page); + if (retval < 0) { + put_unnamed_dev(dev); + goto dput_and_out; + } + } + retval = do_fmount(dev,dev_name,dir_dentry,t,flags,(void *) page); free_page(page); if (retval && fops && fops->release) { fops->release(inode, NULL); diff -urN 2.1.46/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h - --- 2.1.46/include/asm-i386/unistd.h Thu Jul 10 16:20:54 1997 +++ linux/include/asm-i386/unistd.h Wed Jul 23 16:48:49 1997 @@ -177,6 +177,7 @@ #define __NR_nfsservctl 169 #define __NR_setresgid 170 #define __NR_getresgid 171 +#define __NR_fmount 172 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */ -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv iQCVAwUBM9YurT/9BWnmOc5FAQGk/wQAhyQYM4X2kZwxOuOzSxWitikUF8QeBIwe bxYSFi3SwcqNYIvos4dDxTI7ed3ou1yoGMi98sHZvB8yd5d1T/LCezuB47x0kWXl vQkaKEuexs89ubX9XX6q4FkJ9Dvz97I5GxKd408W1KWOgM04z5HvN4kdnhzHV3p3 am+WaRgG2Bk= =7wfw -----END PGP SIGNATURE-----
| |