Commit 27da3461 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] consolidate compat_sys_mount

This replaces six duplicated implementations of various quality of
sys32_mount with a shiny new compat_sys_mount().

It's been tested on parisc64 and sparc64 and fixes a bug exposed by the
latest revision of Debian's initscripts.  Thanks to Arnd Bergmann and
Dave Miller for their suggestions, fixes and testing.  Please apply.
parent 72a3b209
......@@ -229,7 +229,7 @@ ia32_syscall_table:
data8 sys_ni_syscall
data8 sys32_lseek
data8 sys_getpid /* 20 */
data8 sys_mount
data8 compat_sys_mount
data8 sys_oldumount
data8 sys_setuid /* 16-bit version */
data8 sys_getuid /* 16-bit version */
......
......@@ -34,9 +34,6 @@
#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
#include <linux/ncp_fs.h>
#include <linux/quota.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
......@@ -2384,157 +2381,6 @@ long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */
struct ncp_mount_data32 {
int version;
unsigned int ncp_fd;
compat_uid_t mounted_uid;
int wdog_pid;
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
unsigned int time_out;
unsigned int retry_count;
unsigned int flags;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *
do_ncp_super_data_conv(void *raw_data)
{
struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
n->dir_mode = n32->dir_mode;
n->file_mode = n32->file_mode;
n->gid = n32->gid;
n->uid = n32->uid;
memmove (n->mounted_vol, n32->mounted_vol,
(sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
n->wdog_pid = n32->wdog_pid;
n->mounted_uid = n32->mounted_uid;
return raw_data;
}
struct smb_mount_data32 {
int version;
compat_uid_t mounted_uid;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *
do_smb_super_data_conv(void *raw_data)
{
struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
if (s32->version != SMB_MOUNT_OLDVERSION)
goto out;
s->version = s32->version;
s->mounted_uid = s32->mounted_uid;
s->uid = s32->uid;
s->gid = s32->gid;
s->file_mode = s32->file_mode;
s->dir_mode = s32->dir_mode;
out:
return raw_data;
}
static int
copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
{
int i;
unsigned long page;
struct vm_area_struct *vma;
*kernel = 0;
if(!user)
return 0;
vma = find_vma(current->mm, (unsigned long)user);
if(!vma || (unsigned long)user < vma->vm_start)
return -EFAULT;
if(!(vma->vm_flags & VM_READ))
return -EFAULT;
i = vma->vm_end - (unsigned long) user;
if(PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE - 1;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
if(copy_from_user((void *) page, user, i)) {
free_page(page);
return -EFAULT;
}
*kernel = page;
return 0;
}
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
asmlinkage long
sys32_mount(char *dev_name, char *dir_name, char *type,
unsigned long new_flags, u32 data)
{
unsigned long type_page;
int err, is_smb, is_ncp;
if(!capable(CAP_SYS_ADMIN))
return -EPERM;
is_smb = is_ncp = 0;
err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
if(err)
return err;
if(type_page) {
is_smb = !strcmp((char *)type_page, SMBFS_NAME);
is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
}
if(!is_smb && !is_ncp) {
if(type_page)
free_page(type_page);
return sys_mount(dev_name, dir_name, type, new_flags,
(void *)AA(data));
} else {
unsigned long dev_page, dir_page, data_page;
err = copy_mount_stuff_to_kernel((const void *)dev_name,
&dev_page);
if(err)
goto out;
err = copy_mount_stuff_to_kernel((const void *)dir_name,
&dir_page);
if(err)
goto dev_out;
err = copy_mount_stuff_to_kernel((const void *)AA(data),
&data_page);
if(err)
goto dir_out;
if(is_ncp)
do_ncp_super_data_conv((void *)data_page);
else if(is_smb)
do_smb_super_data_conv((void *)data_page);
else
panic("The problem is here...");
err = do_mount((char *)dev_page, (char *)dir_page,
(char *)type_page, new_flags,
(void *)data_page);
if(data_page)
free_page(data_page);
dir_out:
if(dir_page)
free_page(dir_page);
dev_out:
if(dev_page)
free_page(dev_page);
out:
if(type_page)
free_page(type_page);
return err;
}
}
asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid)
{
uid_t sruid, seuid;
......
......@@ -607,105 +607,6 @@ sys32_readdir (unsigned int fd, void * dirent, unsigned int count)
return error;
}
static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
{
int i;
unsigned long page;
struct vm_area_struct *vma;
*kernel = 0;
if(!user)
return 0;
vma = find_vma(current->mm, (unsigned long)user);
if(!vma || (unsigned long)user < vma->vm_start)
return -EFAULT;
if(!(vma->vm_flags & VM_READ))
return -EFAULT;
i = vma->vm_end - (unsigned long) user;
if(PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE - 1;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
if(copy_from_user((void *) page, user, i)) {
free_page(page);
return -EFAULT;
}
*kernel = page;
return 0;
}
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
{
unsigned long type_page = 0;
unsigned long data_page = 0;
unsigned long dev_page = 0;
unsigned long dir_page = 0;
int err, is_smb, is_ncp;
is_smb = is_ncp = 0;
err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
if (err)
goto out;
if (!type_page) {
err = -EINVAL;
goto out;
}
is_smb = !strcmp((char *)type_page, SMBFS_NAME);
is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
err = copy_mount_stuff_to_kernel((const void *)(unsigned long)data, &data_page);
if (err)
goto type_out;
err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
if (err)
goto data_out;
err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
if (err)
goto dev_out;
if (!is_smb && !is_ncp) {
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
} else {
if (is_ncp)
panic("NCP mounts not yet supported 32/64 parisc");
/* do_ncp_super_data_conv((void *)data_page); */
else {
panic("SMB mounts not yet supported 32/64 parisc");
/* do_smb_super_data_conv((void *)data_page); */
}
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
}
free_page(dir_page);
dev_out:
free_page(dev_page);
data_out:
free_page(data_page);
type_out:
free_page(type_page);
out:
return err;
}
/* readv/writev stolen from mips64 */
typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
......
......@@ -84,7 +84,7 @@
ENTRY_DIFF(lseek)
ENTRY_SAME(getpid) /* 20 */
/* the 'void * data' parameter may need re-packing in wide */
ENTRY_DIFF(mount)
ENTRY_COMP(mount)
/* concerned about struct sockaddr in wide/narrow */
/* ---> I think sockaddr is OK unless the compiler packs the struct */
/* differently to align the char array */
......
......@@ -593,7 +593,7 @@ _GLOBAL(sys_call_table32)
.llong .sys_ni_syscall /* old stat syscall */
.llong .ppc32_lseek
.llong .sys_getpid /* 20 */
.llong .sys32_mount
.llong .compat_sys_mount
.llong .sys_oldumount
.llong .sys_setuid
.llong .sys_getuid
......
......@@ -35,9 +35,6 @@
#include <linux/uio.h>
#include <linux/aio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
#include <linux/ncp_fs.h>
#include <linux/module.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
......@@ -253,209 +250,6 @@ asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, u32 count)
return ret;
}
struct ncp_mount_data32_v3 {
int version;
unsigned int ncp_fd;
compat_uid_t mounted_uid;
compat_pid_t wdog_pid;
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
unsigned int time_out;
unsigned int retry_count;
unsigned int flags;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
struct ncp_mount_data32_v4 {
int version;
/* all members below are "long" in ABI ... i.e. 32bit on sparc32, while 64bits on sparc64 */
unsigned int flags;
unsigned int mounted_uid;
int wdog_pid;
unsigned int ncp_fd;
unsigned int time_out;
unsigned int retry_count;
unsigned int uid;
unsigned int gid;
unsigned int file_mode;
unsigned int dir_mode;
};
static void *do_ncp_super_data_conv(void *raw_data)
{
switch (*(int*)raw_data) {
case NCP_MOUNT_VERSION:
{
struct ncp_mount_data news, *n = &news;
struct ncp_mount_data32_v3 *n32 = (struct ncp_mount_data32_v3 *)raw_data;
n->version = n32->version;
n->ncp_fd = n32->ncp_fd;
n->mounted_uid = n32->mounted_uid;
n->wdog_pid = n32->wdog_pid;
memmove (n->mounted_vol, n32->mounted_vol, sizeof (n32->mounted_vol));
n->time_out = n32->time_out;
n->retry_count = n32->retry_count;
n->flags = n32->flags;
n->uid = n32->uid;
n->gid = n32->gid;
n->file_mode = n32->file_mode;
n->dir_mode = n32->dir_mode;
memcpy(raw_data, n, sizeof(*n));
}
break;
case NCP_MOUNT_VERSION_V4:
{
struct ncp_mount_data_v4 news, *n = &news;
struct ncp_mount_data32_v4 *n32 = (struct ncp_mount_data32_v4 *)raw_data;
n->version = n32->version;
n->flags = n32->flags;
n->mounted_uid = n32->mounted_uid;
n->wdog_pid = n32->wdog_pid;
n->ncp_fd = n32->ncp_fd;
n->time_out = n32->time_out;
n->retry_count = n32->retry_count;
n->uid = n32->uid;
n->gid = n32->gid;
n->file_mode = n32->file_mode;
n->dir_mode = n32->dir_mode;
memcpy(raw_data, n, sizeof(*n));
}
break;
default:
/* do not touch unknown structures */
break;
}
return raw_data;
}
struct smb_mount_data32 {
int version;
compat_uid_t mounted_uid;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *do_smb_super_data_conv(void *raw_data)
{
struct smb_mount_data news, *s = &news;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
if (s32->version != SMB_MOUNT_OLDVERSION)
goto out;
s->version = s32->version;
s->mounted_uid = s32->mounted_uid;
s->uid = s32->uid;
s->gid = s32->gid;
s->file_mode = s32->file_mode;
s->dir_mode = s32->dir_mode;
memcpy(raw_data, s, sizeof(struct smb_mount_data));
out:
return raw_data;
}
static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
{
int i;
unsigned long page;
struct vm_area_struct *vma;
*kernel = 0;
if(!user)
return 0;
vma = find_vma(current->mm, (unsigned long)user);
if(!vma || (unsigned long)user < vma->vm_start)
return -EFAULT;
if(!(vma->vm_flags & VM_READ))
return -EFAULT;
i = vma->vm_end - (unsigned long) user;
if(PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE - 1;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
if(copy_from_user((void *) page, user, i)) {
free_page(page);
return -EFAULT;
}
*kernel = page;
return 0;
}
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
asmlinkage long sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
{
unsigned long type_page = 0;
unsigned long data_page = 0;
unsigned long dev_page = 0;
unsigned long dir_page = 0;
int err, is_smb, is_ncp;
is_smb = is_ncp = 0;
err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
if (err)
goto out;
if (!type_page) {
err = -EINVAL;
goto out;
}
is_smb = !strcmp((char *)type_page, SMBFS_NAME);
is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
if (err)
goto type_out;
err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
if (err)
goto data_out;
err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
if (err)
goto dev_out;
if (!is_smb && !is_ncp) {
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
} else {
if (is_ncp)
do_ncp_super_data_conv((void *)data_page);
else
do_smb_super_data_conv((void *)data_page);
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
}
free_page(dir_page);
dev_out:
free_page(dev_page);
data_out:
free_page(data_page);
type_out:
free_page(type_page);
out:
return err;
}
/* readdir & getdents */
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
......
......@@ -35,9 +35,6 @@
#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
#include <linux/ncp_fs.h>
#include <linux/quota.h>
#include <linux/module.h>
#include <linux/sunrpc/svc.h>
......@@ -828,157 +825,6 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
return err;
}
struct ncp_mount_data32 {
int version;
unsigned int ncp_fd;
compat_uid_t mounted_uid;
compat_pid_t wdog_pid;
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
unsigned int time_out;
unsigned int retry_count;
unsigned int flags;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *do_ncp_super_data_conv(void *raw_data)
{
struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
n->dir_mode = n32->dir_mode;
n->file_mode = n32->file_mode;
n->gid = low2highgid(n32->gid);
n->uid = low2highuid(n32->uid);
memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
n->wdog_pid = n32->wdog_pid;
n->mounted_uid = low2highuid(n32->mounted_uid);
return raw_data;
}
struct smb_mount_data32 {
int version;
compat_uid_t mounted_uid;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *do_smb_super_data_conv(void *raw_data)
{
struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
if (s32->version != SMB_MOUNT_OLDVERSION)
goto out;
s->version = s32->version;
s->mounted_uid = low2highuid(s32->mounted_uid);
s->uid = low2highuid(s32->uid);
s->gid = low2highgid(s32->gid);
s->file_mode = s32->file_mode;
s->dir_mode = s32->dir_mode;
out:
return raw_data;
}
static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
{
int i;
unsigned long page;
struct vm_area_struct *vma;
*kernel = 0;
if(!user)
return 0;
vma = find_vma(current->mm, (unsigned long)user);
if(!vma || (unsigned long)user < vma->vm_start)
return -EFAULT;
if(!(vma->vm_flags & VM_READ))
return -EFAULT;
i = vma->vm_end - (unsigned long) user;
if(PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE - 1;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
if(copy_from_user((void *) page, user, i)) {
free_page(page);
return -EFAULT;
}
*kernel = page;
return 0;
}
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
{
unsigned long type_page = 0;
unsigned long data_page = 0;
unsigned long dev_page = 0;
unsigned long dir_page = 0;
int err, is_smb, is_ncp;
is_smb = is_ncp = 0;
err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
if (err)
goto out;
if (!type_page) {
err = -EINVAL;
goto out;
}
is_smb = !strcmp((char *)type_page, SMBFS_NAME);
is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
if (err)
goto type_out;
err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
if (err)
goto data_out;
err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
if (err)
goto dev_out;
if (!is_smb && !is_ncp) {
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
} else {
if (is_ncp)
do_ncp_super_data_conv((void *)data_page);
else
do_smb_super_data_conv((void *)data_page);
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
}
free_page(dir_page);
dev_out:
free_page(dev_page);
data_out:
free_page(data_page);
type_out:
free_page(type_page);
out:
return err;
}
struct sysinfo32 {
s32 uptime;
u32 loads[3];
......
......@@ -102,7 +102,7 @@ sys32_mount_wrapper:
llgtr %r4,%r4 # char *
llgfr %r5,%r5 # unsigned long
llgtr %r6,%r6 # void *
jg sys32_mount # branch to system call
jg compat_sys_mount # branch to system call
.globl sys32_oldumount_wrapper
sys32_oldumount_wrapper:
......
......@@ -27,9 +27,6 @@
#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
#include <linux/ncp_fs.h>
#include <linux/quota.h>
#include <linux/module.h>
#include <linux/sunrpc/svc.h>
......@@ -1329,209 +1326,6 @@ asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
return sys_sysfs(option, arg1, arg2);
}
struct ncp_mount_data32_v3 {
int version;
unsigned int ncp_fd;
compat_uid_t mounted_uid;
compat_pid_t wdog_pid;
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
unsigned int time_out;
unsigned int retry_count;
unsigned int flags;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
struct ncp_mount_data32_v4 {
int version;
/* all members below are "long" in ABI ... i.e. 32bit on sparc32, while 64bits on sparc64 */
unsigned int flags;
unsigned int mounted_uid;
int wdog_pid;
unsigned int ncp_fd;
unsigned int time_out;
unsigned int retry_count;
unsigned int uid;
unsigned int gid;
unsigned int file_mode;
unsigned int dir_mode;
};
static void *do_ncp_super_data_conv(void *raw_data)
{
switch (*(int*)raw_data) {
case NCP_MOUNT_VERSION:
{
struct ncp_mount_data news, *n = &news;
struct ncp_mount_data32_v3 *n32 = (struct ncp_mount_data32_v3 *)raw_data;
n->version = n32->version;
n->ncp_fd = n32->ncp_fd;
n->mounted_uid = low2highuid(n32->mounted_uid);
n->wdog_pid = n32->wdog_pid;
memmove (n->mounted_vol, n32->mounted_vol, sizeof (n32->mounted_vol));
n->time_out = n32->time_out;
n->retry_count = n32->retry_count;
n->flags = n32->flags;
n->uid = low2highuid(n32->uid);
n->gid = low2highgid(n32->gid);
n->file_mode = n32->file_mode;
n->dir_mode = n32->dir_mode;
memcpy(raw_data, n, sizeof(*n));
}
break;
case NCP_MOUNT_VERSION_V4:
{
struct ncp_mount_data_v4 news, *n = &news;
struct ncp_mount_data32_v4 *n32 = (struct ncp_mount_data32_v4 *)raw_data;
n->version = n32->version;
n->flags = n32->flags;
n->mounted_uid = n32->mounted_uid;
n->wdog_pid = n32->wdog_pid;
n->ncp_fd = n32->ncp_fd;
n->time_out = n32->time_out;
n->retry_count = n32->retry_count;
n->uid = n32->uid;
n->gid = n32->gid;
n->file_mode = n32->file_mode;
n->dir_mode = n32->dir_mode;
memcpy(raw_data, n, sizeof(*n));
}
break;
default:
/* do not touch unknown structures */
break;
}
return raw_data;
}
struct smb_mount_data32 {
int version;
compat_uid_t mounted_uid;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *do_smb_super_data_conv(void *raw_data)
{
struct smb_mount_data news, *s = &news;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
if (s32->version != SMB_MOUNT_OLDVERSION)
goto out;
s->version = s32->version;
s->mounted_uid = low2highuid(s32->mounted_uid);
s->uid = low2highuid(s32->uid);
s->gid = low2highgid(s32->gid);
s->file_mode = s32->file_mode;
s->dir_mode = s32->dir_mode;
memcpy(raw_data, s, sizeof(struct smb_mount_data));
out:
return raw_data;
}
static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
{
int i;
unsigned long page;
struct vm_area_struct *vma;
*kernel = 0;
if(!user)
return 0;
vma = find_vma(current->mm, (unsigned long)user);
if(!vma || (unsigned long)user < vma->vm_start)
return -EFAULT;
if(!(vma->vm_flags & VM_READ))
return -EFAULT;
i = vma->vm_end - (unsigned long) user;
if(PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE - 1;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
if(copy_from_user((void *) page, user, i)) {
free_page(page);
return -EFAULT;
}
*kernel = page;
return 0;
}
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
{
unsigned long type_page = 0;
unsigned long data_page = 0;
unsigned long dev_page = 0;
unsigned long dir_page = 0;
int err, is_smb, is_ncp;
is_smb = is_ncp = 0;
err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
if (err)
goto out;
if (!type_page) {
err = -EINVAL;
goto out;
}
is_smb = !strcmp((char *)type_page, SMBFS_NAME);
is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
if (err)
goto type_out;
err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
if (err)
goto data_out;
err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
if (err)
goto dev_out;
if (!is_smb && !is_ncp) {
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
} else {
if (is_ncp)
do_ncp_super_data_conv((void *)data_page);
else
do_smb_super_data_conv((void *)data_page);
lock_kernel();
err = do_mount((char*)dev_page, (char*)dir_page,
(char*)type_page, new_flags, (char*)data_page);
unlock_kernel();
}
free_page(dir_page);
dev_out:
free_page(dev_page);
data_out:
free_page(data_page);
type_out:
free_page(type_page);
out:
return err;
}
struct sysinfo32 {
s32 uptime;
u32 loads[3];
......
......@@ -52,7 +52,7 @@ sys_call_table32:
/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
.word compat_sys_fcntl64, sys_ni_syscall, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
/*160*/ .word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
.word sys_quotactl, sys_set_tid_address, sys32_mount, sys_ustat, sys_setxattr
.word sys_quotactl, sys_set_tid_address, compat_sys_mount, sys_ustat, sys_setxattr
/*170*/ .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
/*180*/ .word sys_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
......
......@@ -326,7 +326,7 @@ ia32_sys_call_table:
.quad sys_stat
.quad sys32_lseek
.quad sys_getpid /* 20 */
.quad sys_mount /* mount */
.quad compat_sys_mount /* mount */
.quad sys_oldumount /* old_umount */
.quad sys_setuid16
.quad sys_getuid16
......
......@@ -40,9 +40,6 @@
#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
#include <linux/smb_mount.h>
#include <linux/ncp_fs.h>
#include <linux/quota.h>
#include <linux/module.h>
#include <linux/sunrpc/svc.h>
......@@ -874,39 +871,6 @@ sys32_sysfs(int option, u32 arg1, u32 arg2)
return sys_sysfs(option, arg1, arg2);
}
static char *badfs[] = {
"smbfs", "ncpfs", NULL
};
static int checktype(char *user_type)
{
int err = 0;
char **s,*kernel_type = getname(user_type);
if (!kernel_type || IS_ERR(kernel_type))
return -EFAULT;
for (s = badfs; *s; ++s)
if (!strcmp(kernel_type, *s)) {
printk(KERN_ERR "mount32: unsupported fs `%s' -- use 64bit mount\n", *s);
err = -EINVAL;
break;
}
putname(user_type);
return err;
}
asmlinkage long
sys32_mount(char *dev_name, char *dir_name, char *type,
unsigned long new_flags, u32 data)
{
int err;
if(!capable(CAP_SYS_ADMIN))
return -EPERM;
err = checktype(type);
if (err)
return err;
return sys_mount(dev_name, dir_name, type, new_flags, (void *)AA(data));
}
struct sysinfo32 {
s32 uptime;
u32 loads[3];
......
......@@ -27,6 +27,9 @@
#include <linux/ioctl32.h>
#include <linux/init.h>
#include <linux/sockios.h> /* for SIOCDEVPRIVATE */
#include <linux/smb.h>
#include <linux/smb_mount.h>
#include <linux/ncp_mount.h>
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/ctype.h>
......@@ -642,3 +645,152 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 *iocb)
ret = sys_io_submit(ctx_id, nr, iocb64);
return ret;
}
struct compat_ncp_mount_data {
compat_int_t version;
compat_uint_t ncp_fd;
compat_uid_t mounted_uid;
compat_pid_t wdog_pid;
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
compat_uint_t time_out;
compat_uint_t retry_count;
compat_uint_t flags;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
struct compat_ncp_mount_data_v4 {
compat_int_t version;
compat_ulong_t flags;
compat_ulong_t mounted_uid;
compat_long_t wdog_pid;
compat_uint_t ncp_fd;
compat_uint_t time_out;
compat_uint_t retry_count;
compat_ulong_t uid;
compat_ulong_t gid;
compat_ulong_t file_mode;
compat_ulong_t dir_mode;
};
static void *do_ncp_super_data_conv(void *raw_data)
{
int version = *(unsigned int *)raw_data;
if (version == 3) {
struct compat_ncp_mount_data *c_n = raw_data;
struct ncp_mount_data *n = raw_data;
n->dir_mode = c_n->dir_mode;
n->file_mode = c_n->file_mode;
n->gid = c_n->gid;
n->uid = c_n->uid;
memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
n->wdog_pid = c_n->wdog_pid;
n->mounted_uid = c_n->mounted_uid;
} else if (version == 4) {
struct compat_ncp_mount_data_v4 *c_n = raw_data;
struct ncp_mount_data_v4 *n = raw_data;
n->dir_mode = c_n->dir_mode;
n->file_mode = c_n->file_mode;
n->gid = c_n->gid;
n->uid = c_n->uid;
n->retry_count = c_n->retry_count;
n->time_out = c_n->time_out;
n->ncp_fd = c_n->ncp_fd;
n->wdog_pid = c_n->wdog_pid;
n->mounted_uid = c_n->mounted_uid;
n->flags = c_n->flags;
} else if (version != 5) {
return NULL;
}
return raw_data;
}
struct compat_smb_mount_data {
compat_int_t version;
compat_uid_t mounted_uid;
compat_uid_t uid;
compat_gid_t gid;
compat_mode_t file_mode;
compat_mode_t dir_mode;
};
static void *do_smb_super_data_conv(void *raw_data)
{
struct smb_mount_data *s = raw_data;
struct compat_smb_mount_data *c_s = raw_data;
if (c_s->version != SMB_MOUNT_OLDVERSION)
goto out;
s->dir_mode = c_s->dir_mode;
s->file_mode = c_s->file_mode;
s->gid = c_s->gid;
s->uid = c_s->uid;
s->mounted_uid = c_s->mounted_uid;
out:
return raw_data;
}
extern int copy_mount_options (const void __user *, unsigned long *);
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
asmlinkage int compat_sys_mount(char __user * dev_name, char __user * dir_name,
char __user * type, unsigned long flags,
void __user * data)
{
unsigned long type_page;
unsigned long data_page;
unsigned long dev_page;
char *dir_page;
int retval;
retval = copy_mount_options (type, &type_page);
if (retval < 0)
goto out;
dir_page = getname(dir_name);
retval = PTR_ERR(dir_page);
if (IS_ERR(dir_page))
goto out1;
retval = copy_mount_options (dev_name, &dev_page);
if (retval < 0)
goto out2;
retval = copy_mount_options (data, &data_page);
if (retval < 0)
goto out3;
retval = -EINVAL;
if (type_page) {
if (!strcmp((char *)type_page, SMBFS_NAME)) {
do_smb_super_data_conv((void *)data_page);
} else if (!strcmp((char *)type_page, NCPFS_NAME)) {
do_ncp_super_data_conv((void *)data_page);
}
}
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);
out1:
free_page(type_page);
out:
return retval;
}
......@@ -694,7 +694,7 @@ static int do_add_mount(struct nameidata *nd, char *type, int flags,
return err;
}
static int copy_mount_options (const void __user *data, unsigned long *where)
int copy_mount_options (const void __user *data, unsigned long *where)
{
int i;
unsigned long page;
......
......@@ -2,6 +2,7 @@
#define __LINUX_NET_SCM_H
#include <linux/limits.h>
#include <linux/net.h>
/* Well, we should have at least one descriptor open
* to accept passed FDs 8)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment