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
  61/* For this source file, we want overflow handling. */
  62
  63#undef high2lowuid
  64#undef high2lowgid
  65#undef low2highuid
  66#undef low2highgid
  67#undef SET_UID16
  68#undef SET_GID16
  69#undef NEW_TO_OLD_UID
  70#undef NEW_TO_OLD_GID
  71#undef SET_OLDSTAT_UID
  72#undef SET_OLDSTAT_GID
  73#undef SET_STAT_UID
  74#undef SET_STAT_GID
  75
  76#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
  77#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
  78#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
  79#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
  80#define SET_UID16(var, uid)     var = high2lowuid(uid)
  81#define SET_GID16(var, gid)     var = high2lowgid(gid)
  82#define NEW_TO_OLD_UID(uid)     high2lowuid(uid)
  83#define NEW_TO_OLD_GID(gid)     high2lowgid(gid)
  84#define SET_OLDSTAT_UID(stat, uid)      (stat).st_uid = high2lowuid(uid)
  85#define SET_OLDSTAT_GID(stat, gid)      (stat).st_gid = high2lowgid(gid)
  86#define SET_STAT_UID(stat, uid)         (stat).st_uid = high2lowuid(uid)
  87#define SET_STAT_GID(stat, gid)         (stat).st_gid = high2lowgid(gid)
  88
  89COMPAT_SYSCALL_DEFINE3(s390_chown16, const char __user *, filename,
  90                       u16, user, u16, group)
  91{
  92        return sys_chown(filename, low2highuid(user), low2highgid(group));
  93}
  94
  95COMPAT_SYSCALL_DEFINE3(s390_lchown16, const char __user *,
  96                       filename, u16, user, u16, group)
  97{
  98        return sys_lchown(filename, low2highuid(user), low2highgid(group));
  99}
 100
 101COMPAT_SYSCALL_DEFINE3(s390_fchown16, unsigned int, fd, u16, user, u16, group)
 102{
 103        return sys_fchown(fd, low2highuid(user), low2highgid(group));
 104}
 105
 106COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid)
 107{
 108        return sys_setregid(low2highgid(rgid), low2highgid(egid));
 109}
 110
 111COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid)
 112{
 113        return sys_setgid((gid_t)gid);
 114}
 115
 116COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid)
 117{
 118        return sys_setreuid(low2highuid(ruid), low2highuid(euid));
 119}
 120
 121COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid)
 122{
 123        return sys_setuid((uid_t)uid);
 124}
 125
 126COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid)
 127{
 128        return sys_setresuid(low2highuid(ruid), low2highuid(euid),
 129                             low2highuid(suid));
 130}
 131
 132COMPAT_SYSCALL_DEFINE3(s390_getresuid16, u16 __user *, ruidp,
 133                       u16 __user *, euidp, u16 __user *, suidp)
 134{
 135        const struct cred *cred = current_cred();
 136        int retval;
 137        u16 ruid, euid, suid;
 138
 139        ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid));
 140        euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid));
 141        suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid));
 142
 143        if (!(retval   = put_user(ruid, ruidp)) &&
 144            !(retval   = put_user(euid, euidp)))
 145                retval = put_user(suid, suidp);
 146
 147        return retval;
 148}
 149
 150COMPAT_SYSCALL_DEFINE3(s390_setresgid16, u16, rgid, u16, egid, u16, sgid)
 151{
 152        return sys_setresgid(low2highgid(rgid), low2highgid(egid),
 153                             low2highgid(sgid));
 154}
 155
 156COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp,
 157                       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
 174COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid)
 175{
 176        return sys_setfsuid((uid_t)uid);
 177}
 178
 179COMPAT_SYSCALL_DEFINE1(s390_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
 222COMPAT_SYSCALL_DEFINE2(s390_getgroups16, int, gidsetsize, u16 __user *, grouplist)
 223{
 224        const struct cred *cred = current_cred();
 225        int i;
 226
 227        if (gidsetsize < 0)
 228                return -EINVAL;
 229
 230        get_group_info(cred->group_info);
 231        i = cred->group_info->ngroups;
 232        if (gidsetsize) {
 233                if (i > gidsetsize) {
 234                        i = -EINVAL;
 235                        goto out;
 236                }
 237                if (groups16_to_user(grouplist, cred->group_info)) {
 238                        i = -EFAULT;
 239                        goto out;
 240                }
 241        }
 242out:
 243        put_group_info(cred->group_info);
 244        return i;
 245}
 246
 247COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplist)
 248{
 249        struct group_info *group_info;
 250        int retval;
 251
 252        if (!may_setgroups())
 253                return -EPERM;
 254        if ((unsigned)gidsetsize > NGROUPS_MAX)
 255                return -EINVAL;
 256
 257        group_info = groups_alloc(gidsetsize);
 258        if (!group_info)
 259                return -ENOMEM;
 260        retval = groups16_from_user(group_info, grouplist);
 261        if (retval) {
 262                put_group_info(group_info);
 263                return retval;
 264        }
 265
 266        retval = set_current_groups(group_info);
 267        put_group_info(group_info);
 268
 269        return retval;
 270}
 271
 272COMPAT_SYSCALL_DEFINE0(s390_getuid16)
 273{
 274        return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
 275}
 276
 277COMPAT_SYSCALL_DEFINE0(s390_geteuid16)
 278{
 279        return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
 280}
 281
 282COMPAT_SYSCALL_DEFINE0(s390_getgid16)
 283{
 284        return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
 285}
 286
 287COMPAT_SYSCALL_DEFINE0(s390_getegid16)
 288{
 289        return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
 290}
 291
 292#ifdef CONFIG_SYSVIPC
 293COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second,
 294                compat_ulong_t, third, compat_uptr_t, ptr)
 295{
 296        if (call >> 16)         /* hack for backward compatibility */
 297                return -EINVAL;
 298        return compat_sys_ipc(call, first, second, third, ptr, third);
 299}
 300#endif
 301
 302COMPAT_SYSCALL_DEFINE3(s390_truncate64, const char __user *, path, u32, high, u32, low)
 303{
 304        return sys_truncate(path, (unsigned long)high << 32 | low);
 305}
 306
 307COMPAT_SYSCALL_DEFINE3(s390_ftruncate64, unsigned int, fd, u32, high, u32, low)
 308{
 309        return sys_ftruncate(fd, (unsigned long)high << 32 | low);
 310}
 311
 312COMPAT_SYSCALL_DEFINE5(s390_pread64, unsigned int, fd, char __user *, ubuf,
 313                       compat_size_t, count, u32, high, u32, low)
 314{
 315        if ((compat_ssize_t) count < 0)
 316                return -EINVAL;
 317        return sys_pread64(fd, ubuf, count, (unsigned long)high << 32 | low);
 318}
 319
 320COMPAT_SYSCALL_DEFINE5(s390_pwrite64, unsigned int, fd, const char __user *, ubuf,
 321                       compat_size_t, count, u32, high, u32, low)
 322{
 323        if ((compat_ssize_t) count < 0)
 324                return -EINVAL;
 325        return sys_pwrite64(fd, ubuf, count, (unsigned long)high << 32 | low);
 326}
 327
 328COMPAT_SYSCALL_DEFINE4(s390_readahead, int, fd, u32, high, u32, low, s32, count)
 329{
 330        return sys_readahead(fd, (unsigned long)high << 32 | low, count);
 331}
 332
 333struct stat64_emu31 {
 334        unsigned long long  st_dev;
 335        unsigned int    __pad1;
 336#define STAT64_HAS_BROKEN_ST_INO        1
 337        u32             __st_ino;
 338        unsigned int    st_mode;
 339        unsigned int    st_nlink;
 340        u32             st_uid;
 341        u32             st_gid;
 342        unsigned long long  st_rdev;
 343        unsigned int    __pad3;
 344        long            st_size;
 345        u32             st_blksize;
 346        unsigned char   __pad4[4];
 347        u32             __pad5;     /* future possible st_blocks high bits */
 348        u32             st_blocks;  /* Number 512-byte blocks allocated. */
 349        u32             st_atime;
 350        u32             __pad6;
 351        u32             st_mtime;
 352        u32             __pad7;
 353        u32             st_ctime;
 354        u32             __pad8;     /* will be high 32 bits of ctime someday */
 355        unsigned long   st_ino;
 356};      
 357
 358static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
 359{
 360        struct stat64_emu31 tmp;
 361
 362        memset(&tmp, 0, sizeof(tmp));
 363
 364        tmp.st_dev = huge_encode_dev(stat->dev);
 365        tmp.st_ino = stat->ino;
 366        tmp.__st_ino = (u32)stat->ino;
 367        tmp.st_mode = stat->mode;
 368        tmp.st_nlink = (unsigned int)stat->nlink;
 369        tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
 370        tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
 371        tmp.st_rdev = huge_encode_dev(stat->rdev);
 372        tmp.st_size = stat->size;
 373        tmp.st_blksize = (u32)stat->blksize;
 374        tmp.st_blocks = (u32)stat->blocks;
 375        tmp.st_atime = (u32)stat->atime.tv_sec;
 376        tmp.st_mtime = (u32)stat->mtime.tv_sec;
 377        tmp.st_ctime = (u32)stat->ctime.tv_sec;
 378
 379        return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 
 380}
 381
 382COMPAT_SYSCALL_DEFINE2(s390_stat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
 383{
 384        struct kstat stat;
 385        int ret = vfs_stat(filename, &stat);
 386        if (!ret)
 387                ret = cp_stat64(statbuf, &stat);
 388        return ret;
 389}
 390
 391COMPAT_SYSCALL_DEFINE2(s390_lstat64, const char __user *, filename, struct stat64_emu31 __user *, statbuf)
 392{
 393        struct kstat stat;
 394        int ret = vfs_lstat(filename, &stat);
 395        if (!ret)
 396                ret = cp_stat64(statbuf, &stat);
 397        return ret;
 398}
 399
 400COMPAT_SYSCALL_DEFINE2(s390_fstat64, unsigned int, fd, struct stat64_emu31 __user *, statbuf)
 401{
 402        struct kstat stat;
 403        int ret = vfs_fstat(fd, &stat);
 404        if (!ret)
 405                ret = cp_stat64(statbuf, &stat);
 406        return ret;
 407}
 408
 409COMPAT_SYSCALL_DEFINE4(s390_fstatat64, unsigned int, dfd, const char __user *, filename,
 410                       struct stat64_emu31 __user *, statbuf, int, flag)
 411{
 412        struct kstat stat;
 413        int error;
 414
 415        error = vfs_fstatat(dfd, filename, &stat, flag);
 416        if (error)
 417                return error;
 418        return cp_stat64(statbuf, &stat);
 419}
 420
 421/*
 422 * Linux/i386 didn't use to be able to handle more than
 423 * 4 system call parameters, so these system calls used a memory
 424 * block for parameter passing..
 425 */
 426
 427struct mmap_arg_struct_emu31 {
 428        compat_ulong_t addr;
 429        compat_ulong_t len;
 430        compat_ulong_t prot;
 431        compat_ulong_t flags;
 432        compat_ulong_t fd;
 433        compat_ulong_t offset;
 434};
 435
 436COMPAT_SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct_emu31 __user *, arg)
 437{
 438        struct mmap_arg_struct_emu31 a;
 439
 440        if (copy_from_user(&a, arg, sizeof(a)))
 441                return -EFAULT;
 442        if (a.offset & ~PAGE_MASK)
 443                return -EINVAL;
 444        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
 445                              a.offset >> PAGE_SHIFT);
 446}
 447
 448COMPAT_SYSCALL_DEFINE1(s390_mmap2, struct mmap_arg_struct_emu31 __user *, arg)
 449{
 450        struct mmap_arg_struct_emu31 a;
 451
 452        if (copy_from_user(&a, arg, sizeof(a)))
 453                return -EFAULT;
 454        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 455}
 456
 457COMPAT_SYSCALL_DEFINE3(s390_read, unsigned int, fd, char __user *, buf, compat_size_t, count)
 458{
 459        if ((compat_ssize_t) count < 0)
 460                return -EINVAL; 
 461
 462        return sys_read(fd, buf, count);
 463}
 464
 465COMPAT_SYSCALL_DEFINE3(s390_write, unsigned int, fd, const char __user *, buf, compat_size_t, count)
 466{
 467        if ((compat_ssize_t) count < 0)
 468                return -EINVAL; 
 469
 470        return sys_write(fd, buf, count);
 471}
 472
 473/*
 474 * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64.
 475 * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE}
 476 * because the 31 bit values differ from the 64 bit values.
 477 */
 478
 479COMPAT_SYSCALL_DEFINE5(s390_fadvise64, int, fd, u32, high, u32, low, compat_size_t, len, int, advise)
 480{
 481        if (advise == 4)
 482                advise = POSIX_FADV_DONTNEED;
 483        else if (advise == 5)
 484                advise = POSIX_FADV_NOREUSE;
 485        return sys_fadvise64(fd, (unsigned long)high << 32 | low, len, advise);
 486}
 487
 488struct fadvise64_64_args {
 489        int fd;
 490        long long offset;
 491        long long len;
 492        int advice;
 493};
 494
 495COMPAT_SYSCALL_DEFINE1(s390_fadvise64_64, struct fadvise64_64_args __user *, args)
 496{
 497        struct fadvise64_64_args a;
 498
 499        if ( copy_from_user(&a, args, sizeof(a)) )
 500                return -EFAULT;
 501        if (a.advice == 4)
 502                a.advice = POSIX_FADV_DONTNEED;
 503        else if (a.advice == 5)
 504                a.advice = POSIX_FADV_NOREUSE;
 505        return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
 506}
 507
 508COMPAT_SYSCALL_DEFINE6(s390_sync_file_range, int, fd, u32, offhigh, u32, offlow,
 509                       u32, nhigh, u32, nlow, unsigned int, flags)
 510{
 511        return sys_sync_file_range(fd, ((loff_t)offhigh << 32) + offlow,
 512                                   ((u64)nhigh << 32) + nlow, flags);
 513}
 514
 515COMPAT_SYSCALL_DEFINE6(s390_fallocate, int, fd, int, mode, u32, offhigh, u32, offlow,
 516                       u32, lenhigh, u32, lenlow)
 517{
 518        return sys_fallocate(fd, mode, ((loff_t)offhigh << 32) + offlow,
 519                             ((u64)lenhigh << 32) + lenlow);
 520}
 521