linux/arch/x86/ia32/sys_ia32.c
<<
>>
Prefs
   1/*
   2 * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
   3 *             sys_sparc32
   4 *
   5 * Copyright (C) 2000           VA Linux Co
   6 * Copyright (C) 2000           Don Dugger <n0ano@valinux.com>
   7 * Copyright (C) 1999           Arun Sharma <arun.sharma@intel.com>
   8 * Copyright (C) 1997,1998      Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   9 * Copyright (C) 1997           David S. Miller (davem@caip.rutgers.edu)
  10 * Copyright (C) 2000           Hewlett-Packard Co.
  11 * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
  12 * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port)
  13 *
  14 * These routines maintain argument size conversion between 32bit and 64bit
  15 * environment. In 2.5 most of this should be moved to a generic directory.
  16 *
  17 * This file assumes that there is a hole at the end of user address space.
  18 *
  19 * Some of the functions are LE specific currently. These are
  20 * hopefully all marked.  This should be fixed.
  21 */
  22
  23#include <linux/kernel.h>
  24#include <linux/sched.h>
  25#include <linux/fs.h>
  26#include <linux/file.h>
  27#include <linux/signal.h>
  28#include <linux/syscalls.h>
  29#include <linux/resource.h>
  30#include <linux/times.h>
  31#include <linux/utsname.h>
  32#include <linux/smp.h>
  33#include <linux/smp_lock.h>
  34#include <linux/sem.h>
  35#include <linux/msg.h>
  36#include <linux/mm.h>
  37#include <linux/shm.h>
  38#include <linux/slab.h>
  39#include <linux/uio.h>
  40#include <linux/nfs_fs.h>
  41#include <linux/quota.h>
  42#include <linux/module.h>
  43#include <linux/sunrpc/svc.h>
  44#include <linux/nfsd/nfsd.h>
  45#include <linux/nfsd/cache.h>
  46#include <linux/nfsd/xdr.h>
  47#include <linux/nfsd/syscall.h>
  48#include <linux/poll.h>
  49#include <linux/personality.h>
  50#include <linux/stat.h>
  51#include <linux/ipc.h>
  52#include <linux/rwsem.h>
  53#include <linux/binfmts.h>
  54#include <linux/init.h>
  55#include <linux/aio_abi.h>
  56#include <linux/aio.h>
  57#include <linux/compat.h>
  58#include <linux/vfs.h>
  59#include <linux/ptrace.h>
  60#include <linux/highuid.h>
  61#include <linux/vmalloc.h>
  62#include <linux/fsnotify.h>
  63#include <linux/sysctl.h>
  64#include <asm/mman.h>
  65#include <asm/types.h>
  66#include <asm/uaccess.h>
  67#include <asm/semaphore.h>
  68#include <asm/atomic.h>
  69#include <asm/ldt.h>
  70
  71#include <net/scm.h>
  72#include <net/sock.h>
  73#include <asm/ia32.h>
  74
  75#define AA(__x)         ((unsigned long)(__x))
  76
  77int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
  78{
  79        compat_ino_t ino;
  80
  81        typeof(ubuf->st_uid) uid = 0;
  82        typeof(ubuf->st_gid) gid = 0;
  83        SET_UID(uid, kbuf->uid);
  84        SET_GID(gid, kbuf->gid);
  85        if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
  86                return -EOVERFLOW;
  87        if (kbuf->size >= 0x7fffffff)
  88                return -EOVERFLOW;
  89        ino = kbuf->ino;
  90        if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
  91                return -EOVERFLOW;
  92        if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
  93            __put_user(old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
  94            __put_user(ino, &ubuf->st_ino) ||
  95            __put_user(kbuf->mode, &ubuf->st_mode) ||
  96            __put_user(kbuf->nlink, &ubuf->st_nlink) ||
  97            __put_user(uid, &ubuf->st_uid) ||
  98            __put_user(gid, &ubuf->st_gid) ||
  99            __put_user(old_encode_dev(kbuf->rdev), &ubuf->st_rdev) ||
 100            __put_user(kbuf->size, &ubuf->st_size) ||
 101            __put_user(kbuf->atime.tv_sec, &ubuf->st_atime) ||
 102            __put_user(kbuf->atime.tv_nsec, &ubuf->st_atime_nsec) ||
 103            __put_user(kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
 104            __put_user(kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
 105            __put_user(kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
 106            __put_user(kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
 107            __put_user(kbuf->blksize, &ubuf->st_blksize) ||
 108            __put_user(kbuf->blocks, &ubuf->st_blocks))
 109                return -EFAULT;
 110        return 0;
 111}
 112
 113asmlinkage long sys32_truncate64(char __user *filename,
 114                                 unsigned long offset_low,
 115                                 unsigned long offset_high)
 116{
 117       return sys_truncate(filename, ((loff_t) offset_high << 32) | offset_low);
 118}
 119
 120asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low,
 121                                  unsigned long offset_high)
 122{
 123       return sys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
 124}
 125
 126/*
 127 * Another set for IA32/LFS -- x86_64 struct stat is different due to
 128 * support for 64bit inode numbers.
 129 */
 130static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
 131{
 132        typeof(ubuf->st_uid) uid = 0;
 133        typeof(ubuf->st_gid) gid = 0;
 134        SET_UID(uid, stat->uid);
 135        SET_GID(gid, stat->gid);
 136        if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
 137            __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
 138            __put_user(stat->ino, &ubuf->__st_ino) ||
 139            __put_user(stat->ino, &ubuf->st_ino) ||
 140            __put_user(stat->mode, &ubuf->st_mode) ||
 141            __put_user(stat->nlink, &ubuf->st_nlink) ||
 142            __put_user(uid, &ubuf->st_uid) ||
 143            __put_user(gid, &ubuf->st_gid) ||
 144            __put_user(huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
 145            __put_user(stat->size, &ubuf->st_size) ||
 146            __put_user(stat->atime.tv_sec, &ubuf->st_atime) ||
 147            __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec) ||
 148            __put_user(stat->mtime.tv_sec, &ubuf->st_mtime) ||
 149            __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
 150            __put_user(stat->ctime.tv_sec, &ubuf->st_ctime) ||
 151            __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
 152            __put_user(stat->blksize, &ubuf->st_blksize) ||
 153            __put_user(stat->blocks, &ubuf->st_blocks))
 154                return -EFAULT;
 155        return 0;
 156}
 157
 158asmlinkage long sys32_stat64(char __user *filename,
 159                             struct stat64 __user *statbuf)
 160{
 161        struct kstat stat;
 162        int ret = vfs_stat(filename, &stat);
 163
 164        if (!ret)
 165                ret = cp_stat64(statbuf, &stat);
 166        return ret;
 167}
 168
 169asmlinkage long sys32_lstat64(char __user *filename,
 170                              struct stat64 __user *statbuf)
 171{
 172        struct kstat stat;
 173        int ret = vfs_lstat(filename, &stat);
 174        if (!ret)
 175                ret = cp_stat64(statbuf, &stat);
 176        return ret;
 177}
 178
 179asmlinkage long sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
 180{
 181        struct kstat stat;
 182        int ret = vfs_fstat(fd, &stat);
 183        if (!ret)
 184                ret = cp_stat64(statbuf, &stat);
 185        return ret;
 186}
 187
 188asmlinkage long sys32_fstatat(unsigned int dfd, char __user *filename,
 189                              struct stat64 __user *statbuf, int flag)
 190{
 191        struct kstat stat;
 192        int error = -EINVAL;
 193
 194        if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
 195                goto out;
 196
 197        if (flag & AT_SYMLINK_NOFOLLOW)
 198                error = vfs_lstat_fd(dfd, filename, &stat);
 199        else
 200                error = vfs_stat_fd(dfd, filename, &stat);
 201
 202        if (!error)
 203                error = cp_stat64(statbuf, &stat);
 204
 205out:
 206        return error;
 207}
 208
 209/*
 210 * Linux/i386 didn't use to be able to handle more than
 211 * 4 system call parameters, so these system calls used a memory
 212 * block for parameter passing..
 213 */
 214
 215struct mmap_arg_struct {
 216        unsigned int addr;
 217        unsigned int len;
 218        unsigned int prot;
 219        unsigned int flags;
 220        unsigned int fd;
 221        unsigned int offset;
 222};
 223
 224asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg)
 225{
 226        struct mmap_arg_struct a;
 227        struct file *file = NULL;
 228        unsigned long retval;
 229        struct mm_struct *mm ;
 230
 231        if (copy_from_user(&a, arg, sizeof(a)))
 232                return -EFAULT;
 233
 234        if (a.offset & ~PAGE_MASK)
 235                return -EINVAL;
 236
 237        if (!(a.flags & MAP_ANONYMOUS)) {
 238                file = fget(a.fd);
 239                if (!file)
 240                        return -EBADF;
 241        }
 242
 243        mm = current->mm;
 244        down_write(&mm->mmap_sem);
 245        retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags,
 246                               a.offset>>PAGE_SHIFT);
 247        if (file)
 248                fput(file);
 249
 250        up_write(&mm->mmap_sem);
 251
 252        return retval;
 253}
 254
 255asmlinkage long sys32_mprotect(unsigned long start, size_t len,
 256                               unsigned long prot)
 257{
 258        return sys_mprotect(start, len, prot);
 259}
 260
 261asmlinkage long sys32_pipe(int __user *fd)
 262{
 263        int retval;
 264        int fds[2];
 265
 266        retval = do_pipe(fds);
 267        if (retval)
 268                goto out;
 269        if (copy_to_user(fd, fds, sizeof(fds)))
 270                retval = -EFAULT;
 271out:
 272        return retval;
 273}
 274
 275asmlinkage long sys32_rt_sigaction(int sig, struct sigaction32 __user *act,
 276                                   struct sigaction32 __user *oact,
 277                                   unsigned int sigsetsize)
 278{
 279        struct k_sigaction new_ka, old_ka;
 280        int ret;
 281        compat_sigset_t set32;
 282
 283        /* XXX: Don't preclude handling different sized sigset_t's.  */
 284        if (sigsetsize != sizeof(compat_sigset_t))
 285                return -EINVAL;
 286
 287        if (act) {
 288                compat_uptr_t handler, restorer;
 289
 290                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 291                    __get_user(handler, &act->sa_handler) ||
 292                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 293                    __get_user(restorer, &act->sa_restorer) ||
 294                    __copy_from_user(&set32, &act->sa_mask,
 295                                     sizeof(compat_sigset_t)))
 296                        return -EFAULT;
 297                new_ka.sa.sa_handler = compat_ptr(handler);
 298                new_ka.sa.sa_restorer = compat_ptr(restorer);
 299
 300                /*
 301                 * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
 302                 * than _NSIG_WORDS << 1
 303                 */
 304                switch (_NSIG_WORDS) {
 305                case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
 306                                | (((long)set32.sig[7]) << 32);
 307                case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
 308                                | (((long)set32.sig[5]) << 32);
 309                case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
 310                                | (((long)set32.sig[3]) << 32);
 311                case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
 312                                | (((long)set32.sig[1]) << 32);
 313                }
 314        }
 315
 316        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 317
 318        if (!ret && oact) {
 319                /*
 320                 * FIXME: here we rely on _COMPAT_NSIG_WORS to be >=
 321                 * than _NSIG_WORDS << 1
 322                 */
 323                switch (_NSIG_WORDS) {
 324                case 4:
 325                        set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
 326                        set32.sig[6] = old_ka.sa.sa_mask.sig[3];
 327                case 3:
 328                        set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
 329                        set32.sig[4] = old_ka.sa.sa_mask.sig[2];
 330                case 2:
 331                        set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
 332                        set32.sig[2] = old_ka.sa.sa_mask.sig[1];
 333                case 1:
 334                        set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
 335                        set32.sig[0] = old_ka.sa.sa_mask.sig[0];
 336                }
 337                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 338                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
 339                               &oact->sa_handler) ||
 340                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
 341                               &oact->sa_restorer) ||
 342                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 343                    __copy_to_user(&oact->sa_mask, &set32,
 344                                   sizeof(compat_sigset_t)))
 345                        return -EFAULT;
 346        }
 347
 348        return ret;
 349}
 350
 351asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
 352                                struct old_sigaction32 __user *oact)
 353{
 354        struct k_sigaction new_ka, old_ka;
 355        int ret;
 356
 357        if (act) {
 358                compat_old_sigset_t mask;
 359                compat_uptr_t handler, restorer;
 360
 361                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
 362                    __get_user(handler, &act->sa_handler) ||
 363                    __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 364                    __get_user(restorer, &act->sa_restorer) ||
 365                    __get_user(mask, &act->sa_mask))
 366                        return -EFAULT;
 367
 368                new_ka.sa.sa_handler = compat_ptr(handler);
 369                new_ka.sa.sa_restorer = compat_ptr(restorer);
 370
 371                siginitset(&new_ka.sa.sa_mask, mask);
 372        }
 373
 374        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 375
 376        if (!ret && oact) {
 377                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
 378                    __put_user(ptr_to_compat(old_ka.sa.sa_handler),
 379                               &oact->sa_handler) ||
 380                    __put_user(ptr_to_compat(old_ka.sa.sa_restorer),
 381                               &oact->sa_restorer) ||
 382                    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 383                    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
 384                        return -EFAULT;
 385        }
 386
 387        return ret;
 388}
 389
 390asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
 391                                     compat_sigset_t __user *oset,
 392                                     unsigned int sigsetsize)
 393{
 394        sigset_t s;
 395        compat_sigset_t s32;
 396        int ret;
 397        mm_segment_t old_fs = get_fs();
 398
 399        if (set) {
 400                if (copy_from_user(&s32, set, sizeof(compat_sigset_t)))
 401                        return -EFAULT;
 402                switch (_NSIG_WORDS) {
 403                case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 404                case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 405                case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
 406                case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
 407                }
 408        }
 409        set_fs(KERNEL_DS);
 410        ret = sys_rt_sigprocmask(how,
 411                                 set ? (sigset_t __user *)&s : NULL,
 412                                 oset ? (sigset_t __user *)&s : NULL,
 413                                 sigsetsize);
 414        set_fs(old_fs);
 415        if (ret)
 416                return ret;
 417        if (oset) {
 418                switch (_NSIG_WORDS) {
 419                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 420                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 421                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 422                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 423                }
 424                if (copy_to_user(oset, &s32, sizeof(compat_sigset_t)))
 425                        return -EFAULT;
 426        }
 427        return 0;
 428}
 429
 430static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
 431{
 432        int err = -EFAULT;
 433
 434        if (access_ok(VERIFY_READ, i, sizeof(*i))) {
 435                err = __get_user(o->tv_sec, &i->tv_sec);
 436                err |= __get_user(o->tv_usec, &i->tv_usec);
 437        }
 438        return err;
 439}
 440
 441static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
 442{
 443        int err = -EFAULT;
 444
 445        if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
 446                err = __put_user(i->tv_sec, &o->tv_sec);
 447                err |= __put_user(i->tv_usec, &o->tv_usec);
 448        }
 449        return err;
 450}
 451
 452asmlinkage long sys32_alarm(unsigned int seconds)
 453{
 454        return alarm_setitimer(seconds);
 455}
 456
 457/*
 458 * Translations due to time_t size differences. Which affects all
 459 * sorts of things, like timeval and itimerval.
 460 */
 461asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
 462                                   struct timezone __user *tz)
 463{
 464        if (tv) {
 465                struct timeval ktv;
 466
 467                do_gettimeofday(&ktv);
 468                if (put_tv32(tv, &ktv))
 469                        return -EFAULT;
 470        }
 471        if (tz) {
 472                if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
 473                        return -EFAULT;
 474        }
 475        return 0;
 476}
 477
 478asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
 479                                   struct timezone __user *tz)
 480{
 481        struct timeval ktv;
 482        struct timespec kts;
 483        struct timezone ktz;
 484
 485        if (tv) {
 486                if (get_tv32(&ktv, tv))
 487                        return -EFAULT;
 488                kts.tv_sec = ktv.tv_sec;
 489                kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC;
 490        }
 491        if (tz) {
 492                if (copy_from_user(&ktz, tz, sizeof(ktz)))
 493                        return -EFAULT;
 494        }
 495
 496        return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 497}
 498
 499struct sel_arg_struct {
 500        unsigned int n;
 501        unsigned int inp;
 502        unsigned int outp;
 503        unsigned int exp;
 504        unsigned int tvp;
 505};
 506
 507asmlinkage long sys32_old_select(struct sel_arg_struct __user *arg)
 508{
 509        struct sel_arg_struct a;
 510
 511        if (copy_from_user(&a, arg, sizeof(a)))
 512                return -EFAULT;
 513        return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
 514                                 compat_ptr(a.exp), compat_ptr(a.tvp));
 515}
 516
 517asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
 518                              int options)
 519{
 520        return compat_sys_wait4(pid, stat_addr, options, NULL);
 521}
 522
 523/* 32-bit timeval and related flotsam.  */
 524
 525asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2)
 526{
 527        return sys_sysfs(option, arg1, arg2);
 528}
 529
 530asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
 531                                    struct compat_timespec __user *interval)
 532{
 533        struct timespec t;
 534        int ret;
 535        mm_segment_t old_fs = get_fs();
 536
 537        set_fs(KERNEL_DS);
 538        ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
 539        set_fs(old_fs);
 540        if (put_compat_timespec(&t, interval))
 541                return -EFAULT;
 542        return ret;
 543}
 544
 545asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
 546                                    compat_size_t sigsetsize)
 547{
 548        sigset_t s;
 549        compat_sigset_t s32;
 550        int ret;
 551        mm_segment_t old_fs = get_fs();
 552
 553        set_fs(KERNEL_DS);
 554        ret = sys_rt_sigpending((sigset_t __user *)&s, sigsetsize);
 555        set_fs(old_fs);
 556        if (!ret) {
 557                switch (_NSIG_WORDS) {
 558                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 559                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 560                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 561                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 562                }
 563                if (copy_to_user(set, &s32, sizeof(compat_sigset_t)))
 564                        return -EFAULT;
 565        }
 566        return ret;
 567}
 568
 569asmlinkage long sys32_rt_sigqueueinfo(int pid, int sig,
 570                                      compat_siginfo_t __user *uinfo)
 571{
 572        siginfo_t info;
 573        int ret;
 574        mm_segment_t old_fs = get_fs();
 575
 576        if (copy_siginfo_from_user32(&info, uinfo))
 577                return -EFAULT;
 578        set_fs(KERNEL_DS);
 579        ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
 580        set_fs(old_fs);
 581        return ret;
 582}
 583
 584/* These are here just in case some old ia32 binary calls it. */
 585asmlinkage long sys32_pause(void)
 586{
 587        current->state = TASK_INTERRUPTIBLE;
 588        schedule();
 589        return -ERESTARTNOHAND;
 590}
 591
 592
 593#ifdef CONFIG_SYSCTL_SYSCALL
 594struct sysctl_ia32 {
 595        unsigned int    name;
 596        int             nlen;
 597        unsigned int    oldval;
 598        unsigned int    oldlenp;
 599        unsigned int    newval;
 600        unsigned int    newlen;
 601        unsigned int    __unused[4];
 602};
 603
 604
 605asmlinkage long sys32_sysctl(struct sysctl_ia32 __user *args32)
 606{
 607        struct sysctl_ia32 a32;
 608        mm_segment_t old_fs = get_fs();
 609        void __user *oldvalp, *newvalp;
 610        size_t oldlen;
 611        int __user *namep;
 612        long ret;
 613
 614        if (copy_from_user(&a32, args32, sizeof(a32)))
 615                return -EFAULT;
 616
 617        /*
 618         * We need to pre-validate these because we have to disable
 619         * address checking before calling do_sysctl() because of
 620         * OLDLEN but we can't run the risk of the user specifying bad
 621         * addresses here.  Well, since we're dealing with 32 bit
 622         * addresses, we KNOW that access_ok() will always succeed, so
 623         * this is an expensive NOP, but so what...
 624         */
 625        namep = compat_ptr(a32.name);
 626        oldvalp = compat_ptr(a32.oldval);
 627        newvalp =  compat_ptr(a32.newval);
 628
 629        if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
 630            || !access_ok(VERIFY_WRITE, namep, 0)
 631            || !access_ok(VERIFY_WRITE, oldvalp, 0)
 632            || !access_ok(VERIFY_WRITE, newvalp, 0))
 633                return -EFAULT;
 634
 635        set_fs(KERNEL_DS);
 636        lock_kernel();
 637        ret = do_sysctl(namep, a32.nlen, oldvalp, (size_t __user *)&oldlen,
 638                        newvalp, (size_t) a32.newlen);
 639        unlock_kernel();
 640        set_fs(old_fs);
 641
 642        if (oldvalp && put_user(oldlen, (int __user *)compat_ptr(a32.oldlenp)))
 643                return -EFAULT;
 644
 645        return ret;
 646}
 647#endif
 648
 649/* warning: next two assume little endian */
 650asmlinkage long sys32_pread(unsigned int fd, char __user *ubuf, u32 count,
 651                            u32 poslo, u32 poshi)
 652{
 653        return sys_pread64(fd, ubuf, count,
 654                         ((loff_t)AA(poshi) << 32) | AA(poslo));
 655}
 656
 657asmlinkage long sys32_pwrite(unsigned int fd, char __user *ubuf, u32 count,
 658                             u32 poslo, u32 poshi)
 659{
 660        return sys_pwrite64(fd, ubuf, count,
 661                          ((loff_t)AA(poshi) << 32) | AA(poslo));
 662}
 663
 664
 665asmlinkage long sys32_personality(unsigned long personality)
 666{
 667        int ret;
 668
 669        if (personality(current->personality) == PER_LINUX32 &&
 670                personality == PER_LINUX)
 671                personality = PER_LINUX32;
 672        ret = sys_personality(personality);
 673        if (ret == PER_LINUX32)
 674                ret = PER_LINUX;
 675        return ret;
 676}
 677
 678asmlinkage long sys32_sendfile(int out_fd, int in_fd,
 679                               compat_off_t __user *offset, s32 count)
 680{
 681        mm_segment_t old_fs = get_fs();
 682        int ret;
 683        off_t of;
 684
 685        if (offset && get_user(of, offset))
 686                return -EFAULT;
 687
 688        set_fs(KERNEL_DS);
 689        ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
 690                           count);
 691        set_fs(old_fs);
 692
 693        if (offset && put_user(of, offset))
 694                return -EFAULT;
 695        return ret;
 696}
 697
 698asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 699                            unsigned long prot, unsigned long flags,
 700                            unsigned long fd, unsigned long pgoff)
 701{
 702        struct mm_struct *mm = current->mm;
 703        unsigned long error;
 704        struct file *file = NULL;
 705
 706        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 707        if (!(flags & MAP_ANONYMOUS)) {
 708                file = fget(fd);
 709                if (!file)
 710                        return -EBADF;
 711        }
 712
 713        down_write(&mm->mmap_sem);
 714        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 715        up_write(&mm->mmap_sem);
 716
 717        if (file)
 718                fput(file);
 719        return error;
 720}
 721
 722asmlinkage long sys32_olduname(struct oldold_utsname __user *name)
 723{
 724        char *arch = "x86_64";
 725        int err;
 726
 727        if (!name)
 728                return -EFAULT;
 729        if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
 730                return -EFAULT;
 731
 732        down_read(&uts_sem);
 733
 734        err = __copy_to_user(&name->sysname, &utsname()->sysname,
 735                             __OLD_UTS_LEN);
 736        err |= __put_user(0, name->sysname+__OLD_UTS_LEN);
 737        err |= __copy_to_user(&name->nodename, &utsname()->nodename,
 738                              __OLD_UTS_LEN);
 739        err |= __put_user(0, name->nodename+__OLD_UTS_LEN);
 740        err |= __copy_to_user(&name->release, &utsname()->release,
 741                              __OLD_UTS_LEN);
 742        err |= __put_user(0, name->release+__OLD_UTS_LEN);
 743        err |= __copy_to_user(&name->version, &utsname()->version,
 744                              __OLD_UTS_LEN);
 745        err |= __put_user(0, name->version+__OLD_UTS_LEN);
 746
 747        if (personality(current->personality) == PER_LINUX32)
 748                arch = "i686";
 749
 750        err |= __copy_to_user(&name->machine, arch, strlen(arch) + 1);
 751
 752        up_read(&uts_sem);
 753
 754        err = err ? -EFAULT : 0;
 755
 756        return err;
 757}
 758
 759long sys32_uname(struct old_utsname __user *name)
 760{
 761        int err;
 762
 763        if (!name)
 764                return -EFAULT;
 765        down_read(&uts_sem);
 766        err = copy_to_user(name, utsname(), sizeof(*name));
 767        up_read(&uts_sem);
 768        if (personality(current->personality) == PER_LINUX32)
 769                err |= copy_to_user(&name->machine, "i686", 5);
 770
 771        return err ? -EFAULT : 0;
 772}
 773
 774long sys32_ustat(unsigned dev, struct ustat32 __user *u32p)
 775{
 776        struct ustat u;
 777        mm_segment_t seg;
 778        int ret;
 779
 780        seg = get_fs();
 781        set_fs(KERNEL_DS);
 782        ret = sys_ustat(dev, (struct ustat __user *)&u);
 783        set_fs(seg);
 784        if (ret < 0)
 785                return ret;
 786
 787        if (!access_ok(VERIFY_WRITE, u32p, sizeof(struct ustat32)) ||
 788            __put_user((__u32) u.f_tfree, &u32p->f_tfree) ||
 789            __put_user((__u32) u.f_tinode, &u32p->f_tfree) ||
 790            __copy_to_user(&u32p->f_fname, u.f_fname, sizeof(u.f_fname)) ||
 791            __copy_to_user(&u32p->f_fpack, u.f_fpack, sizeof(u.f_fpack)))
 792                ret = -EFAULT;
 793        return ret;
 794}
 795
 796asmlinkage long sys32_execve(char __user *name, compat_uptr_t __user *argv,
 797                             compat_uptr_t __user *envp, struct pt_regs *regs)
 798{
 799        long error;
 800        char *filename;
 801
 802        filename = getname(name);
 803        error = PTR_ERR(filename);
 804        if (IS_ERR(filename))
 805                return error;
 806        error = compat_do_execve(filename, argv, envp, regs);
 807        if (error == 0) {
 808                task_lock(current);
 809                current->ptrace &= ~PT_DTRACE;
 810                task_unlock(current);
 811        }
 812        putname(filename);
 813        return error;
 814}
 815
 816asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
 817                            struct pt_regs *regs)
 818{
 819        void __user *parent_tid = (void __user *)regs->dx;
 820        void __user *child_tid = (void __user *)regs->di;
 821
 822        if (!newsp)
 823                newsp = regs->sp;
 824        return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
 825}
 826
 827/*
 828 * Some system calls that need sign extended arguments. This could be
 829 * done by a generic wrapper.
 830 */
 831long sys32_lseek(unsigned int fd, int offset, unsigned int whence)
 832{
 833        return sys_lseek(fd, offset, whence);
 834}
 835
 836long sys32_kill(int pid, int sig)
 837{
 838        return sys_kill(pid, sig);
 839}
 840
 841long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
 842                        __u32 len_low, __u32 len_high, int advice)
 843{
 844        return sys_fadvise64_64(fd,
 845                               (((u64)offset_high)<<32) | offset_low,
 846                               (((u64)len_high)<<32) | len_low,
 847                                advice);
 848}
 849
 850long sys32_vm86_warning(void)
 851{
 852        struct task_struct *me = current;
 853        static char lastcomm[sizeof(me->comm)];
 854
 855        if (strncmp(lastcomm, me->comm, sizeof(lastcomm))) {
 856                compat_printk(KERN_INFO
 857                              "%s: vm86 mode not supported on 64 bit kernel\n",
 858                              me->comm);
 859                strncpy(lastcomm, me->comm, sizeof(lastcomm));
 860        }
 861        return -ENOSYS;
 862}
 863
 864long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
 865                          char __user *buf, size_t len)
 866{
 867        return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
 868}
 869
 870asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
 871                                   size_t count)
 872{
 873        return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
 874}
 875
 876asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi,
 877                                      unsigned n_low, unsigned n_hi,  int flags)
 878{
 879        return sys_sync_file_range(fd,
 880                                   ((u64)off_hi << 32) | off_low,
 881                                   ((u64)n_hi << 32) | n_low, flags);
 882}
 883
 884asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
 885                                size_t len, int advice)
 886{
 887        return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
 888                                len, advice);
 889}
 890
 891asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
 892                                unsigned offset_hi, unsigned len_lo,
 893                                unsigned len_hi)
 894{
 895        return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
 896                             ((u64)len_hi << 32) | len_lo);
 897}
 898
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.