#include <linux/ptrace.h>
#include <linux/highuid.h>
#include <linux/vmalloc.h>
+#include <linux/fsnotify.h>
#include <linux/vs_cvirt.h>
#include <asm/mman.h>
#include <asm/types.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
-#include <asm/ipc.h>
#include <asm/atomic.h>
#include <asm/ldt.h>
#include <net/sock.h>
#include <asm/ia32.h>
-#define A(__x) ((unsigned long)(__x))
#define AA(__x) ((unsigned long)(__x))
-#define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
{
return -EOVERFLOW;
if (kbuf->size >= 0x7fffffff)
return -EOVERFLOW;
- if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
+ if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
__put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
__put_user (kbuf->ino, &ubuf->st_ino) ||
__put_user (kbuf->mode, &ubuf->st_mode) ||
typeof(ubuf->st_gid) gid = 0;
SET_UID(uid, stat->uid);
SET_GID(gid, stat->gid);
- if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
+ if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
__put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
__put_user (stat->ino, &ubuf->__st_ino) ||
__put_user (stat->ino, &ubuf->st_ino) ||
return ret;
}
+asmlinkage long
+sys32_fstatat(unsigned int dfd, char __user *filename,
+ struct stat64 __user* statbuf, int flag)
+{
+ struct kstat stat;
+ int error = -EINVAL;
+
+ if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+ goto out;
+
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ error = vfs_lstat_fd(dfd, filename, &stat);
+ else
+ error = vfs_stat_fd(dfd, filename, &stat);
+
+ if (!error)
+ error = cp_stat64(statbuf, &stat);
+
+out:
+ return error;
+}
+
/*
* Linux/i386 didn't use to be able to handle more than
* 4 system call parameters, so these system calls used a memory
if (a.offset & ~PAGE_MASK)
return -EINVAL;
- if (a.flags & MAP_FIXED) {
- if (a.len > IA32_PAGE_OFFSET)
- return -EINVAL;
- if (a.addr > IA32_PAGE_OFFSET - a.len)
- return -ENOMEM;
- }
-
if (!(a.flags & MAP_ANONYMOUS)) {
file = fget(a.fd);
if (!file)
return retval;
}
-asmlinkage long
-sys32_munmap(unsigned long start, unsigned long len)
-{
- if ((start + len) > IA32_PAGE_OFFSET)
- return -EINVAL;
- return sys_munmap(start, len);
-}
-
asmlinkage long
sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
{
- if ((start + PAGE_ALIGN(len)) >> 32)
- return -ENOMEM;
return sys_mprotect(start,len,prot);
}
-sys32_brk(unsigned long brk)
-{
- if (brk > IA32_PAGE_OFFSET)
- return -EINVAL;
- return sys_brk(brk);
-}
-
-extern unsigned long do_mremap(unsigned long addr,
- unsigned long old_len, unsigned long new_len,
- unsigned long flags, unsigned long new_addr);
-
-asmlinkage unsigned long sys32_mremap(unsigned long addr,
- unsigned long old_len, unsigned long new_len,
- unsigned long flags, unsigned long new_addr)
-{
- struct vm_area_struct *vma;
- unsigned long ret = -EINVAL;
-
- if (old_len > IA32_PAGE_OFFSET || new_len > IA32_PAGE_OFFSET)
- goto out;
- if (addr > IA32_PAGE_OFFSET - old_len)
- goto out;
- down_write(¤t->mm->mmap_sem);
- if (flags & MREMAP_FIXED) {
- if (new_addr > IA32_PAGE_OFFSET - new_len)
- goto out_sem;
- } else if (addr > IA32_PAGE_OFFSET - new_len) {
- unsigned long map_flags = 0;
- struct file *file = NULL;
-
- ret = -ENOMEM;
- if (!(flags & MREMAP_MAYMOVE))
- goto out_sem;
-
- vma = find_vma(current->mm, addr);
- if (vma) {
- if (vma->vm_flags & VM_SHARED)
- map_flags |= MAP_SHARED;
- file = vma->vm_file;
- }
-
- /* MREMAP_FIXED checked above. */
- new_addr = get_unmapped_area(file, addr, new_len,
- vma ? vma->vm_pgoff : 0, map_flags);
- ret = new_addr;
- if (new_addr & ~PAGE_MASK)
- goto out_sem;
- flags |= MREMAP_FIXED;
- }
- ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-out_sem:
- up_write(¤t->mm->mmap_sem);
-out:
-return ret;
-}
-
-
asmlinkage long
sys32_pipe(int __user *fd)
{
if (act) {
compat_uptr_t handler, restorer;
- if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(handler, &act->sa_handler) ||
__get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
__get_user(restorer, &act->sa_restorer)||
set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
set32.sig[0] = old_ka.sa.sa_mask.sig[0];
}
- if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
+ __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
__put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
__copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t)))
return -EFAULT;
compat_old_sigset_t mask;
compat_uptr_t handler, restorer;
- if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(handler, &act->sa_handler) ||
__get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
__get_user(restorer, &act->sa_restorer) ||
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
- if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler) ||
+ __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer) ||
__put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
compat_ptr(a.exp), compat_ptr(a.tvp));
}
-/*
- * sys_time() can be implemented in user-level using
- * sys_gettimeofday(). x86-64 did this but i386 Linux did not
- * so we have to implement this system call here.
- */
-asmlinkage long sys32_time(int __user * tloc)
-{
- int i;
- struct timeval tv;
-
- do_gettimeofday(&tv);
- i = tv.tv_sec;
-
- if (tloc) {
- if (put_user(i,tloc))
- i = -EFAULT;
- }
- return i;
-}
-
extern asmlinkage long
compat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options,
struct compat_rusage *ru);
s.freehigh >>= bitcount;
}
- if (verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
+ if (!access_ok(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
__put_user (s.uptime, &info->uptime) ||
__put_user (s.loads[0], &info->loads[0]) ||
__put_user (s.loads[1], &info->loads[1]) ||
return ret;
}
-
asmlinkage long
-sys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo,
- struct compat_timespec __user *uts, compat_size_t sigsetsize)
-{
- sigset_t s;
- compat_sigset_t s32;
- struct timespec t;
- int ret;
- mm_segment_t old_fs = get_fs();
- siginfo_t info;
-
- if (copy_from_user (&s32, uthese, sizeof(compat_sigset_t)))
- return -EFAULT;
- switch (_NSIG_WORDS) {
- case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
- case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
- case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
- case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
- }
- if (uts && get_compat_timespec(&t, uts))
- return -EFAULT;
- if (uinfo) {
- /* stop data leak to user space in case of structure fill mismatch
- * between sys_rt_sigtimedwait & ia32_copy_siginfo_to_user.
- */
- memset(&info, 0, sizeof(info));
- }
- set_fs (KERNEL_DS);
- ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL,
- sigsetsize);
- set_fs (old_fs);
- if (ret >= 0 && uinfo) {
- if (ia32_copy_siginfo_to_user(uinfo, &info))
- return -EFAULT;
- }
- return ret;
-}
-
-asmlinkage long
-sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo)
+sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
{
siginfo_t info;
int ret;
mm_segment_t old_fs = get_fs();
- if (ia32_copy_siginfo_from_user(&info, uinfo))
+ if (copy_siginfo_from_user32(&info, uinfo))
return -EFAULT;
set_fs (KERNEL_DS);
ret = sys_rt_sigqueueinfo(pid, sig, &info);
}
+#ifdef CONFIG_SYSCTL
struct sysctl_ia32 {
unsigned int name;
int nlen;
asmlinkage long
sys32_sysctl(struct sysctl_ia32 __user *args32)
{
-#ifndef CONFIG_SYSCTL
- return -ENOSYS;
-#else
struct sysctl_ia32 a32;
mm_segment_t old_fs = get_fs ();
- void *oldvalp, *newvalp;
+ void __user *oldvalp, *newvalp;
size_t oldlen;
- int *namep;
+ int __user *namep;
long ret;
extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
void *newval, size_t newlen);
* addresses, we KNOW that access_ok() will always succeed, so this is an
* expensive NOP, but so what...
*/
- namep = (int *) A(a32.name);
- oldvalp = (void *) A(a32.oldval);
- newvalp = (void *) A(a32.newval);
+ namep = compat_ptr(a32.name);
+ oldvalp = compat_ptr(a32.oldval);
+ newvalp = compat_ptr(a32.newval);
if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
|| !access_ok(VERIFY_WRITE, namep, 0)
return -EFAULT;
return ret;
-#endif
}
+#endif
/* warning: next two assume little endian */
asmlinkage long
ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
set_fs(old_fs);
- if (!ret && offset && put_user(of, offset))
+ if (offset && put_user(of, offset))
return -EFAULT;
return ret;
memset(&txc, 0, sizeof(struct timex));
- if(verify_area(VERIFY_READ, utp, sizeof(struct timex32)) ||
+ if (!access_ok(VERIFY_READ, utp, sizeof(struct timex32)) ||
__get_user(txc.modes, &utp->modes) ||
__get_user(txc.offset, &utp->offset) ||
__get_user(txc.freq, &utp->freq) ||
ret = do_adjtimex(&txc);
- if(verify_area(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
+ if (!access_ok(VERIFY_WRITE, utp, sizeof(struct timex32)) ||
__put_user(txc.modes, &utp->modes) ||
__put_user(txc.offset, &utp->offset) ||
__put_user(txc.freq, &utp->freq) ||
struct file * file = NULL;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
- if (flags & MAP_FIXED) {
- if (len > IA32_PAGE_OFFSET)
- return -EINVAL;
- if (addr > IA32_PAGE_OFFSET - len)
- return -ENOMEM;
- }
-
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
if (!file)
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
-asmlinkage long sys32_waitid(int which, compat_pid_t pid,
- siginfo_t32 __user *uinfo, int options,
- struct compat_rusage __user *uru)
-{
- siginfo_t info;
- struct rusage ru;
- long ret;
- mm_segment_t old_fs = get_fs();
-
- info.si_signo = 0;
- set_fs (KERNEL_DS);
- ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options,
- uru ? &ru : NULL);
- set_fs (old_fs);
-
- if (ret < 0 || info.si_signo == 0)
- return ret;
-
- if (uru && (ret = put_compat_rusage(&ru, uru)))
- return ret;
-
- BUG_ON(info.si_code & __SI_MASK);
- info.si_code |= __SI_CHLD;
- return ia32_copy_siginfo_to_user(uinfo, &info);
-}
-
/*
* Some system calls that need sign extended arguments. This could be done by a generic wrapper.
*/
return sys_kill(pid, sig);
}
-asmlinkage long sys32_open(const char __user * filename, int flags, int mode)
-{
- char * tmp;
- int fd, error;
-
- /* don't force O_LARGEFILE */
- tmp = getname(filename);
- fd = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
- if (fd >= 0) {
- struct file *f = filp_open(tmp, flags, mode);
- error = PTR_ERR(f);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = error;
- } else
- fd_install(fd, f);
- }
- putname(tmp);
- }
- return fd;
-}
-
-struct sigevent32 {
- u32 sigev_value;
- u32 sigev_signo;
- u32 sigev_notify;
- u32 payload[(64 / 4) - 3];
-};
-
-extern asmlinkage long
-sys_timer_create(clockid_t which_clock,
- struct sigevent __user *timer_event_spec,
- timer_t __user * created_timer_id);
-
-long
-sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id)
-{
- struct sigevent __user *p = NULL;
- if (se32) {
- struct sigevent se;
- p = compat_alloc_user_space(sizeof(struct sigevent));
- memset(&se, 0, sizeof(struct sigevent));
- if (get_user(se.sigev_value.sival_int, &se32->sigev_value) ||
- __get_user(se.sigev_signo, &se32->sigev_signo) ||
- __get_user(se.sigev_notify, &se32->sigev_notify) ||
- __copy_from_user(&se._sigev_un._pad, &se32->payload,
- sizeof(se32->payload)) ||
- copy_to_user(p, &se, sizeof(se)))
- return -EFAULT;
- }
- return sys_timer_create(clock, p, timer_id);
-}
-
long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
__u32 len_low, __u32 len_high, int advice)
{
return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
}
-cond_syscall(sys32_ipc)
-
static int __init ia32_init (void)
{
printk("IA32 emulation $Id: sys_ia32.c,v 1.32 2002/03/24 13:02:28 ak Exp $\n");
__initcall(ia32_init);
extern unsigned long ia32_sys_call_table[];
+EXPORT_SYMBOL(ia32_sys_call_table);