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