linux/arch/s390/kernel/compat_linux.c
<<
>>
Prefs
   1/*
   2 *  S390 version
   3 *    Copyright IBM Corp. 2000
   4 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
   5 *               Gerhard Tonn (ton@de.ibm.com)   
   6 *               Thomas Spatzier (tspat@de.ibm.com)
   7 *
   8 *  Conversion between 31bit and 64bit native syscalls.
   9 *
  10 * Heavily inspired by the 32-bit Sparc compat code which is 
  11 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  12 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  13 *
  14 */
  15
  16
  17#include <linux/kernel.h>
  18#include <linux/sched.h>
  19#include <linux/fs.h> 
  20#include <linux/mm.h> 
  21#include <linux/file.h> 
  22#include <linux/signal.h>
  23#include <linux/resource.h>
  24#include <linux/times.h>
  25#include <linux/smp.h>
  26#include <linux/sem.h>
  27#include <linux/msg.h>
  28#include <linux/shm.h>
  29#include <linux/uio.h>
  30#include <linux/quota.h>
  31#include <linux/module.h>
  32#include <linux/poll.h>
  33#include <linux/personality.h>
  34#include <linux/stat.h>
  35#include <linux/filter.h>
  36#include <linux/highmem.h>
  37#include <linux/highuid.h>
  38#include <linux/mman.h>
  39#include <linux/ipv6.h>
  40#include <linux/in.h>
  41#include <linux/icmpv6.h>
  42#include <linux/syscalls.h>
  43#include <linux/sysctl.h>
  44#include <linux/binfmts.h>
  45#include <linux/capability.h>
  46#include <linux/compat.h>
  47#include <linux/vfs.h>
  48#include <linux/ptrace.h>
  49#include <linux/fadvise.h>
  50#include <linux/ipc.h>
  51#include <linux/slab.h>
  52
  53#include <asm/types.h>
  54#include <asm/uaccess.h>
  55
  56#include <net/scm.h>
  57#include <net/sock.h>
  58
  59#include "compat_linux.h"
  60
  61u32 psw32_user_bits = PSW32_MASK_DAT | PSW32_MASK_IO | PSW32_MASK_EXT |
  62                      PSW32_DEFAULT_KEY | PSW32_MASK_BASE | PSW32_MASK_MCHECK |
  63                      PSW32_MASK_PSTATE | PSW32_ASC_HOME;
  64 
  65/* For this source file, we want overflow handling. */
  66
  67#undef high2lowuid
  68#undef high2lowgid
  69#undef low2highuid
  70#undef low2highgid
  71#undef SET_UID16
  72#undef SET_GID16
  73#undef NEW_TO_OLD_UID
  74#undef NEW_TO_OLD_GID
  75#undef SET_OLDSTAT_UID
  76#undef SET_OLDSTAT_GID
  77#undef SET_STAT_UID
  78#undef SET_STAT_GID
  79
  80#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
  81#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
  82#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
  83#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
  84#define SET_UID16(var, uid)     var = high2lowuid(uid)
  85#define SET_GID16(var, gid)     var = high2lowgid(gid)
  86#define NEW_TO_OLD_UID(uid)     high2lowuid(uid)
  87#define NEW_TO_OLD_GID(gid)     high2lowgid(gid)
  88#define SET_OLDSTAT_UID(stat, uid)      (stat).st_uid = high2lowuid(uid)
  89#define SET_OLDSTAT_GID(stat, gid)      (stat).st_gid = high2lowgid(gid)
  90#define SET_STAT_UID(stat, uid)         (stat).st_uid = high2lowuid(uid)
  91#define SET_STAT_GID(stat, gid)         (stat).st_gid = high2lowgid(gid)
  92
  93asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
  94{
  95        return sys_chown(filename, low2highuid(user), low2highgid(group));
  96}
  97
  98asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
  99{
 100        return sys_lchown(filename, low2highuid(user), low2highgid(group));
 101}
 102
 103asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
 104{
 105        return sys_fchown(fd, low2highuid(user), low2highgid(group));
 106}
 107
 108asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
 109{
 110        return sys_setregid(low2highgid(rgid), low2highgid(egid));
 111}
 112
 113asmlinkage long sys32_setgid16(u16 gid)
 114{
 115        return sys_setgid((gid_t)gid);
 116}
 117
 118asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
 119{
 120        return sys_setreuid(low2highuid(ruid), low2highuid(euid));
 121}
 122
 123asmlinkage long sys32_setuid16(u16 uid)
 124{
 125        return sys_setuid((uid_t)uid);
 126}
 127
 128asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
 129{
 130        return sys_setresuid(low2highuid(ruid), low2highuid(euid),
 131                low2highuid(suid));
 132}
 133
 134asmlinkage long sys32_getresuid16(u16 __user *ruidp, u16 __user *euidp, u16 __user *suidp)
 135{
 136        const struct cred *cred = current_cred();
 137        int retval;
 138        u16 ruid, euid, suid;
 139
 140        ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid));
 141        euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid));
 142        suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid));
 143
 144        if (!(retval   = put_user(ruid, ruidp)) &&
 145            !(retval   = put_user(euid, euidp)))
 146                retval = put_user(suid, suidp);
 147
 148        return retval;
 149}
 150
 151asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
 152{
 153        return sys_setresgid(low2highgid(rgid), low2highgid(egid),
 154                low2highgid(sgid));
 155}
 156
 157asmlinkage long sys32_getresgid16(u16 __user *rgidp, u16 __user *egidp, u16 __user *sgidp)
 158{
 159        const struct cred *cred = current_cred();
 160        int retval;
 161        u16 rgid, egid, sgid;
 162
 163        rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid));
 164        egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid));
 165        sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid));
 166
 167        if (!(retval   = put_user(rgid, rgidp)) &&
 168            !(retval   = put_user(egid, egidp)))
 169                retval = put_user(sgid, sgidp);
 170
 171        return retval;
 172}
 173
 174asmlinkage long sys32_setfsuid16(u16 uid)
 175{
 176        return sys_setfsuid((uid_t)uid);
 177}
 178
 179asmlinkage long sys32_setfsgid16(u16 gid)
 180{
 181        return sys_setfsgid((gid_t)gid);
 182}
 183
 184static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
 185{
 186        struct user_namespace *user_ns = current_user_ns();
 187        int i;
 188        u16 group;
 189        kgid_t kgid;
 190
 191        for (i = 0; i < group_info->ngroups; i++) {
 192                kgid = GROUP_AT(group_info, i);
 193                group = (u16)from_kgid_munged(user_ns, kgid);
 194                if (put_user(group, grouplist+i))
 195                        return -EFAULT;
 196        }
 197
 198        return 0;
 199}
 200
 201static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
 202{
 203        struct user_namespace *user_ns = current_user_ns();
 204        int i;
 205        u16 group;
 206        kgid_t kgid;
 207
 208        for (i = 0; i < group_info->ngroups; i++) {
 209                if (get_user(group, grouplist+i))
 210                        return  -EFAULT;
 211
 212                kgid = make_kgid(user_ns, (gid_t)group);
 213                if (!gid_valid(kgid))
 214                        return -EINVAL;
 215
 216                GROUP_AT(group_info, i) = kgid;
 217        }
 218
 219        return 0;
 220}
 221
 222asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
 223{
 224        int i;
 225
 226        if (gidsetsize < 0)
 227                return -EINVAL;
 228
 229        get_group_info(current->cred->group_info);
 230        i = current->cred->group_info->ngroups;
 231        if (gidsetsize) {
 232                if (i > gidsetsize) {
 233                        i = -EINVAL;
 234                        goto out;
 235                }
 236                if (groups16_to_user(grouplist, current->cred->group_info)) {
 237                        i = -EFAULT;
 238                        goto out;
 239                }
 240        }
 241out:
 242        put_group_info(current->cred->group_info);
 243        return i;
 244}
 245
 246asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
 247{
 248        struct group_info *group_info;
 249        int retval;
 250
 251        if (!capable(CAP_SETGID))
 252                return -EPERM;
 253        if ((unsigned)gidsetsize > NGROUPS_MAX)
 254                return -EINVAL;
 255
 256        group_info = groups_alloc(gidsetsize);
 257        if (!group_info)
 258                return -ENOMEM;
 259        retval = groups16_from_user(group_info, grouplist);
 260        if (retval) {
 261                put_group_info(group_info);
 262                return retval;
 263        }
 264
 265        retval = set_current_groups(group_info);
 266        put_group_info(group_info);
 267
 268        return retval;
 269}
 270
 271asmlinkage long sys32_getuid16(void)
 272{
 273        return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
 274}
 275
 276asmlinkage long sys32_geteuid16(void)
 277{
 278        return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
 279}
 280
 281asmlinkage long sys32_getgid16(void)
 282{
 283        return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
 284}
 285
 286asmlinkage long sys32_getegid16(void)
 287{
 288        return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
 289}
 290
 291#ifdef CONFIG_SYSVIPC
 292COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second,
 293                unsigned long, third, compat_uptr_t, ptr)
 294{
 295        if (call >> 16)         /* hack for backward compatibility */
 296                return -EINVAL;
 297        return compat_sys_ipc(call, first, second, third, ptr, third);
 298}
 299#endif
 300
 301asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
 302{
 303        if ((int)high < 0)
 304                return -EINVAL;
 305        else
 306                return sys_truncate(path, (high << 32) | low);
 307}
 308
 309asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
 310{
 311        if ((int)high < 0)
 312                return -EINVAL;
 313        else
 314                return sys_ftruncate(fd, (high << 32) | low);
 315}
 316
 317asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
 318                                size_t count, u32 poshi, u32 poslo)
 319{
 320        if ((compat_ssize_t) count < 0)
 321                return -EINVAL;
 322        return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 323}
 324
 325asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
 326                                size_t count, u32 poshi, u32 poslo)
 327{
 328        if ((compat_ssize_t) count < 0)
 329                return -EINVAL;
 330        return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 331}
 332
 333asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
 334{
 335        return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
 336}
 337
 338struct stat64_emu31 {
 339        unsigned long long  st_dev;
 340        unsigned int    __pad1;
 341#define STAT64_HAS_BROKEN_ST_INO        1
 342        u32             __st_ino;
 343        unsigned int    st_mode;
 344        unsigned int    st_nlink;
 345        u32             st_uid;
 346        u32             st_gid;
 347        unsigned long long  st_rdev;
 348        unsigned int    __pad3;
 349        long            st_size;
 350        u32             st_blksize;
 351        unsigned char   __pad4[4];
 352        u32             __pad5;     /* future possible st_blocks high bits */
 353        u32             st_blocks;  /* Number 512-byte blocks allocated. */
 354        u32             st_atime;
 355        u32             __pad6;
 356        u32             st_mtime;
 357        u32             __pad7;
 358        u32             st_ctime;
 359        u32             __pad8;     /* will be high 32 bits of ctime someday */
 360        unsigned long   st_ino;
 361};      
 362
 363static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
 364{
 365        struct stat64_emu31 tmp;
 366
 367        memset(&tmp, 0, sizeof(tmp));
 368
 369        tmp.st_dev = huge_encode_dev(stat->dev);
 370        tmp.st_ino = stat->ino;
 371        tmp.__st_ino = (u32)stat->ino;
 372        tmp.st_mode = stat->mode;
 373        tmp.st_nlink = (unsigned int)stat->nlink;
 374        tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
 375        tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
 376        tmp.st_rdev = huge_encode_dev(stat->rdev);
 377        tmp.st_size = stat->size;
 378        tmp.st_blksize = (u32)stat->blksize;
 379        tmp.st_blocks = (u32)stat->blocks;
 380        tmp.st_atime = (u32)stat->atime.tv_sec;
 381        tmp.st_mtime = (u32)stat->mtime.tv_sec;
 382        tmp.st_ctime = (u32)stat->ctime.tv_sec;
 383
 384        return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 
 385}
 386
 387asmlinkage long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
 388{
 389        struct kstat stat;
 390        int ret = vfs_stat(filename, &stat);
 391        if (!ret)
 392                ret = cp_stat64(statbuf, &stat);
 393        return ret;
 394}
 395
 396asmlinkage long sys32_lstat64(const char __user * filename, struct stat64_emu31 __user * statbuf)
 397{
 398        struct kstat stat;
 399        int ret = vfs_lstat(filename, &stat);
 400        if (!ret)
 401                ret = cp_stat64(statbuf, &stat);
 402        return ret;
 403}
 404
 405asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf)
 406{
 407        struct kstat stat;
 408        int ret = vfs_fstat(fd, &stat);
 409        if (!ret)
 410                ret = cp_stat64(statbuf, &stat);
 411        return ret;
 412}
 413
 414asmlinkage long sys32_fstatat64(unsigned int dfd, const char __user *filename,
 415                                struct stat64_emu31 __user* statbuf, int flag)
 416{
 417        struct kstat stat;
 418        int error;
 419
 420        error = vfs_fstatat(dfd, filename, &stat, flag);
 421        if (error)
 422                return error;
 423        return cp_stat64(statbuf, &stat);
 424}
 425
 426/*
 427 * Linux/i386 didn't use to be able to handle more than
 428 * 4 system call parameters, so these system calls used a memory
 429 * block for parameter passing..
 430 */
 431
 432struct mmap_arg_struct_emu31 {
 433        compat_ulong_t addr;
 434        compat_ulong_t len;
 435        compat_ulong_t prot;
 436        compat_ulong_t flags;
 437        compat_ulong_t fd;
 438        compat_ulong_t offset;
 439};
 440
 441asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
 442{
 443        struct mmap_arg_struct_emu31 a;
 444
 445        if (copy_from_user(&a, arg, sizeof(a)))
 446                return -EFAULT;
 447        if (a.offset & ~PAGE_MASK)
 448                return -EINVAL;
 449        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
 450                              a.offset >> PAGE_SHIFT);
 451}
 452
 453asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
 454{
 455        struct mmap_arg_struct_emu31 a;
 456
 457        if (copy_from_user(&a, arg, sizeof(a)))
 458                return -EFAULT;
 459        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 460}
 461
 462asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
 463{
 464        if ((compat_ssize_t) count < 0)
 465                return -EINVAL; 
 466
 467        return sys_read(fd, buf, count);
 468}
 469
 470asmlinkage long sys32_write(unsigned int fd, const char __user * buf, size_t count)
 471{
 472        if ((compat_ssize_t) count < 0)
 473                return -EINVAL; 
 474
 475        return sys_write(fd, buf, count);
 476}
 477
 478/*
 479 * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64.
 480 * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE}
 481 * because the 31 bit values differ from the 64 bit values.
 482 */
 483
 484asmlinkage long
 485sys32_fadvise64(int fd, loff_t offset, size_t len, int advise)
 486{
 487        if (advise == 4)
 488                advise = POSIX_FADV_DONTNEED;
 489        else if (advise == 5)
 490                advise = POSIX_FADV_NOREUSE;
 491        return sys_fadvise64(fd, offset, len, advise);
 492}
 493
 494struct fadvise64_64_args {
 495        int fd;
 496        long long offset;
 497        long long len;
 498        int advice;
 499};
 500
 501asmlinkage long
 502sys32_fadvise64_64(struct fadvise64_64_args __user *args)
 503{
 504        struct fadvise64_64_args a;
 505
 506        if ( copy_from_user(&a, args, sizeof(a)) )
 507                return -EFAULT;
 508        if (a.advice == 4)
 509                a.advice = POSIX_FADV_DONTNEED;
 510        else if (a.advice == 5)
 511                a.advice = POSIX_FADV_NOREUSE;
 512        return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
 513}
 514