linux/arch/sparc64/kernel/sys_sparc32.c
<<
>>
Prefs
   1/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
   2 *
   3 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   4 * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
   5 *
   6 * These routines maintain argument size conversion between 32bit and 64bit
   7 * environment.
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/sched.h>
  12#include <linux/capability.h>
  13#include <linux/fs.h> 
  14#include <linux/mm.h> 
  15#include <linux/file.h> 
  16#include <linux/signal.h>
  17#include <linux/resource.h>
  18#include <linux/times.h>
  19#include <linux/utsname.h>
  20#include <linux/smp.h>
  21#include <linux/smp_lock.h>
  22#include <linux/sem.h>
  23#include <linux/msg.h>
  24#include <linux/shm.h>
  25#include <linux/slab.h>
  26#include <linux/uio.h>
  27#include <linux/nfs_fs.h>
  28#include <linux/quota.h>
  29#include <linux/module.h>
  30#include <linux/sunrpc/svc.h>
  31#include <linux/nfsd/nfsd.h>
  32#include <linux/nfsd/cache.h>
  33#include <linux/nfsd/xdr.h>
  34#include <linux/nfsd/syscall.h>
  35#include <linux/poll.h>
  36#include <linux/personality.h>
  37#include <linux/stat.h>
  38#include <linux/filter.h>
  39#include <linux/highmem.h>
  40#include <linux/highuid.h>
  41#include <linux/mman.h>
  42#include <linux/ipv6.h>
  43#include <linux/in.h>
  44#include <linux/icmpv6.h>
  45#include <linux/syscalls.h>
  46#include <linux/sysctl.h>
  47#include <linux/binfmts.h>
  48#include <linux/dnotify.h>
  49#include <linux/security.h>
  50#include <linux/compat.h>
  51#include <linux/vfs.h>
  52#include <linux/netfilter_ipv4/ip_tables.h>
  53#include <linux/ptrace.h>
  54
  55#include <asm/types.h>
  56#include <asm/uaccess.h>
  57#include <asm/fpumacro.h>
  58#include <asm/mmu_context.h>
  59#include <asm/compat_signal.h>
  60
  61#ifdef CONFIG_SYSVIPC                                                        
  62asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
  63{
  64        int version;
  65
  66        version = call >> 16; /* hack for backward compatibility */
  67        call &= 0xffff;
  68
  69        switch (call) {
  70        case SEMTIMEDOP:
  71                if (fifth)
  72                        /* sign extend semid */
  73                        return compat_sys_semtimedop((int)first,
  74                                                     compat_ptr(ptr), second,
  75                                                     compat_ptr(fifth));
  76                /* else fall through for normal semop() */
  77        case SEMOP:
  78                /* struct sembuf is the same on 32 and 64bit :)) */
  79                /* sign extend semid */
  80                return sys_semtimedop((int)first, compat_ptr(ptr), second,
  81                                      NULL);
  82        case SEMGET:
  83                /* sign extend key, nsems */
  84                return sys_semget((int)first, (int)second, third);
  85        case SEMCTL:
  86                /* sign extend semid, semnum */
  87                return compat_sys_semctl((int)first, (int)second, third,
  88                                         compat_ptr(ptr));
  89
  90        case MSGSND:
  91                /* sign extend msqid */
  92                return compat_sys_msgsnd((int)first, (int)second, third,
  93                                         compat_ptr(ptr));
  94        case MSGRCV:
  95                /* sign extend msqid, msgtyp */
  96                return compat_sys_msgrcv((int)first, second, (int)fifth,
  97                                         third, version, compat_ptr(ptr));
  98        case MSGGET:
  99                /* sign extend key */
 100                return sys_msgget((int)first, second);
 101        case MSGCTL:
 102                /* sign extend msqid */
 103                return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
 104
 105        case SHMAT:
 106                /* sign extend shmid */
 107                return compat_sys_shmat((int)first, second, third, version,
 108                                        compat_ptr(ptr));
 109        case SHMDT:
 110                return sys_shmdt(compat_ptr(ptr));
 111        case SHMGET:
 112                /* sign extend key_t */
 113                return sys_shmget((int)first, second, third);
 114        case SHMCTL:
 115                /* sign extend shmid */
 116                return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
 117
 118        default:
 119                return -ENOSYS;
 120        };
 121
 122        return -ENOSYS;
 123}
 124#endif
 125
 126asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
 127{
 128        if ((int)high < 0)
 129                return -EINVAL;
 130        else
 131                return sys_truncate(path, (high << 32) | low);
 132}
 133
 134asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
 135{
 136        if ((int)high < 0)
 137                return -EINVAL;
 138        else
 139                return sys_ftruncate(fd, (high << 32) | low);
 140}
 141
 142static int cp_compat_stat64(struct kstat *stat,
 143                            struct compat_stat64 __user *statbuf)
 144{
 145        int err;
 146
 147        err  = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev);
 148        err |= put_user(stat->ino, &statbuf->st_ino);
 149        err |= put_user(stat->mode, &statbuf->st_mode);
 150        err |= put_user(stat->nlink, &statbuf->st_nlink);
 151        err |= put_user(stat->uid, &statbuf->st_uid);
 152        err |= put_user(stat->gid, &statbuf->st_gid);
 153        err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
 154        err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
 155        err |= put_user(stat->size, &statbuf->st_size);
 156        err |= put_user(stat->blksize, &statbuf->st_blksize);
 157        err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]);
 158        err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]);
 159        err |= put_user(stat->blocks, &statbuf->st_blocks);
 160        err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
 161        err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
 162        err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
 163        err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
 164        err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
 165        err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
 166        err |= put_user(0, &statbuf->__unused4);
 167        err |= put_user(0, &statbuf->__unused5);
 168
 169        return err;
 170}
 171
 172asmlinkage long compat_sys_stat64(char __user * filename,
 173                struct compat_stat64 __user *statbuf)
 174{
 175        struct kstat stat;
 176        int error = vfs_stat(filename, &stat);
 177
 178        if (!error)
 179                error = cp_compat_stat64(&stat, statbuf);
 180        return error;
 181}
 182
 183asmlinkage long compat_sys_lstat64(char __user * filename,
 184                struct compat_stat64 __user *statbuf)
 185{
 186        struct kstat stat;
 187        int error = vfs_lstat(filename, &stat);
 188
 189        if (!error)
 190                error = cp_compat_stat64(&stat, statbuf);
 191        return error;
 192}
 193
 194asmlinkage long compat_sys_fstat64(unsigned int fd,
 195                struct compat_stat64 __user * statbuf)
 196{
 197        struct kstat stat;
 198        int error = vfs_fstat(fd, &stat);
 199
 200        if (!error)
 201                error = cp_compat_stat64(&stat, statbuf);
 202        return error;
 203}
 204
 205asmlinkage long compat_sys_fstatat64(unsigned int dfd, char __user *filename,
 206                struct compat_stat64 __user * statbuf, int flag)
 207{
 208        struct kstat stat;
 209        int error = -EINVAL;
 210
 211        if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
 212                goto out;
 213
 214        if (flag & AT_SYMLINK_NOFOLLOW)
 215                error = vfs_lstat_fd(dfd, filename, &stat);
 216        else
 217                error = vfs_stat_fd(dfd, filename, &stat);
 218
 219        if (!error)
 220                error = cp_compat_stat64(&stat, statbuf);
 221
 222out:
 223        return error;
 224}
 225
 226asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
 227{
 228        return sys_sysfs(option, arg1, arg2);
 229}
 230
 231asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
 232{
 233        struct timespec t;
 234        int ret;
 235        mm_segment_t old_fs = get_fs ();
 236        
 237        set_fs (KERNEL_DS);
 238        ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
 239        set_fs (old_fs);
 240        if (put_compat_timespec(&t, interval))
 241                return -EFAULT;
 242        return ret;
 243}
 244
 245asmlinkage long compat_sys_rt_sigprocmask(int how,
 246                                          compat_sigset_t __user *set,
 247                                          compat_sigset_t __user *oset,
 248                                          compat_size_t sigsetsize)
 249{
 250        sigset_t s;
 251        compat_sigset_t s32;
 252        int ret;
 253        mm_segment_t old_fs = get_fs();
 254        
 255        if (set) {
 256                if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
 257                        return -EFAULT;
 258                switch (_NSIG_WORDS) {
 259                case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 260                case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 261                case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
 262                case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
 263                }
 264        }
 265        set_fs (KERNEL_DS);
 266        ret = sys_rt_sigprocmask(how,
 267                                 set ? (sigset_t __user *) &s : NULL,
 268                                 oset ? (sigset_t __user *) &s : NULL,
 269                                 sigsetsize);
 270        set_fs (old_fs);
 271        if (ret) return ret;
 272        if (oset) {
 273                switch (_NSIG_WORDS) {
 274                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 275                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 276                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 277                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 278                }
 279                if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
 280                        return -EFAULT;
 281        }
 282        return 0;
 283}
 284
 285asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
 286                                    compat_size_t sigsetsize)
 287{
 288        sigset_t s;
 289        compat_sigset_t s32;
 290        int ret;
 291        mm_segment_t old_fs = get_fs();
 292                
 293        set_fs (KERNEL_DS);
 294        ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
 295        set_fs (old_fs);
 296        if (!ret) {
 297                switch (_NSIG_WORDS) {
 298                case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
 299                case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
 300                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
 301                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
 302                }
 303                if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
 304                        return -EFAULT;
 305        }
 306        return ret;
 307}
 308
 309asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig,
 310                                           struct compat_siginfo __user *uinfo)
 311{
 312        siginfo_t info;
 313        int ret;
 314        mm_segment_t old_fs = get_fs();
 315        
 316        if (copy_siginfo_from_user32(&info, uinfo))
 317                return -EFAULT;
 318
 319        set_fs (KERNEL_DS);
 320        ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
 321        set_fs (old_fs);
 322        return ret;
 323}
 324
 325asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act,
 326                                     struct old_sigaction32 __user *oact)
 327{
 328        struct k_sigaction new_ka, old_ka;
 329        int ret;
 330
 331        WARN_ON_ONCE(sig >= 0);
 332        sig = -sig;
 333
 334        if (act) {
 335                compat_old_sigset_t mask;
 336                u32 u_handler, u_restorer;
 337                
 338                ret = get_user(u_handler, &act->sa_handler);
 339                new_ka.sa.sa_handler =  compat_ptr(u_handler);
 340                ret |= __get_user(u_restorer, &act->sa_restorer);
 341                new_ka.sa.sa_restorer = compat_ptr(u_restorer);
 342                ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 343                ret |= __get_user(mask, &act->sa_mask);
 344                if (ret)
 345                        return ret;
 346                new_ka.ka_restorer = NULL;
 347                siginitset(&new_ka.sa.sa_mask, mask);
 348        }
 349
 350        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 351
 352        if (!ret && oact) {
 353                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
 354                ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
 355                ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 356                ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 357        }
 358
 359        return ret;
 360}
 361
 362asmlinkage long compat_sys_rt_sigaction(int sig,
 363                                        struct sigaction32 __user *act,
 364                                        struct sigaction32 __user *oact,
 365                                        void __user *restorer,
 366                                        compat_size_t sigsetsize)
 367{
 368        struct k_sigaction new_ka, old_ka;
 369        int ret;
 370        compat_sigset_t set32;
 371
 372        /* XXX: Don't preclude handling different sized sigset_t's.  */
 373        if (sigsetsize != sizeof(compat_sigset_t))
 374                return -EINVAL;
 375
 376        if (act) {
 377                u32 u_handler, u_restorer;
 378
 379                new_ka.ka_restorer = restorer;
 380                ret = get_user(u_handler, &act->sa_handler);
 381                new_ka.sa.sa_handler =  compat_ptr(u_handler);
 382                ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
 383                switch (_NSIG_WORDS) {
 384                case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
 385                case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
 386                case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
 387                case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
 388                }
 389                ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 390                ret |= __get_user(u_restorer, &act->sa_restorer);
 391                new_ka.sa.sa_restorer = compat_ptr(u_restorer);
 392                if (ret)
 393                        return -EFAULT;
 394        }
 395
 396        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 397
 398        if (!ret && oact) {
 399                switch (_NSIG_WORDS) {
 400                case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
 401                case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
 402                case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
 403                case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
 404                }
 405                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
 406                ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
 407                ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 408                ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
 409                if (ret)
 410                        ret = -EFAULT;
 411        }
 412
 413        return ret;
 414}
 415
 416/*
 417 * sparc32_execve() executes a new program after the asm stub has set
 418 * things up for us.  This should basically do what I want it to.
 419 */
 420asmlinkage long sparc32_execve(struct pt_regs *regs)
 421{
 422        int error, base = 0;
 423        char *filename;
 424
 425        /* User register window flush is done by entry.S */
 426
 427        /* Check for indirect call. */
 428        if ((u32)regs->u_regs[UREG_G1] == 0)
 429                base = 1;
 430
 431        filename = getname(compat_ptr(regs->u_regs[base + UREG_I0]));
 432        error = PTR_ERR(filename);
 433        if (IS_ERR(filename))
 434                goto out;
 435
 436        error = compat_do_execve(filename,
 437                                 compat_ptr(regs->u_regs[base + UREG_I1]),
 438                                 compat_ptr(regs->u_regs[base + UREG_I2]), regs);
 439
 440        putname(filename);
 441
 442        if (!error) {
 443                fprs_write(0);
 444                current_thread_info()->xfsr[0] = 0;
 445                current_thread_info()->fpsaved[0] = 0;
 446                regs->tstate &= ~TSTATE_PEF;
 447        }
 448out:
 449        return error;
 450}
 451
 452#ifdef CONFIG_MODULES
 453
 454asmlinkage long sys32_init_module(void __user *umod, u32 len,
 455                                  const char __user *uargs)
 456{
 457        return sys_init_module(umod, len, uargs);
 458}
 459
 460asmlinkage long sys32_delete_module(const char __user *name_user,
 461                                    unsigned int flags)
 462{
 463        return sys_delete_module(name_user, flags);
 464}
 465
 466#else /* CONFIG_MODULES */
 467
 468asmlinkage long sys32_init_module(const char __user *name_user,
 469                                  struct module __user *mod_user)
 470{
 471        return -ENOSYS;
 472}
 473
 474asmlinkage long sys32_delete_module(const char __user *name_user)
 475{
 476        return -ENOSYS;
 477}
 478
 479#endif  /* CONFIG_MODULES */
 480
 481asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
 482                                        char __user *ubuf,
 483                                        compat_size_t count,
 484                                        unsigned long poshi,
 485                                        unsigned long poslo)
 486{
 487        return sys_pread64(fd, ubuf, count, (poshi << 32) | poslo);
 488}
 489
 490asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd,
 491                                         char __user *ubuf,
 492                                         compat_size_t count,
 493                                         unsigned long poshi,
 494                                         unsigned long poslo)
 495{
 496        return sys_pwrite64(fd, ubuf, count, (poshi << 32) | poslo);
 497}
 498
 499asmlinkage long compat_sys_readahead(int fd,
 500                                     unsigned long offhi,
 501                                     unsigned long offlo,
 502                                     compat_size_t count)
 503{
 504        return sys_readahead(fd, (offhi << 32) | offlo, count);
 505}
 506
 507long compat_sys_fadvise64(int fd,
 508                          unsigned long offhi,
 509                          unsigned long offlo,
 510                          compat_size_t len, int advice)
 511{
 512        return sys_fadvise64_64(fd, (offhi << 32) | offlo, len, advice);
 513}
 514
 515long compat_sys_fadvise64_64(int fd,
 516                             unsigned long offhi, unsigned long offlo,
 517                             unsigned long lenhi, unsigned long lenlo,
 518                             int advice)
 519{
 520        return sys_fadvise64_64(fd,
 521                                (offhi << 32) | offlo,
 522                                (lenhi << 32) | lenlo,
 523                                advice);
 524}
 525
 526asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
 527                                    compat_off_t __user *offset,
 528                                    compat_size_t count)
 529{
 530        mm_segment_t old_fs = get_fs();
 531        int ret;
 532        off_t of;
 533        
 534        if (offset && get_user(of, offset))
 535                return -EFAULT;
 536                
 537        set_fs(KERNEL_DS);
 538        ret = sys_sendfile(out_fd, in_fd,
 539                           offset ? (off_t __user *) &of : NULL,
 540                           count);
 541        set_fs(old_fs);
 542        
 543        if (offset && put_user(of, offset))
 544                return -EFAULT;
 545                
 546        return ret;
 547}
 548
 549asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd,
 550                                      compat_loff_t __user *offset,
 551                                      compat_size_t count)
 552{
 553        mm_segment_t old_fs = get_fs();
 554        int ret;
 555        loff_t lof;
 556        
 557        if (offset && get_user(lof, offset))
 558                return -EFAULT;
 559                
 560        set_fs(KERNEL_DS);
 561        ret = sys_sendfile64(out_fd, in_fd,
 562                             offset ? (loff_t __user *) &lof : NULL,
 563                             count);
 564        set_fs(old_fs);
 565        
 566        if (offset && put_user(lof, offset))
 567                return -EFAULT;
 568                
 569        return ret;
 570}
 571
 572/* This is just a version for 32-bit applications which does
 573 * not force O_LARGEFILE on.
 574 */
 575
 576asmlinkage long sparc32_open(const char __user *filename,
 577                             int flags, int mode)
 578{
 579        return do_sys_open(AT_FDCWD, filename, flags, mode);
 580}
 581
 582extern unsigned long do_mremap(unsigned long addr,
 583        unsigned long old_len, unsigned long new_len,
 584        unsigned long flags, unsigned long new_addr);
 585                
 586asmlinkage unsigned long sys32_mremap(unsigned long addr,
 587        unsigned long old_len, unsigned long new_len,
 588        unsigned long flags, u32 __new_addr)
 589{
 590        unsigned long ret = -EINVAL;
 591        unsigned long new_addr = __new_addr;
 592
 593        if (unlikely(sparc_mmap_check(addr, old_len)))
 594                goto out;
 595        if (unlikely(sparc_mmap_check(new_addr, new_len)))
 596                goto out;
 597        down_write(&current->mm->mmap_sem);
 598        ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 599        up_write(&current->mm->mmap_sem);
 600out:
 601        return ret;       
 602}
 603
 604struct __sysctl_args32 {
 605        u32 name;
 606        int nlen;
 607        u32 oldval;
 608        u32 oldlenp;
 609        u32 newval;
 610        u32 newlen;
 611        u32 __unused[4];
 612};
 613
 614asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
 615{
 616#ifndef CONFIG_SYSCTL_SYSCALL
 617        return -ENOSYS;
 618#else
 619        struct __sysctl_args32 tmp;
 620        int error;
 621        size_t oldlen, __user *oldlenp = NULL;
 622        unsigned long addr = (((unsigned long)&args->__unused[0]) + 7UL) & ~7UL;
 623
 624        if (copy_from_user(&tmp, args, sizeof(tmp)))
 625                return -EFAULT;
 626
 627        if (tmp.oldval && tmp.oldlenp) {
 628                /* Duh, this is ugly and might not work if sysctl_args
 629                   is in read-only memory, but do_sysctl does indirectly
 630                   a lot of uaccess in both directions and we'd have to
 631                   basically copy the whole sysctl.c here, and
 632                   glibc's __sysctl uses rw memory for the structure
 633                   anyway.  */
 634                if (get_user(oldlen, (u32 __user *)(unsigned long)tmp.oldlenp) ||
 635                    put_user(oldlen, (size_t __user *)addr))
 636                        return -EFAULT;
 637                oldlenp = (size_t __user *)addr;
 638        }
 639
 640        lock_kernel();
 641        error = do_sysctl((int __user *)(unsigned long) tmp.name,
 642                          tmp.nlen,
 643                          (void __user *)(unsigned long) tmp.oldval,
 644                          oldlenp,
 645                          (void __user *)(unsigned long) tmp.newval,
 646                          tmp.newlen);
 647        unlock_kernel();
 648        if (oldlenp) {
 649                if (!error) {
 650                        if (get_user(oldlen, (size_t __user *)addr) ||
 651                            put_user(oldlen, (u32 __user *)(unsigned long) tmp.oldlenp))
 652                                error = -EFAULT;
 653                }
 654                if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
 655                        error = -EFAULT;
 656        }
 657        return error;
 658#endif
 659}
 660
 661long sys32_lookup_dcookie(unsigned long cookie_high,
 662                          unsigned long cookie_low,
 663                          char __user *buf, size_t len)
 664{
 665        return sys_lookup_dcookie((cookie_high << 32) | cookie_low,
 666                                  buf, len);
 667}
 668
 669long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags)
 670{
 671        return sys_sync_file_range(fd,
 672                                   (off_high << 32) | off_low,
 673                                   (nb_high << 32) | nb_low,
 674                                   flags);
 675}
 676
 677asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
 678                                     u32 lenhi, u32 lenlo)
 679{
 680        return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
 681                             ((loff_t)lenhi << 32) | lenlo);
 682}
 683
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.