COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name, const char __user *, dir_name, const char __user *, type, compat_ulong_t, flags, const void __user *, data) { char *kernel_type; void *options; char *kernel_dev; int retval; kernel_type = copy_mount_string(type); retval = PTR_ERR(kernel_type); if (IS_ERR(kernel_type)) goto out; kernel_dev = copy_mount_string(dev_name); retval = PTR_ERR(kernel_dev); if (IS_ERR(kernel_dev)) goto out1; options = copy_mount_options(data); retval = PTR_ERR(options); if (IS_ERR(options)) goto out2; if (kernel_type && options) { if (!strcmp(kernel_type, NCPFS_NAME)) { do_ncp_super_data_conv(options); } else if (!strcmp(kernel_type, NFS4_NAME)) { retval = -EINVAL; if (do_nfs4_super_data_conv(options)) goto out3; } } retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options); out3: kfree(options); out2: kfree(kernel_dev); out1: kfree(kernel_type); out: return retval; }
asmlinkage long jprobe_sys_mount_handler(char __user *dev_name, char __user *dir_name, char __user *type, unsigned long flags, void __user *data) { int ret = 0; char *kernel_type; char *kernel_dir; char *kernel_dev; unsigned long data_page; ret = copy_mount_string(type, &kernel_type); if (ret < 0) goto out_type; ret = copy_mount_string(dir_name, &kernel_dir); if (ret < 0) goto out_dir; ret = copy_mount_string(dev_name, &kernel_dev); if (ret < 0) goto out_dev; ret = copy_mount_options(data, &data_page); if (ret < 0) goto out_data; printk(KERN_INFO "%s() sys_mount(dev=%s, dir=%s, type=%s, flags=%lu)", __func__, kernel_dev, kernel_dir, kernel_type, flags); free_page(data_page); out_data: kfree(kernel_dev); out_dev: kfree(kernel_dir); out_dir: kfree(kernel_type); out_type: jprobe_return(); }
/* * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * NOTE! As old versions of mount() didn't use this setup, the flags * has to have a special 16-bit magic number in the hight word: * 0xC0ED. If this magic word isn't present, the flags and data info * isn't used, as the syscall assumes we are talking to an older * version that didn't understand them. */ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void * data) { struct file_system_type * fstype; struct inode * inode; struct file_operations * fops; kdev_t dev; int retval; const char * t; unsigned long flags = 0; unsigned long page = 0; if (!suser()) return -EPERM; if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { retval = copy_mount_options (data, &page); if (retval < 0) return retval; retval = do_remount(dir_name, new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, (char *) page); free_page(page); return retval; } retval = copy_mount_options (type, &page); if (retval < 0) return retval; fstype = get_fs_type((char *) page); free_page(page); if (!fstype) return -ENODEV; t = fstype->name; fops = NULL; if (fstype->requires_dev) { retval = namei(dev_name, &inode); if (retval) return retval; if (!S_ISBLK(inode->i_mode)) { iput(inode); return -ENOTBLK; } if (IS_NODEV(inode)) { iput(inode); return -EACCES; } dev = inode->i_rdev; if (MAJOR(dev) >= MAX_BLKDEV) { iput(inode); return -ENXIO; } fops = get_blkfops(MAJOR(dev)); if (!fops) { iput(inode); return -ENOTBLK; } if (fops->open) { struct file dummy; /* allows read-write or read-only flag */ memset(&dummy, 0, sizeof(dummy)); dummy.f_inode = inode; dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3; retval = fops->open(inode, &dummy); if (retval) { iput(inode); return retval; } } } else { if (!(dev = get_unnamed_dev())) return -EMFILE; inode = NULL; } 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) { iput(inode); return retval; } } retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page); free_page(page); if (retval && fops && fops->release) fops->release(inode, NULL); iput(inode); return retval; }
/* * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * NOTE! As old 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. */ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void * data) { struct file_system_type * fstype; struct dentry * dentry = NULL; struct inode * inode = NULL; kdev_t dev; int retval = -EPERM; unsigned long flags = 0; unsigned long page = 0; struct file dummy; /* allows read-write or read-only flag */ lock_kernel(); if (!capable(CAP_SYS_ADMIN)) goto out; if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { retval = copy_mount_options (data, &page); if (retval < 0) goto out; retval = do_remount(dir_name, new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, (char *) page); free_mount_page(page); goto out; } retval = copy_mount_options (type, &page); if (retval < 0) goto out; fstype = get_fs_type((char *) page); free_mount_page(page); retval = -ENODEV; if (!fstype) goto out; memset(&dummy, 0, sizeof(dummy)); 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; retval = -ENOTBLK; dummy.f_op = get_blkfops(MAJOR(dev)); if (!dummy.f_op) goto dput_and_out; if (dummy.f_op->open) { dummy.f_dentry = dentry; dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3; retval = dummy.f_op->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) goto clean_up; } retval = do_mount(dev, dev_name, dir_name, fstype->name, flags, (void *) page); free_mount_page(page); if (retval) goto clean_up; dput_and_out: dput(dentry); out: unlock_kernel(); return retval; clean_up: if (dummy.f_op) { if (dummy.f_op->release) dummy.f_op->release(inode, NULL); } else put_unnamed_dev(dev); goto dput_and_out; }