*/
#include <linux/config.h>
-#include <asm/ptrace.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/compat.h>
#include <linux/ptrace.h>
#include <linux/aio_abi.h>
+#include <linux/elf.h>
+
+#include <net/scm.h>
+#include <net/sock.h>
+#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
-
#include <asm/semaphore.h>
-
-#include <net/scm.h>
-#include <net/sock.h>
-#include <linux/elf.h>
#include <asm/ppcdebug.h>
#include <asm/time.h>
#include <asm/ppc32.h>
#include "pci.h"
-typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
-typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
-
-static long do_readv_writev32(int type, struct file *file,
- const struct compat_iovec *vector, u32 count)
-{
- compat_ssize_t tot_len;
- struct iovec iovstack[UIO_FASTIOV];
- struct iovec *iov=iovstack, *ivp;
- struct inode *inode;
- long retval, i;
- io_fn_t fn;
- iov_fn_t fnv;
-
- /*
- * SuS says "The readv() function *may* fail if the iovcnt argument
- * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
- * traditionally returned zero for zero segments, so...
- */
- retval = 0;
- if (count == 0)
- goto out;
-
- /* First get the "struct iovec" from user memory and
- * verify all the pointers
- */
- retval = -EINVAL;
- if (count > UIO_MAXIOV)
- goto out;
- if (!file->f_op)
- goto out;
- if (count > UIO_FASTIOV) {
- retval = -ENOMEM;
- iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
- if (!iov)
- goto out;
- }
- retval = -EFAULT;
- if (verify_area(VERIFY_READ, vector, sizeof(struct compat_iovec)*count))
- goto out;
-
- /*
- * Single unix specification:
- * We should -EINVAL if an element length is not >= 0 and fitting an
- * ssize_t. The total length is fitting an ssize_t
- *
- * Be careful here because iov_len is a size_t not an ssize_t
- */
- tot_len = 0;
- i = count;
- ivp = iov;
- retval = -EINVAL;
- while(i > 0) {
- compat_ssize_t tmp = tot_len;
- compat_ssize_t len;
- u32 buf;
-
- if (__get_user(len, &vector->iov_len) ||
- __get_user(buf, &vector->iov_base)) {
- retval = -EFAULT;
- goto out;
- }
- if (len < 0) /* size_t not fitting an compat_ssize_t .. */
- goto out;
- tot_len += len;
- if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
- goto out;
- ivp->iov_base = (void *)A(buf);
- ivp->iov_len = (__kernel_size_t) len;
- vector++;
- ivp++;
- i--;
- }
- if (tot_len == 0) {
- retval = 0;
- goto out;
- }
-
- inode = file->f_dentry->d_inode;
- /* VERIFY_WRITE actually means a read, as we write to user space */
- retval = locks_verify_area((type == READ
- ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
- inode, file, file->f_pos, tot_len);
- if (retval)
- goto out;
-
- if (type == READ) {
- fn = file->f_op->read;
- fnv = file->f_op->readv;
- } else {
- fn = (io_fn_t)file->f_op->write;
- fnv = file->f_op->writev;
- }
- if (fnv) {
- retval = fnv(file, iov, count, &file->f_pos);
- goto out;
- }
-
- /* Do it by hand, with file-ops */
- ivp = iov;
- while (count > 0) {
- void * base;
- int len, nr;
-
- base = ivp->iov_base;
- len = ivp->iov_len;
- ivp++;
- count--;
-
- nr = fn(file, base, len, &file->f_pos);
-
- if (nr < 0) {
- if (!retval)
- retval = nr;
- break;
- }
- retval += nr;
- if (nr != len)
- break;
- }
-out:
- if (iov != iovstack)
- kfree(iov);
- if ((retval + (type == READ)) > 0)
- dnotify_parent(file->f_dentry,
- (type == READ) ? DN_ACCESS : DN_MODIFY);
-
- return retval;
-}
-
-asmlinkage long sys32_readv(int fd, struct compat_iovec *vector, u32 count)
-{
- struct file *file;
- int ret = -EBADF;
-
- file = fget(fd);
- if (!file || !(file->f_mode & FMODE_READ))
- goto out;
-
- ret = -EINVAL;
- if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
- goto out;
-
- ret = do_readv_writev32(READ, file, vector, count);
-
-out:
- if (file)
- fput(file);
- return ret;
-}
-
-asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, u32 count)
-{
- struct file *file;
- int ret = -EBADF;
-
- file = fget(fd);
- if (!file || !(file->f_mode & FMODE_WRITE))
- goto out;
-
- ret = -EINVAL;
- if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
- goto out;
-
- ret = do_readv_writev32(WRITE, file, vector, count);
-
-out:
- if (file)
- fput(file);
- return ret;
-}
-
/* readdir & getdents */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
struct old_linux_dirent32 {
};
struct readdir_callback32 {
- struct old_linux_dirent32 * dirent;
+ struct old_linux_dirent32 __user * dirent;
int count;
};
off_t offset, ino_t ino, unsigned int d_type)
{
struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
- struct old_linux_dirent32 * dirent;
+ struct old_linux_dirent32 __user * dirent;
if (buf->count)
return -EINVAL;
return 0;
}
-asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
+asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 __user *dirent, unsigned int count)
{
int error = -EBADF;
struct file * file;
};
struct getdents_callback32 {
- struct linux_dirent32 * current_dir;
- struct linux_dirent32 * previous;
+ struct linux_dirent32 __user * current_dir;
+ struct linux_dirent32 __user * previous;
int count;
int error;
};
static int filldir(void * __buf, const char * name, int namlen, off_t offset,
ino_t ino, unsigned int d_type)
{
- struct linux_dirent32 * dirent;
+ struct linux_dirent32 __user * dirent;
struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
goto efault;
if (__put_user(0, dirent->d_name + namlen))
goto efault;
- if (__put_user(d_type, (char *) dirent + reclen - 1))
+ if (__put_user(d_type, (char __user *) dirent + reclen - 1))
goto efault;
buf->previous = dirent;
- dirent = (void *)dirent + reclen;
+ dirent = (void __user *)dirent + reclen;
buf->current_dir = dirent;
buf->count -= reclen;
return 0;
return -EFAULT;
}
-long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent,
+asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 __user *dirent,
unsigned int count)
{
struct file * file;
- struct linux_dirent32 * lastdirent;
+ struct linux_dirent32 __user * lastdirent;
struct getdents_callback32 buf;
int error;
return error;
}
-/*
- * Ooo, nasty. We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
-{
- if (ufdset) {
- unsigned long odd;
-
- if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
- return -EFAULT;
-
- odd = n & 1UL;
- n &= ~1UL;
- while (n) {
- unsigned long h, l;
- __get_user(l, ufdset);
- __get_user(h, ufdset+1);
- ufdset += 2;
- *fdset++ = h << 32 | l;
- n -= 2;
- }
- if (odd)
- __get_user(*fdset, ufdset);
- } else {
- /* Tricky, must clear full unsigned long in the
- * kernel fdset at the end, this makes sure that
- * actually happens.
- */
- memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
- }
- return 0;
-}
-
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
- unsigned long odd;
-
- if (!ufdset)
- return;
-
- odd = n & 1UL;
- n &= ~1UL;
- while (n) {
- unsigned long h, l;
- l = *fdset++;
- h = l >> 32;
- __put_user(l, ufdset);
- __put_user(h, ufdset+1);
- ufdset += 2;
- n -= 2;
- }
- if (odd)
- __put_user(*fdset, ufdset);
-}
-
-
-
-#define MAX_SELECT_SECONDS ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
-asmlinkage long sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
-{
- fd_set_bits fds;
- struct compat_timeval *tvp = (struct compat_timeval *)AA(tvp_x);
- char *bits;
- unsigned long nn;
- long timeout;
- int ret, size, max_fdset;
-
- timeout = MAX_SCHEDULE_TIMEOUT;
- if (tvp) {
- time_t sec, usec;
- if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
- || (ret = __get_user(sec, &tvp->tv_sec))
- || (ret = __get_user(usec, &tvp->tv_usec)))
- goto out_nofds;
-
- ret = -EINVAL;
- if(sec < 0 || usec < 0)
- goto out_nofds;
-
- if ((unsigned long) sec < MAX_SELECT_SECONDS) {
- timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
- timeout += sec * (unsigned long) HZ;
- }
- }
-
- ret = -EINVAL;
- if (n < 0)
- goto out_nofds;
-
- /* max_fdset can increase, so grab it once to avoid race */
- max_fdset = current->files->max_fdset;
- if (n > max_fdset)
- n = max_fdset;
-
- /*
- * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
- * since we used fdset we need to allocate memory in units of
- * long-words.
- */
- ret = -ENOMEM;
- size = FDS_BYTES(n);
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
- fds.in = (unsigned long *) bits;
- fds.out = (unsigned long *) (bits + size);
- fds.ex = (unsigned long *) (bits + 2*size);
- fds.res_in = (unsigned long *) (bits + 3*size);
- fds.res_out = (unsigned long *) (bits + 4*size);
- fds.res_ex = (unsigned long *) (bits + 5*size);
-
- nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
- if ((ret = get_fd_set32(nn, fds.in, inp)) ||
- (ret = get_fd_set32(nn, fds.out, outp)) ||
- (ret = get_fd_set32(nn, fds.ex, exp)))
- goto out;
- zero_fd_set(n, fds.res_in);
- zero_fd_set(n, fds.res_out);
- zero_fd_set(n, fds.res_ex);
-
- ret = do_select(n, &fds, &timeout);
-
- if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
- time_t sec = 0, usec = 0;
- if (timeout) {
- sec = timeout / HZ;
- usec = timeout % HZ;
- usec *= (1000000/HZ);
- }
- put_user(sec, &tvp->tv_sec);
- put_user(usec, &tvp->tv_usec);
- }
-
- if (ret < 0)
- goto out;
- if (!ret) {
- ret = -ERESTARTNOHAND;
- if (signal_pending(current))
- goto out;
- ret = 0;
- }
-
- set_fd_set32(nn, inp, fds.res_in);
- set_fd_set32(nn, outp, fds.res_out);
- set_fd_set32(nn, exp, fds.res_ex);
-
-out:
- kfree(bits);
-
-out_nofds:
- return ret;
-}
-
-int ppc32_select(u32 n, u32* inp, u32* outp, u32* exp, u32 tvp_x)
+asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
+ compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+ compat_uptr_t tvp_x)
{
/* sign extend n */
- return sys32_select((int)n, inp, outp, exp, tvp_x);
+ return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
}
-int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
+int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
long err;
extern int do_adjtimex(struct timex *);
extern void ppc_adjtimex(void);
-asmlinkage long sys32_adjtimex(struct timex32 *utp)
+asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
{
struct timex txc;
int ret;
return ret;
}
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
- u16 svc32_port;
- s32 svc32_nthreads;
-};
-
-struct nfsctl_client32 {
- s8 cl32_ident[NFSCLNT_IDMAX+1];
- s32 cl32_naddr;
- struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX];
- s32 cl32_fhkeytype;
- s32 cl32_fhkeylen;
- u8 cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
- s8 ex32_client[NFSCLNT_IDMAX+1];
- s8 ex32_path[NFS_MAXPATHLEN+1];
- compat_dev_t ex32_dev;
- compat_ino_t ex32_ino;
- s32 ex32_flags;
- compat_uid_t ex32_anon_uid;
- compat_gid_t ex32_anon_gid;
-};
-
-struct nfsctl_fdparm32 {
- struct sockaddr gd32_addr;
- s8 gd32_path[NFS_MAXPATHLEN+1];
- s32 gd32_version;
-};
-
-struct nfsctl_fsparm32 {
- struct sockaddr gd32_addr;
- s8 gd32_path[NFS_MAXPATHLEN+1];
- s32 gd32_maxlen;
-};
-
-struct nfsctl_arg32 {
- s32 ca32_version; /* safeguard */
- union {
- struct nfsctl_svc32 u32_svc;
- struct nfsctl_client32 u32_client;
- struct nfsctl_export32 u32_export;
- struct nfsctl_fdparm32 u32_getfd;
- struct nfsctl_fsparm32 u32_getfs;
- } u;
-#define ca32_svc u.u32_svc
-#define ca32_client u.u32_client
-#define ca32_export u.u32_export
-#define ca32_getfd u.u32_getfd
-#define ca32_getfs u.u32_getfs
-};
-
-union nfsctl_res32 {
- __u8 cr32_getfh[NFS_FHSIZE];
- struct knfsd_fh cr32_getfs;
-};
-
-static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
- int err;
-
- err = __get_user(karg->ca_version, &arg32->ca32_version);
- err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
- err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
- return err;
-}
-
-static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
- int err;
-
- err = __get_user(karg->ca_version, &arg32->ca32_version);
- err |= copy_from_user(&karg->ca_client.cl_ident[0],
- &arg32->ca32_client.cl32_ident[0],
- NFSCLNT_IDMAX);
- err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
- err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
- &arg32->ca32_client.cl32_addrlist[0],
- (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
- err |= __get_user(karg->ca_client.cl_fhkeytype,
- &arg32->ca32_client.cl32_fhkeytype);
- err |= __get_user(karg->ca_client.cl_fhkeylen,
- &arg32->ca32_client.cl32_fhkeylen);
- err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
- &arg32->ca32_client.cl32_fhkey[0],
- NFSCLNT_KEYMAX);
-
- if(err) return -EFAULT;
- return 0;
-}
-
-static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
- int err;
-
- err = __get_user(karg->ca_version, &arg32->ca32_version);
- err |= copy_from_user(&karg->ca_export.ex_client[0],
- &arg32->ca32_export.ex32_client[0],
- NFSCLNT_IDMAX);
- err |= copy_from_user(&karg->ca_export.ex_path[0],
- &arg32->ca32_export.ex32_path[0],
- NFS_MAXPATHLEN);
- err |= __get_user(karg->ca_export.ex_dev,
- &arg32->ca32_export.ex32_dev);
- err |= __get_user(karg->ca_export.ex_ino,
- &arg32->ca32_export.ex32_ino);
- err |= __get_user(karg->ca_export.ex_flags,
- &arg32->ca32_export.ex32_flags);
- err |= __get_user(karg->ca_export.ex_anon_uid,
- &arg32->ca32_export.ex32_anon_uid);
- err |= __get_user(karg->ca_export.ex_anon_gid,
- &arg32->ca32_export.ex32_anon_gid);
- karg->ca_export.ex_anon_uid = karg->ca_export.ex_anon_uid;
- karg->ca_export.ex_anon_gid = karg->ca_export.ex_anon_gid;
-
- if(err) return -EFAULT;
- return 0;
-}
-
-static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
- int err;
-
- err = __get_user(karg->ca_version, &arg32->ca32_version);
- err |= copy_from_user(&karg->ca_getfd.gd_addr,
- &arg32->ca32_getfd.gd32_addr,
- (sizeof(struct sockaddr)));
- err |= copy_from_user(&karg->ca_getfd.gd_path,
- &arg32->ca32_getfd.gd32_path,
- (NFS_MAXPATHLEN+1));
- err |= __get_user(karg->ca_getfd.gd_version,
- &arg32->ca32_getfd.gd32_version);
-
- if(err) return -EFAULT;
- return 0;
-}
-
-static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
- int err;
-
- err = __get_user(karg->ca_version, &arg32->ca32_version);
- err |= copy_from_user(&karg->ca_getfs.gd_addr,
- &arg32->ca32_getfs.gd32_addr,
- (sizeof(struct sockaddr)));
- err |= copy_from_user(&karg->ca_getfs.gd_path,
- &arg32->ca32_getfs.gd32_path,
- (NFS_MAXPATHLEN+1));
- err |= __get_user(karg->ca_getfs.gd_maxlen,
- &arg32->ca32_getfs.gd32_maxlen);
-
- if(err) return -EFAULT;
- return 0;
-}
-
-/* This really doesn't need translations, we are only passing
- * back a union which contains opaque nfs file handle data.
- */
-static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
- int err;
-
- err = copy_to_user(res32, kres, sizeof(*res32));
-
- if(err) return -EFAULT;
- return 0;
-}
-
-/* Note: it is necessary to treat cmd_parm as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-int asmlinkage sys32_nfsservctl(u32 cmd_parm, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
- int cmd = (int)cmd_parm;
- struct nfsctl_arg *karg = NULL;
- union nfsctl_res *kres = NULL;
- mm_segment_t oldfs;
- int err;
-
- karg = kmalloc(sizeof(*karg), GFP_USER);
- if(!karg)
- return -ENOMEM;
- if(res32) {
- kres = kmalloc(sizeof(*kres), GFP_USER);
- if(!kres) {
- kfree(karg);
- return -ENOMEM;
- }
- }
- switch(cmd) {
- case NFSCTL_SVC:
- err = nfs_svc32_trans(karg, arg32);
- break;
- case NFSCTL_ADDCLIENT:
- err = nfs_clnt32_trans(karg, arg32);
- break;
- case NFSCTL_DELCLIENT:
- err = nfs_clnt32_trans(karg, arg32);
- break;
- case NFSCTL_EXPORT:
- case NFSCTL_UNEXPORT:
- err = nfs_exp32_trans(karg, arg32);
- break;
- case NFSCTL_GETFD:
- err = nfs_getfd32_trans(karg, arg32);
- break;
- case NFSCTL_GETFS:
- err = nfs_getfs32_trans(karg, arg32);
- break;
- default:
- err = -EINVAL;
- break;
- }
- if(err)
- goto done;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_nfsservctl(cmd, karg, kres);
- set_fs(oldfs);
-
- if (err)
- goto done;
-
- if((cmd == NFSCTL_GETFD) ||
- (cmd == NFSCTL_GETFS))
- err = nfs_getfh32_res_trans(kres, res32);
-
-done:
- if(karg)
- kfree(karg);
- if(kres)
- kfree(kres);
- return err;
-}
-
-
/* These are here just in case some old sparc32 binary calls it. */
asmlinkage long sys32_pause(void)
-static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
+static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
{
long usec;
return 0;
}
-static inline long put_tv32(struct compat_timeval *o, struct timeval *i)
+static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
{
return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
(__put_user(i->tv_sec, &o->tv_sec) |
char _f[20-2*sizeof(int)-sizeof(int)];
};
-asmlinkage long sys32_sysinfo(struct sysinfo32 *info)
+asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
{
struct sysinfo s;
int ret, err;
int bitcount=0;
mm_segment_t old_fs = get_fs ();
+ /* The __user cast is valid due to set_fs() */
set_fs (KERNEL_DS);
- ret = sys_sysinfo(&s);
+ ret = sys_sysinfo((struct sysinfo __user *)&s);
set_fs (old_fs);
+
/* Check to see if any memory value is too large for 32-bit and
* scale down if needed.
*/
sorts of things, like timeval and itimerval. */
extern struct timezone sys_tz;
-asmlinkage long sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
{
if (tv) {
struct timeval ktv;
-asmlinkage long sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
{
struct timespec kts;
struct timezone ktz;
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}
-
-struct msgbuf32 {
- compat_long_t mtype;
- char mtext[1];
-};
-
-struct semid_ds32 {
- struct ipc_perm sem_perm;
- compat_time_t sem_otime;
- compat_time_t sem_ctime;
- compat_uptr_t sem_base;
- compat_uptr_t sem_pending;
- compat_uptr_t sem_pending_last;
- compat_uptr_t undo;
- unsigned short sem_nsems;
-};
-
-struct semid64_ds32 {
- struct ipc64_perm sem_perm;
- unsigned int __unused1;
- compat_time_t sem_otime;
- unsigned int __unused2;
- compat_time_t sem_ctime;
- compat_ulong_t sem_nsems;
- compat_ulong_t __unused3;
- compat_ulong_t __unused4;
-};
-
-struct msqid_ds32 {
- struct ipc_perm msg_perm;
- compat_uptr_t msg_first;
- compat_uptr_t msg_last;
- compat_time_t msg_stime;
- compat_time_t msg_rtime;
- compat_time_t msg_ctime;
- compat_ulong_t msg_lcbytes;
- compat_ulong_t msg_lqbytes;
- unsigned short msg_cbytes;
- unsigned short msg_qnum;
- unsigned short msg_qbytes;
- compat_ipc_pid_t msg_lspid;
- compat_ipc_pid_t msg_lrpid;
-};
-
-struct msqid64_ds32 {
- struct ipc64_perm msg_perm;
- unsigned int __unused1;
- compat_time_t msg_stime;
- unsigned int __unused2;
- compat_time_t msg_rtime;
- unsigned int __unused3;
- compat_time_t msg_ctime;
- compat_ulong_t msg_cbytes;
- compat_ulong_t msg_qnum;
- compat_ulong_t msg_qbytes;
- compat_pid_t msg_lspid;
- compat_pid_t msg_lrpid;
- compat_ulong_t __unused4;
- compat_ulong_t __unused5;
-};
-
-struct shmid_ds32 {
- struct ipc_perm shm_perm;
- int shm_segsz;
- compat_time_t shm_atime;
- compat_time_t shm_dtime;
- compat_time_t shm_ctime;
- compat_ipc_pid_t shm_cpid;
- compat_ipc_pid_t shm_lpid;
- unsigned short shm_nattch;
- unsigned short __unused;
- compat_uptr_t __unused2;
- compat_uptr_t __unused3;
-};
-
-struct shmid64_ds32 {
- struct ipc64_perm shm_perm;
- unsigned int __unused1;
- compat_time_t shm_atime;
- unsigned int __unused2;
- compat_time_t shm_dtime;
- unsigned int __unused3;
- compat_time_t shm_ctime;
- unsigned int __unused4;
- compat_size_t shm_segsz;
- compat_pid_t shm_cpid;
- compat_pid_t shm_lpid;
- compat_ulong_t shm_nattch;
- compat_ulong_t __unused5;
- compat_ulong_t __unused6;
-};
-
-/*
- * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit
- * emulation..
- *
- * This is really horribly ugly.
- */
-static long do_sys32_semctl(int first, int second, int third, void *uptr)
-{
- union semun fourth;
- u32 pad;
- int err, err2;
- mm_segment_t old_fs;
-
- if (!uptr)
- return -EINVAL;
- err = -EFAULT;
- if (get_user(pad, (u32 *)uptr))
- return err;
- if ((third & ~IPC_64) == SETVAL)
- fourth.val = (int)pad;
- else
- fourth.__pad = (void *)A(pad);
- switch (third & (~IPC_64)) {
-
- case IPC_INFO:
- case IPC_RMID:
- case SEM_INFO:
- case GETVAL:
- case GETPID:
- case GETNCNT:
- case GETZCNT:
- case GETALL:
- case SETALL:
- case SETVAL:
- err = sys_semctl(first, second, third, fourth);
- break;
-
- case IPC_STAT:
- case SEM_STAT:
- if (third & IPC_64) {
- struct semid64_ds s64;
- struct semid64_ds32 *usp;
-
- usp = (struct semid64_ds32 *)A(pad);
- fourth.__pad = &s64;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_semctl(first, second, third, fourth);
- set_fs(old_fs);
- err2 = copy_to_user(&usp->sem_perm, &s64.sem_perm,
- sizeof(struct ipc64_perm));
- err2 |= __put_user(s64.sem_otime, &usp->sem_otime);
- err2 |= __put_user(s64.sem_ctime, &usp->sem_ctime);
- err2 |= __put_user(s64.sem_nsems, &usp->sem_nsems);
- if (err2)
- err = -EFAULT;
- } else {
- struct semid_ds s;
- struct semid_ds32 *usp;
-
- usp = (struct semid_ds32 *)A(pad);
- fourth.__pad = &s;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_semctl(first, second, third, fourth);
- set_fs(old_fs);
- err2 = copy_to_user(&usp->sem_perm, &s.sem_perm,
- sizeof(struct ipc_perm));
- err2 |= __put_user(s.sem_otime, &usp->sem_otime);
- err2 |= __put_user(s.sem_ctime, &usp->sem_ctime);
- err2 |= __put_user(s.sem_nsems, &usp->sem_nsems);
- if (err2)
- err = -EFAULT;
- }
- break;
-
- case IPC_SET:
- if (third & IPC_64) {
- struct semid64_ds s64;
- struct semid64_ds32 *usp;
-
- usp = (struct semid64_ds32 *)A(pad);
-
- err = get_user(s64.sem_perm.uid, &usp->sem_perm.uid);
- err |= __get_user(s64.sem_perm.gid,
- &usp->sem_perm.gid);
- err |= __get_user(s64.sem_perm.mode,
- &usp->sem_perm.mode);
- if (err)
- goto out;
- fourth.__pad = &s64;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_semctl(first, second, third, fourth);
- set_fs(old_fs);
-
- } else {
- struct semid_ds s;
- struct semid_ds32 *usp;
-
- usp = (struct semid_ds32 *)A(pad);
-
- err = get_user(s.sem_perm.uid, &usp->sem_perm.uid);
- err |= __get_user(s.sem_perm.gid,
- &usp->sem_perm.gid);
- err |= __get_user(s.sem_perm.mode,
- &usp->sem_perm.mode);
- if (err)
- goto out;
- fourth.__pad = &s;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_semctl(first, second, third, fourth);
- set_fs(old_fs);
- }
- break;
- default:
- err = -EINVAL;
- }
-out:
- return err;
-}
-
-#define MAXBUF (64*1024)
-
-static int
-do_sys32_msgsnd(int first, int second, int third, void *uptr)
-{
- struct msgbuf *p;
- struct msgbuf32 *up = (struct msgbuf32 *)uptr;
- mm_segment_t old_fs;
- int err;
-
- if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
- return -EINVAL;
-
- p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
- if (!p)
- return -ENOMEM;
- err = get_user(p->mtype, &up->mtype);
- err |= copy_from_user(p->mtext, &up->mtext, second);
- if (err) {
- err = -EFAULT;
- goto out;
- }
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_msgsnd(first, p, second, third);
- set_fs(old_fs);
-out:
- kfree(p);
- return err;
-}
-
-static int
-do_sys32_msgrcv(int first, int second, int msgtyp, int third,
- int version, void *uptr)
-{
- struct msgbuf32 *up;
- struct msgbuf *p;
- mm_segment_t old_fs;
- int err;
-
- if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
- return -EINVAL;
-
- if (!version) {
- struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
- struct ipc_kludge_32 ipck;
-
- err = -EINVAL;
- if (!uptr)
- goto out;
- err = -EFAULT;
- if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge_32)))
- goto out;
- uptr = (void *)A(ipck.msgp);
- msgtyp = ipck.msgtyp;
- }
- err = -ENOMEM;
- p = kmalloc(second + sizeof (struct msgbuf), GFP_USER);
- if (!p)
- goto out;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_msgrcv(first, p, second, msgtyp, third);
- set_fs(old_fs);
- if (err < 0)
- goto free_then_out;
- up = (struct msgbuf32 *)uptr;
- if (put_user(p->mtype, &up->mtype) ||
- copy_to_user(&up->mtext, p->mtext, err))
- err = -EFAULT;
-free_then_out:
- kfree(p);
-out:
- return err;
-}
-
-static int
-do_sys32_msgctl(int first, int second, void *uptr)
-{
- int err = -EINVAL, err2;
- mm_segment_t old_fs;
-
- switch (second & (~IPC_64)) {
-
- case IPC_INFO:
- case IPC_RMID:
- case MSG_INFO:
- err = sys_msgctl(first, second, (struct msqid_ds *)uptr);
- break;
-
- case IPC_SET:
- if (second & IPC_64) {
- struct msqid64_ds m64;
- struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
-
- err2 = copy_from_user(&m64.msg_perm, &up->msg_perm,
- sizeof(struct ipc64_perm));
- err2 |= __get_user(m64.msg_qbytes, &up->msg_qbytes);
- if (err2) {
- err = -EFAULT;
- break;
- }
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_msgctl(first, second,
- (struct msqid_ds *)&m64);
- set_fs(old_fs);
- } else {
- struct msqid_ds m;
- struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
-
- err2 = copy_from_user(&m.msg_perm, &up->msg_perm,
- sizeof(struct ipc_perm));
- err2 |= __get_user(m.msg_qbytes, &up->msg_qbytes);
- if (err2) {
- err = -EFAULT;
- break;
- }
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_msgctl(first, second, &m);
- set_fs(old_fs);
- }
- break;
-
- case IPC_STAT:
- case MSG_STAT:
- if (second & IPC_64) {
- struct msqid64_ds m64;
- struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_msgctl(first, second,
- (struct msqid_ds *)&m64);
- set_fs(old_fs);
-
- err2 = copy_to_user(&up->msg_perm, &m64.msg_perm,
- sizeof(struct ipc64_perm));
- err2 |= __put_user(m64.msg_stime, &up->msg_stime);
- err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
- err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
- err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes);
- err2 |= __put_user(m64.msg_qnum, &up->msg_qnum);
- err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes);
- err2 |= __put_user(m64.msg_lspid, &up->msg_lspid);
- err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid);
- if (err2)
- err = -EFAULT;
- } else {
- struct msqid64_ds m;
- struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_msgctl(first, second, (struct msqid_ds *)&m);
- set_fs(old_fs);
-
- err2 = copy_to_user(&up->msg_perm, &m.msg_perm,
- sizeof(struct ipc_perm));
- err2 |= __put_user(m.msg_stime, &up->msg_stime);
- err2 |= __put_user(m.msg_rtime, &up->msg_rtime);
- err2 |= __put_user(m.msg_ctime, &up->msg_ctime);
- err2 |= __put_user(m.msg_cbytes, &up->msg_cbytes);
- err2 |= __put_user(m.msg_qnum, &up->msg_qnum);
- err2 |= __put_user(m.msg_qbytes, &up->msg_qbytes);
- err2 |= __put_user(m.msg_lspid, &up->msg_lspid);
- err2 |= __put_user(m.msg_lrpid, &up->msg_lrpid);
- if (err2)
- err = -EFAULT;
- }
- break;
- }
- return err;
-}
-
-static int
-do_sys32_shmat(int first, int second, int third, int version, void *uptr)
+long sys32_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
+ u32 fifth)
{
- unsigned long raddr;
- u32 *uaddr = (u32 *)A((u32)third);
- int err = -EINVAL;
+ int version;
- if (version == 1)
- return err;
- err = do_shmat(first, uptr, second, &raddr);
- if (err)
- return err;
- err = put_user(raddr, uaddr);
- return err;
-}
-
-static int
-do_sys32_shmctl(int first, int second, void *uptr)
-{
- int err = -EINVAL, err2;
- mm_segment_t old_fs;
-
- switch (second & (~IPC_64)) {
-
- case IPC_INFO:
- case IPC_RMID:
- case SHM_LOCK:
- case SHM_UNLOCK:
- err = sys_shmctl(first, second, (struct shmid_ds *)uptr);
- break;
- case IPC_SET:
- if (second & IPC_64) {
- struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr;
- struct shmid64_ds s64;
-
- err = get_user(s64.shm_perm.uid, &up->shm_perm.uid);
- err |= __get_user(s64.shm_perm.gid, &up->shm_perm.gid);
- err |= __get_user(s64.shm_perm.mode,
- &up->shm_perm.mode);
- if (err)
- break;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_shmctl(first, second,
- (struct shmid_ds *)&s64);
- set_fs(old_fs);
- } else {
- struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
- struct shmid_ds s;
-
- err = get_user(s.shm_perm.uid, &up->shm_perm.uid);
- err |= __get_user(s.shm_perm.gid, &up->shm_perm.gid);
- err |= __get_user(s.shm_perm.mode, &up->shm_perm.mode);
- if (err)
- break;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_shmctl(first, second, &s);
- set_fs(old_fs);
- }
- break;
-
- case IPC_STAT:
- case SHM_STAT:
- if (second & IPC_64) {
- struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr;
- struct shmid64_ds s64;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_shmctl(first, second,
- (struct shmid_ds *)&s64);
- set_fs(old_fs);
- if (err < 0)
- break;
-
- err2 = copy_to_user(&up->shm_perm, &s64.shm_perm,
- sizeof(struct ipc64_perm));
- err2 |= __put_user(s64.shm_atime, &up->shm_atime);
- err2 |= __put_user(s64.shm_dtime, &up->shm_dtime);
- err2 |= __put_user(s64.shm_ctime, &up->shm_ctime);
- err2 |= __put_user(s64.shm_segsz, &up->shm_segsz);
- err2 |= __put_user(s64.shm_nattch, &up->shm_nattch);
- err2 |= __put_user(s64.shm_cpid, &up->shm_cpid);
- err2 |= __put_user(s64.shm_lpid, &up->shm_lpid);
- if (err2)
- err = -EFAULT;
- } else {
- struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
- struct shmid_ds s;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_shmctl(first, second, &s);
- set_fs(old_fs);
- if (err < 0)
- break;
-
- err2 = copy_to_user(&up->shm_perm, &s.shm_perm,
- sizeof(struct ipc_perm));
- err2 |= __put_user (s.shm_atime, &up->shm_atime);
- err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
- err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
- err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
- err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
- err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
- err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
- if (err2)
- err = -EFAULT;
- }
- break;
-
- case SHM_INFO: {
- struct shm_info si;
- struct shm_info32 {
- int used_ids;
- u32 shm_tot, shm_rss, shm_swp;
- u32 swap_attempts, swap_successes;
- } *uip = (struct shm_info32 *)uptr;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_shmctl(first, second, (struct shmid_ds *)&si);
- set_fs(old_fs);
- if (err < 0)
- break;
- err2 = put_user(si.used_ids, &uip->used_ids);
- err2 |= __put_user(si.shm_tot, &uip->shm_tot);
- err2 |= __put_user(si.shm_rss, &uip->shm_rss);
- err2 |= __put_user(si.shm_swp, &uip->shm_swp);
- err2 |= __put_user(si.swap_attempts, &uip->swap_attempts);
- err2 |= __put_user(si.swap_successes, &uip->swap_successes);
- if (err2)
- err = -EFAULT;
- break;
- }
- }
- return err;
-}
-
-static int sys32_semtimedop(int semid, struct sembuf *tsems, int nsems,
- const struct compat_timespec *timeout32)
-{
- struct compat_timespec t32;
- struct timespec *t64 = compat_alloc_user_space(sizeof(*t64));
-
- if (copy_from_user(&t32, timeout32, sizeof(t32)))
- return -EFAULT;
-
- if (put_user(t32.tv_sec, &t64->tv_sec) ||
- put_user(t32.tv_nsec, &t64->tv_nsec))
- return -EFAULT;
-
- return sys_semtimedop(semid, tsems, nsems, t64);
-}
-
-/*
- * Note: it is necessary to treat first_parm, second_parm, and
- * third_parm as unsigned ints, with the corresponding cast to a
- * signed int to insure that the proper conversion (sign extension)
- * between the register representation of a signed int (msr in 32-bit
- * mode) and the register representation of a signed int (msr in
- * 64-bit mode) is performed.
- */
-asmlinkage long sys32_ipc(u32 call, u32 first_parm, u32 second_parm, u32 third_parm, u32 ptr, u32 fifth)
-{
- int first = (int)first_parm;
- int second = (int)second_parm;
- int third = (int)third_parm;
- int version, err;
-
version = call >> 16; /* hack for backward compatibility */
call &= 0xffff;
switch (call) {
+ case SEMTIMEDOP:
+ if (third)
+ /* sign extend semid */
+ return compat_sys_semtimedop((int)first,
+ compat_ptr(ptr), second,
+ compat_ptr(third));
+ /* else fall through for normal semop() */
case SEMOP:
/* struct sembuf is the same on 32 and 64bit :)) */
- err = sys_semtimedop(first, (struct sembuf *)AA(ptr),
- second, NULL);
- break;
- case SEMTIMEDOP:
- err = sys32_semtimedop(first, (struct sembuf *)AA(ptr), second,
- (const struct compat_timespec *)AA(fifth));
- break;
+ /* sign extend semid */
+ return sys_semtimedop((int)first, compat_ptr(ptr), second,
+ NULL);
case SEMGET:
- err = sys_semget(first, second, third);
- break;
+ /* sign extend key, nsems */
+ return sys_semget((int)first, (int)second, third);
case SEMCTL:
- err = do_sys32_semctl(first, second, third,
- (void *)AA(ptr));
- break;
+ /* sign extend semid, semnum */
+ return compat_sys_semctl((int)first, (int)second, third,
+ compat_ptr(ptr));
case MSGSND:
- err = do_sys32_msgsnd(first, second, third,
- (void *)AA(ptr));
- break;
+ /* sign extend msqid */
+ return compat_sys_msgsnd((int)first, (int)second, third,
+ compat_ptr(ptr));
case MSGRCV:
- err = do_sys32_msgrcv(first, second, fifth, third,
- version, (void *)AA(ptr));
- break;
+ /* sign extend msqid, msgtyp */
+ return compat_sys_msgrcv((int)first, second, (int)fifth,
+ third, version, compat_ptr(ptr));
case MSGGET:
- err = sys_msgget((key_t)first, second);
- break;
+ /* sign extend key */
+ return sys_msgget((int)first, second);
case MSGCTL:
- err = do_sys32_msgctl(first, second, (void *)AA(ptr));
- break;
+ /* sign extend msqid */
+ return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
case SHMAT:
- err = do_sys32_shmat(first, second, third,
- version, (void *)AA(ptr));
- break;
- case SHMDT:
- err = sys_shmdt((char *)AA(ptr));
- break;
+ /* sign extend shmid */
+ return compat_sys_shmat((int)first, second, third, version,
+ compat_ptr(ptr));
+ case SHMDT:
+ return sys_shmdt(compat_ptr(ptr));
case SHMGET:
- err = sys_shmget(first, second_parm, third);
- break;
+ /* sign extend key_t */
+ return sys_shmget((int)first, second, third);
case SHMCTL:
- err = do_sys32_shmctl(first, second, (void *)AA(ptr));
- break;
+ /* sign extend shmid */
+ return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
+
default:
- err = -ENOSYS;
- break;
+ return -ENOSYS;
}
- return err;
+
+ return -ENOSYS;
}
/* Note: it is necessary to treat out_fd and in_fd as unsigned ints,
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, compat_off_t* offset, u32 count)
+asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count)
{
mm_segment_t old_fs = get_fs();
int ret;
off_t of;
-
+ off_t __user *up;
+
if (offset && get_user(of, offset))
return -EFAULT;
-
+
+ /* The __user pointer cast is valid because of the set_fs() */
set_fs(KERNEL_DS);
- ret = sys_sendfile((int)out_fd, (int)in_fd, offset ? &of : NULL, count);
+ up = offset ? (off_t __user *) &of : NULL;
+ ret = sys_sendfile((int)out_fd, (int)in_fd, up, count);
set_fs(old_fs);
if (offset && put_user(of, offset))
return ret;
}
-asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t *offset, s32 count)
+asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
{
mm_segment_t old_fs = get_fs();
int ret;
loff_t lof;
+ loff_t __user *up;
if (offset && get_user(lof, offset))
return -EFAULT;
+ /* The __user pointer cast is valid because of the set_fs() */
set_fs(KERNEL_DS);
- ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count);
+ up = offset ? (loff_t __user *) &lof : NULL;
+ ret = sys_sendfile64(out_fd, in_fd, up, count);
set_fs(old_fs);
if (offset && put_user(lof, offset))
return ret;
}
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- u32 p; int error;
-
- error = get_user(p,argv);
- if (error)
- return error;
- if (!p)
- break;
- argv++;
- if (++i > max)
- return -E2BIG;
- }
- }
- return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
- while (argc-- > 0) {
- u32 str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv + argc) ||
- !str ||
- !(len = strnlen_user((char *)A(str), bprm->p)))
- return -EFAULT;
-
- if (bprm->p < len)
- return -E2BIG;
-
- bprm->p -= len;
-
- pos = bprm->p;
- while (len) {
- char *kaddr;
- struct page *page;
- int offset, bytes_to_copy, new, err;
-
- offset = pos % PAGE_SIZE;
- page = bprm->page[pos / PAGE_SIZE];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_USER);
- bprm->page[pos / PAGE_SIZE] = page;
- if (!page)
- return -ENOMEM;
- new = 1;
- }
- kaddr = (char *)kmap(page);
-
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
-
- err = copy_from_user(kaddr + offset, (char *)A(str),
- bytes_to_copy);
- kunmap((unsigned long)kaddr);
-
- if (err)
- return -EFAULT;
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file * file;
- int retval;
- int i;
-
- sched_balance_exec();
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.interp = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
- bprm.security = NULL;
- bprm.mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm.mm)
- goto out_file;
-
- retval = init_new_context(current, bprm.mm);
- if (retval < 0)
- goto out_mm;
-
- bprm.argc = count32(argv, bprm.p / sizeof(u32));
- if ((retval = bprm.argc) < 0)
- goto out_mm;
-
- bprm.envc = count32(envp, bprm.p / sizeof(u32));
- if ((retval = bprm.envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(&bprm);
- if (retval)
- goto out;
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings32(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings32(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm,regs);
- if (retval >= 0) {
- /* execve success */
- security_bprm_free(&bprm);
- return retval;
- }
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page * page = bprm.page[i];
- if (page)
- __free_page(page);
- }
-
- if (bprm.security)
- security_bprm_free(&bprm);
-
-out_mm:
- if (bprm.mm)
- mmdrop(bprm.mm);
-
-out_file:
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- }
- return retval;
-}
-
long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs *regs)
int error;
char * filename;
- filename = getname((char *) a0);
+ filename = getname((char __user *) a0);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
giveup_altivec(current);
#endif /* CONFIG_ALTIVEC */
- error = do_execve32(filename, (u32*) a1, (u32*) a2, regs);
+ error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs);
if (error == 0)
current->ptrace &= ~PT_DTRACE;
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_sched_rr_get_interval(u32 pid, struct compat_timespec *interval)
+asmlinkage long sys32_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval)
{
struct timespec t;
int ret;
mm_segment_t old_fs = get_fs ();
-
+
+ /* The __user pointer cast is valid because of the set_fs() */
set_fs (KERNEL_DS);
- ret = sys_sched_rr_get_interval((int)pid, &t);
+ ret = sys_sched_rr_get_interval((int)pid, (struct timespec __user *) &t);
set_fs (old_fs);
if (put_compat_timespec(&t, interval))
return -EFAULT;
(unsigned long) dfn,
(unsigned long) off,
(unsigned long) len,
- (unsigned char *)AA(ubuf));
+ (unsigned char __user *)AA(ubuf));
}
asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
(unsigned long) dfn,
(unsigned long) off,
(unsigned long) len,
- (unsigned char *)AA(ubuf));
+ (unsigned char __user *)AA(ubuf));
}
#define IOBASE_BRIDGE_NUMBER 0
}
-asmlinkage int ppc64_newuname(struct new_utsname * name)
+asmlinkage int ppc64_newuname(struct new_utsname __user * name)
{
int errno = sys_newuname(name);
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_access(const char * filename, u32 mode)
+asmlinkage long sys32_access(const char __user * filename, u32 mode)
{
return sys_access(filename, (int)mode);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_creat(const char * pathname, u32 mode)
+asmlinkage long sys32_creat(const char __user * pathname, u32 mode)
{
return sys_creat(pathname, (int)mode);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_waitpid(u32 pid, unsigned int * stat_addr, u32 options)
+asmlinkage long sys32_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options)
{
return sys_waitpid((int)pid, stat_addr, (int)options);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t *grouplist)
+asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t __user *grouplist)
{
return sys_getgroups((int)gidsetsize, grouplist);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_mkdir(const char * pathname, u32 mode)
+asmlinkage long sys32_mkdir(const char __user * pathname, u32 mode)
{
return sys_mkdir(pathname, (int)mode);
}
* This is just a version for 32-bit applications which does
* not force O_LARGEFILE on.
*/
-long sys32_open(const char * filename, int flags, int mode)
+asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
{
char * tmp;
int fd, error;
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_readlink(const char * path, char * buf, u32 bufsiz)
+asmlinkage long sys32_readlink(const char __user * path, char __user * buf, u32 bufsiz)
{
return sys_readlink(path, buf, (int)bufsiz);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param *param)
+asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param __user *param)
{
return sys_sched_getparam((int)pid, param);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param *param)
+asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param __user *param)
{
return sys_sched_setparam((int)pid, param);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param *param)
+asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param)
{
return sys_sched_setscheduler((int)pid, (int)policy, param);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_setdomainname(char *name, u32 len)
+asmlinkage long sys32_setdomainname(char __user *name, u32 len)
{
return sys_setdomainname(name, (int)len);
}
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
* and the register representation of a signed int (msr in 64-bit mode) is performed.
*/
-asmlinkage long sys32_setgroups(u32 gidsetsize, gid_t *grouplist)
+asmlinkage long sys32_setgroups(u32 gidsetsize, gid_t __user *grouplist)
{
return sys_setgroups((int)gidsetsize, grouplist);
}
-asmlinkage long sys32_sethostname(char *name, u32 len)
+asmlinkage long sys32_sethostname(char __user *name, u32 len)
{
/* sign extend len */
return sys_sethostname(name, (int)len);
return sys_ssetmask((int) newmask);
}
-long sys32_syslog(u32 type, char * buf, u32 len)
+asmlinkage long sys32_syslog(u32 type, char __user * buf, u32 len)
{
/* sign extend len */
return sys_syslog(type, buf, (int)len);
u32 __unused[4];
};
-extern asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+extern asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
{
struct __sysctl_args32 tmp;
int error;
- size_t oldlen, *oldlenp = NULL;
- unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+ size_t oldlen;
+ size_t __user *oldlenp = NULL;
+ unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
if (copy_from_user(&tmp, args, sizeof(tmp)))
return -EFAULT;
basically copy the whole sysctl.c here, and
glibc's __sysctl uses rw memory for the structure
anyway. */
- if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
- put_user(oldlen, (size_t *)addr))
+ oldlenp = (size_t __user *)addr;
+ if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) ||
+ put_user(oldlen, oldlenp))
return -EFAULT;
- oldlenp = (size_t *)addr;
}
lock_kernel();
- error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
- oldlenp, (void *)A(tmp.newval), tmp.newlen);
+ error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval),
+ oldlenp, (void __user *)A(tmp.newval), tmp.newlen);
unlock_kernel();
if (oldlenp) {
if (!error) {
- if (get_user(oldlen, (size_t *)addr) ||
- put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+ if (get_user(oldlen, oldlenp) ||
+ put_user(oldlen, (u32 __user *)A(tmp.oldlenp)))
error = -EFAULT;
}
copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
return error;
}
-asmlinkage long sys32_time(compat_time_t* tloc)
+asmlinkage long sys32_time(compat_time_t __user * tloc)
{
compat_time_t secs;
return secs;
}
-int sys32_olduname(struct oldold_utsname * name)
+asmlinkage int sys32_olduname(struct oldold_utsname __user * name)
{
int error;
+ struct new_utsname *ptr;
if (!name)
return -EFAULT;
return -EFAULT;
down_read(&uts_sem);
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+ ptr = vx_new_utsname();
+ error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN);
error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN);
error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN);
error -= __put_user(0,name->release+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN);
error -= __put_user(0,name->version+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN);
error = __put_user(0,name->machine+__OLD_UTS_LEN);
up_read(&uts_sem);
return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
}
-int get_compat_timeval(struct timeval *tv, struct compat_timeval *ctv)
+int get_compat_timeval(struct timeval *tv, struct compat_timeval __user *ctv)
{
return (verify_area(VERIFY_READ, ctv, sizeof(*ctv)) ||
__get_user(tv->tv_sec, &ctv->tv_sec) ||
__get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}
-long sys32_utimes(char *filename, struct compat_timeval *tvs)
+asmlinkage long sys32_utimes(char __user *filename, struct compat_timeval __user *tvs)
{
- char *kfilename;
- struct timeval ktvs[2];
- mm_segment_t old_fs;
- long ret;
-
- kfilename = getname(filename);
- ret = PTR_ERR(kfilename);
- if (!IS_ERR(kfilename)) {
- if (tvs) {
- if (get_compat_timeval(&ktvs[0], &tvs[0]) ||
- get_compat_timeval(&ktvs[1], &tvs[1]))
- return -EFAULT;
- }
+ struct timeval ktvs[2], *ptr;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = do_utimes(kfilename, (tvs ? &ktvs[0] : NULL));
- set_fs(old_fs);
-
- putname(kfilename);
+ ptr = NULL;
+ if (tvs) {
+ if (get_compat_timeval(&ktvs[0], &tvs[0]) ||
+ get_compat_timeval(&ktvs[1], &tvs[1]))
+ return -EFAULT;
+ ptr = ktvs;
}
- return ret;
+
+ return do_utimes(filename, ptr);
}
long sys32_tgkill(u32 tgid, u32 pid, int sig)
* The 32 bit ABI passes long longs in an odd even register pair.
*/
-compat_ssize_t sys32_pread64(unsigned int fd, char *ubuf, compat_size_t count,
+compat_ssize_t sys32_pread64(unsigned int fd, char __user *ubuf, compat_size_t count,
u32 reg6, u32 poshi, u32 poslo)
{
return sys_pread64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
}
-compat_ssize_t sys32_pwrite64(unsigned int fd, char *ubuf, compat_size_t count,
+compat_ssize_t sys32_pwrite64(unsigned int fd, char __user *ubuf, compat_size_t count,
u32 reg6, u32 poshi, u32 poslo)
{
return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo);
return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count);
}
-asmlinkage int sys32_truncate64(const char * path, u32 reg4,
+asmlinkage int sys32_truncate64(const char __user * path, u32 reg4,
unsigned long high, unsigned long low)
{
return sys_truncate(path, (high << 32) | low);
return sys_ftruncate(fd, (high << 32) | low);
}
-long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf,
+long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
size_t len)
{
return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
(u64)len_high << 32 | len_low, advice);
}
-extern long sys_timer_create(clockid_t, sigevent_t *, timer_t *);
+extern asmlinkage long sys_timer_create(clockid_t, sigevent_t __user *, timer_t __user *);
long ppc32_timer_create(clockid_t clock,
struct compat_sigevent __user *ev32,
savefs = get_fs();
set_fs(KERNEL_DS);
- err = sys_timer_create(clock, &event, &t);
+ /* The __user pointer casts are valid due to the set_fs() */
+ err = sys_timer_create(clock,
+ (sigevent_t __user *) &event,
+ (timer_t __user *) &t);
set_fs(savefs);
if (err == 0)