1/* $Id: sys_sparc32.c,v 1.1.1.1 2007/08/03 18:52:18 Exp $ 2 * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. 3 * 4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 5 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 6 * 7 * These routines maintain argument size conversion between 32bit and 64bit 8 * environment. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/sched.h> 13#include <linux/capability.h> 14#include <linux/fs.h> 15#include <linux/mm.h> 16#include <linux/file.h> 17#include <linux/signal.h> 18#include <linux/resource.h> 19#include <linux/times.h> 20#include <linux/utsname.h> 21#include <linux/smp.h> 22#include <linux/smp_lock.h> 23#include <linux/sem.h> 24#include <linux/msg.h> 25#include <linux/shm.h> 26#include <linux/slab.h> 27#include <linux/uio.h> 28#include <linux/nfs_fs.h> 29#include <linux/quota.h> 30#include <linux/module.h> 31#include <linux/sunrpc/svc.h> 32#include <linux/nfsd/nfsd.h> 33#include <linux/nfsd/cache.h> 34#include <linux/nfsd/xdr.h> 35#include <linux/nfsd/syscall.h> 36#include <linux/poll.h> 37#include <linux/personality.h> 38#include <linux/stat.h> 39#include <linux/filter.h> 40#include <linux/highmem.h> 41#include <linux/highuid.h> 42#include <linux/mman.h> 43#include <linux/ipv6.h> 44#include <linux/in.h> 45#include <linux/icmpv6.h> 46#include <linux/syscalls.h> 47#include <linux/sysctl.h> 48#include <linux/binfmts.h> 49#include <linux/dnotify.h> 50#include <linux/security.h> 51#include <linux/compat.h> 52#include <linux/vfs.h> 53#include <linux/netfilter_ipv4/ip_tables.h> 54#include <linux/ptrace.h> 55#include <linux/highuid.h> 56 57#include <asm/types.h> 58#include <asm/ipc.h> 59#include <asm/uaccess.h> 60#include <asm/fpumacro.h> 61#include <asm/semaphore.h> 62#include <asm/mmu_context.h> 63#include <asm/a.out.h> 64#include <asm/compat_signal.h> 65 66asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group) 67{ 68 return sys_chown(filename, low2highuid(user), low2highgid(group)); 69} 70 71asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group) 72{ 73 return sys_lchown(filename, low2highuid(user), low2highgid(group)); 74} 75 76asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group) 77{ 78 return sys_fchown(fd, low2highuid(user), low2highgid(group)); 79} 80 81asmlinkage long sys32_setregid16(u16 rgid, u16 egid) 82{ 83 return sys_setregid(low2highgid(rgid), low2highgid(egid)); 84} 85 86asmlinkage long sys32_setgid16(u16 gid) 87{ 88 return sys_setgid((gid_t)gid); 89} 90 91asmlinkage long sys32_setreuid16(u16 ruid, u16 euid) 92{ 93 return sys_setreuid(low2highuid(ruid), low2highuid(euid)); 94} 95 96asmlinkage long sys32_setuid16(u16 uid) 97{ 98 return sys_setuid((uid_t)uid); 99} 100 101asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid) 102{ 103 return sys_setresuid(low2highuid(ruid), low2highuid(euid), 104 low2highuid(suid)); 105} 106 107asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid) 108{ 109 int retval; 110 111 if (!(retval = put_user(high2lowuid(current->uid), ruid)) && 112 !(retval = put_user(high2lowuid(current->euid), euid))) 113 retval = put_user(high2lowuid(current->suid), suid); 114 115 return retval; 116} 117 118asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid) 119{ 120 return sys_setresgid(low2highgid(rgid), low2highgid(egid), 121 low2highgid(sgid)); 122} 123 124asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid) 125{ 126 int retval; 127 128 if (!(retval = put_user(high2lowgid(current->gid), rgid)) && 129 !(retval = put_user(high2lowgid(current->egid), egid))) 130 retval = put_user(high2lowgid(current->sgid), sgid); 131 132 return retval; 133} 134 135asmlinkage long sys32_setfsuid16(u16 uid) 136{ 137 return sys_setfsuid((uid_t)uid); 138} 139 140asmlinkage long sys32_setfsgid16(u16 gid) 141{ 142 return sys_setfsgid((gid_t)gid); 143} 144 145static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info) 146{ 147 int i; 148 u16 group; 149 150 for (i = 0; i < group_info->ngroups; i++) { 151 group = (u16)GROUP_AT(group_info, i); 152 if (put_user(group, grouplist+i)) 153 return -EFAULT; 154 } 155 156 return 0; 157} 158 159static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist) 160{ 161 int i; 162 u16 group; 163 164 for (i = 0; i < group_info->ngroups; i++) { 165 if (get_user(group, grouplist+i)) 166 return -EFAULT; 167 GROUP_AT(group_info, i) = (gid_t)group; 168 } 169 170 return 0; 171} 172 173asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist) 174{ 175 int i; 176 177 if (gidsetsize < 0) 178 return -EINVAL; 179 180 get_group_info(current->group_info); 181 i = current->group_info->ngroups; 182 if (gidsetsize) { 183 if (i > gidsetsize) { 184 i = -EINVAL; 185 goto out; 186 } 187 if (groups16_to_user(grouplist, current->group_info)) { 188 i = -EFAULT; 189 goto out; 190 } 191 } 192out: 193 put_group_info(current->group_info); 194 return i; 195} 196 197asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist) 198{ 199 struct group_info *group_info; 200 int retval; 201 202 if (!capable(CAP_SETGID)) 203 return -EPERM; 204 if ((unsigned)gidsetsize > NGROUPS_MAX) 205 return -EINVAL; 206 207 group_info = groups_alloc(gidsetsize); 208 if (!group_info) 209 return -ENOMEM; 210 retval = groups16_from_user(group_info, grouplist); 211 if (retval) { 212 put_group_info(group_info); 213 return retval; 214 } 215 216 retval = set_current_groups(group_info); 217 put_group_info(group_info); 218 219 return retval; 220} 221 222asmlinkage long sys32_getuid16(void) 223{ 224 return high2lowuid(current->uid); 225} 226 227asmlinkage long sys32_geteuid16(void) 228{ 229 return high2lowuid(current->euid); 230} 231 232asmlinkage long sys32_getgid16(void) 233{ 234 return high2lowgid(current->gid); 235} 236 237asmlinkage long sys32_getegid16(void) 238{ 239 return high2lowgid(current->egid); 240} 241 242/* 32-bit timeval and related flotsam. */ 243 244static long get_tv32(struct timeval *o, struct compat_timeval __user *i) 245{ 246 return (!access_ok(VERIFY_READ, i, sizeof(*i)) || 247 (__get_user(o->tv_sec, &i->tv_sec) | 248 __get_user(o->tv_usec, &i->tv_usec))); 249} 250 251static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i) 252{ 253 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || 254 (__put_user(i->tv_sec, &o->tv_sec) | 255 __put_user(i->tv_usec, &o->tv_usec))); 256} 257 258#ifdef CONFIG_SYSVIPC 259asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth) 260{ 261 int version; 262 263 version = call >> 16; /* hack for backward compatibility */ 264 call &= 0xffff; 265 266 switch (call) { 267 case SEMTIMEDOP: 268 if (fifth) 269 /* sign extend semid */ 270 return compat_sys_semtimedop((int)first, 271 compat_ptr(ptr), second, 272 compat_ptr(fifth)); 273 /* else fall through for normal semop() */ 274 case SEMOP: 275 /* struct sembuf is the same on 32 and 64bit :)) */ 276 /* sign extend semid */ 277 return sys_semtimedop((int)first, compat_ptr(ptr), second, 278 NULL); 279 case SEMGET: 280 /* sign extend key, nsems */ 281 return sys_semget((int)first, (int)second, third); 282 case SEMCTL: 283 /* sign extend semid, semnum */ 284 return compat_sys_semctl((int)first, (int)second, third, 285 compat_ptr(ptr)); 286 287 case MSGSND: 288 /* sign extend msqid */ 289 return compat_sys_msgsnd((int)first, (int)second, third, 290 compat_ptr(ptr)); 291 case MSGRCV: 292 /* sign extend msqid, msgtyp */ 293 return compat_sys_msgrcv((int)first, second, (int)fifth, 294 third, version, compat_ptr(ptr)); 295 case MSGGET: 296 /* sign extend key */ 297 return sys_msgget((int)first, second); 298 case MSGCTL: 299 /* sign extend msqid */ 300 return compat_sys_msgctl((int)first, second, compat_ptr(ptr)); 301 302 case SHMAT: 303 /* sign extend shmid */ 304 return compat_sys_shmat((int)first, second, third, version, 305 compat_ptr(ptr)); 306 case SHMDT: 307 return sys_shmdt(compat_ptr(ptr)); 308 case SHMGET: 309 /* sign extend key_t */ 310 return sys_shmget((int)first, second, third); 311 case SHMCTL: 312 /* sign extend shmid */ 313 return compat_sys_shmctl((int)first, second, compat_ptr(ptr)); 314 315 default: 316 return -ENOSYS; 317 }; 318 319 return -ENOSYS; 320} 321#endif 322 323asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low) 324{ 325 if ((int)high < 0) 326 return -EINVAL; 327 else 328 return sys_truncate(path, (high << 32) | low); 329} 330 331asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low) 332{ 333 if ((int)high < 0) 334 return -EINVAL; 335 else 336 return sys_ftruncate(fd, (high << 32) | low); 337} 338 339int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 340{ 341 compat_ino_t ino; 342 int err; 343 344 if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) || 345 !old_valid_dev(stat->rdev)) 346 return -EOVERFLOW; 347 348 ino = stat->ino; 349 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) 350 return -EOVERFLOW; 351 352 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); 353 err |= put_user(stat->ino, &statbuf->st_ino); 354 err |= put_user(stat->mode, &statbuf->st_mode); 355 err |= put_user(stat->nlink, &statbuf->st_nlink); 356 err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid); 357 err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid); 358 err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev); 359 err |= put_user(stat->size, &statbuf->st_size); 360 err |= put_user(stat->atime.tv_sec, &statbuf->st_atime); 361 err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec); 362 err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime); 363 err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec); 364 err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime); 365 err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec); 366 err |= put_user(stat->blksize, &statbuf->st_blksize); 367 err |= put_user(stat->blocks, &statbuf->st_blocks); 368 err |= put_user(0, &statbuf->__unused4[0]); 369 err |= put_user(0, &statbuf->__unused4[1]); 370 371 return err; 372} 373 374int cp_compat_stat64(struct kstat *stat, struct compat_stat64 __user *statbuf) 375{ 376 int err; 377 378 err = put_user(huge_encode_dev(stat->dev), &statbuf->st_dev); 379 err |= put_user(stat->ino, &statbuf->st_ino); 380 err |= put_user(stat->mode, &statbuf->st_mode); 381 err |= put_user(stat->nlink, &statbuf->st_nlink); 382 err |= put_user(stat->uid, &statbuf->st_uid); 383 err |= put_user(stat->gid, &statbuf->st_gid); 384 err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev); 385 err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]); 386 err |= put_user(stat->size, &statbuf->st_size); 387 err |= put_user(stat->blksize, &statbuf->st_blksize); 388 err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[0]); 389 err |= put_user(0, (unsigned int __user *) &statbuf->__pad4[4]); 390 err |= put_user(stat->blocks, &statbuf->st_blocks); 391 err |= put_user(stat->atime.tv_sec, &statbuf->st_atime); 392 err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec); 393 err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime); 394 err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec); 395 err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime); 396 err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec); 397 err |= put_user(0, &statbuf->__unused4); 398 err |= put_user(0, &statbuf->__unused5); 399 400 return err; 401} 402 403asmlinkage long compat_sys_stat64(char __user * filename, 404 struct compat_stat64 __user *statbuf) 405{ 406 struct kstat stat; 407 int error = vfs_stat(filename, &stat); 408 409 if (!error) 410 error = cp_compat_stat64(&stat, statbuf); 411 return error; 412} 413 414asmlinkage long compat_sys_lstat64(char __user * filename, 415 struct compat_stat64 __user *statbuf) 416{ 417 struct kstat stat; 418 int error = vfs_lstat(filename, &stat); 419 420 if (!error) 421 error = cp_compat_stat64(&stat, statbuf); 422 return error; 423} 424 425asmlinkage long compat_sys_fstat64(unsigned int fd, 426 struct compat_stat64 __user * statbuf) 427{ 428 struct kstat stat; 429 int error = vfs_fstat(fd, &stat); 430 431 if (!error) 432 error = cp_compat_stat64(&stat, statbuf); 433 return error; 434} 435 436asmlinkage long compat_sys_fstatat64(unsigned int dfd, char __user *filename, 437 struct compat_stat64 __user * statbuf, int flag) 438{ 439 struct kstat stat; 440 int error = -EINVAL; 441 442 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) 443 goto out; 444 445 if (flag & AT_SYMLINK_NOFOLLOW) 446 error = vfs_lstat_fd(dfd, filename, &stat); 447 else 448 error = vfs_stat_fd(dfd, filename, &stat); 449 450 if (!error) 451 error = cp_compat_stat64(&stat, statbuf); 452 453out: 454 return error; 455} 456 457asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2) 458{ 459 return sys_sysfs(option, arg1, arg2); 460} 461 462asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) 463{ 464 struct timespec t; 465 int ret; 466 mm_segment_t old_fs = get_fs (); 467 468 set_fs (KERNEL_DS); 469 ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t); 470 set_fs (old_fs); 471 if (put_compat_timespec(&t, interval)) 472 return -EFAULT; 473 return ret; 474} 475 476asmlinkage long compat_sys_rt_sigprocmask(int how, 477 compat_sigset_t __user *set, 478 compat_sigset_t __user *oset, 479 compat_size_t sigsetsize) 480{ 481 sigset_t s; 482 compat_sigset_t s32; 483 int ret; 484 mm_segment_t old_fs = get_fs(); 485 486 if (set) { 487 if (copy_from_user (&s32, set, sizeof(compat_sigset_t))) 488 return -EFAULT; 489 switch (_NSIG_WORDS) { 490 case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); 491 case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); 492 case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); 493 case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); 494 } 495 } 496 set_fs (KERNEL_DS); 497 ret = sys_rt_sigprocmask(how, 498 set ? (sigset_t __user *) &s : NULL, 499 oset ? (sigset_t __user *) &s : NULL, 500 sigsetsize); 501 set_fs (old_fs); 502 if (ret) return ret; 503 if (oset) { 504 switch (_NSIG_WORDS) { 505 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; 506 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; 507 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; 508 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; 509 } 510 if (copy_to_user (oset, &s32, sizeof(compat_sigset_t))) 511 return -EFAULT; 512 } 513 return 0; 514} 515 516asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, 517 compat_size_t sigsetsize) 518{ 519 sigset_t s; 520 compat_sigset_t s32; 521 int ret; 522 mm_segment_t old_fs = get_fs(); 523 524 set_fs (KERNEL_DS); 525 ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); 526 set_fs (old_fs); 527 if (!ret) { 528 switch (_NSIG_WORDS) { 529 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; 530 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; 531 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; 532 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; 533 } 534 if (copy_to_user (set, &s32, sizeof(compat_sigset_t))) 535 return -EFAULT; 536 } 537 return ret; 538} 539 540asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, 541 struct compat_siginfo __user *uinfo) 542{ 543 siginfo_t info; 544 int ret; 545 mm_segment_t old_fs = get_fs(); 546 547 if (copy_siginfo_from_user32(&info, uinfo)) 548 return -EFAULT; 549 550 set_fs (KERNEL_DS); 551 ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); 552 set_fs (old_fs); 553 return ret; 554} 555 556asmlinkage long compat_sys_sigaction(int sig, struct old_sigaction32 __user *act, 557 struct old_sigaction32 __user *oact) 558{ 559 struct k_sigaction new_ka, old_ka; 560 int ret; 561 562 if (sig < 0) { 563 set_thread_flag(TIF_NEWSIGNALS); 564 sig = -sig; 565 } 566 567 if (act) { 568 compat_old_sigset_t mask; 569 u32 u_handler, u_restorer; 570 571 ret = get_user(u_handler, &act->sa_handler); 572 new_ka.sa.sa_handler = compat_ptr(u_handler); 573 ret |= __get_user(u_restorer, &act->sa_restorer); 574 new_ka.sa.sa_restorer = compat_ptr(u_restorer); 575 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 576 ret |= __get_user(mask, &act->sa_mask); 577 if (ret) 578 return ret; 579 new_ka.ka_restorer = NULL; 580 siginitset(&new_ka.sa.sa_mask, mask); 581 } 582 583 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 584 585 if (!ret && oact) { 586 ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler); 587 ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer); 588 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 589 ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); 590 } 591 592 return ret; 593} 594 595asmlinkage long compat_sys_rt_sigaction(int sig, 596 struct sigaction32 __user *act, 597 struct sigaction32 __user *oact, 598 void __user *restorer, 599 compat_size_t sigsetsize) 600{ 601 struct k_sigaction new_ka, old_ka; 602 int ret; 603 compat_sigset_t set32; 604 605 if (sigsetsize != sizeof(compat_sigset_t)) 606 return -EINVAL; 607 608 /* All tasks which use RT signals (effectively) use 609 * new style signals. 610 */ 611 set_thread_flag(TIF_NEWSIGNALS); 612 613 if (act) { 614 u32 u_handler, u_restorer; 615 616 new_ka.ka_restorer = restorer; 617 ret = get_user(u_handler, &act->sa_handler); 618 new_ka.sa.sa_handler = compat_ptr(u_handler); 619 ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t)); 620 switch (_NSIG_WORDS) { 621 case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); 622 case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); 623 case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); 624 case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); 625 } 626 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 627 ret |= __get_user(u_restorer, &act->sa_restorer); 628 new_ka.sa.sa_restorer = compat_ptr(u_restorer); 629 if (ret) 630 return -EFAULT; 631 } 632 633 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 634 635 if (!ret && oact) { 636 switch (_NSIG_WORDS) { 637 case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3]; 638 case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2]; 639 case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1]; 640 case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0]; 641 } 642 ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler); 643 ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t)); 644 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 645 ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer); 646 if (ret) 647 ret = -EFAULT; 648 } 649 650 return ret; 651} 652 653/* 654 * sparc32_execve() executes a new program after the asm stub has set 655 * things up for us. This should basically do what I want it to. 656 */ 657asmlinkage long sparc32_execve(struct pt_regs *regs) 658{ 659 int error, base = 0; 660 char *filename; 661 662 /* User register window flush is done by entry.S */ 663 664 /* Check for indirect call. */ 665 if ((u32)regs->u_regs[UREG_G1] == 0) 666 base = 1; 667 668 filename = getname(compat_ptr(regs->u_regs[base + UREG_I0])); 669 error = PTR_ERR(filename); 670 if (IS_ERR(filename)) 671 goto out; 672 673 error = compat_do_execve(filename, 674 compat_ptr(regs->u_regs[base + UREG_I1]), 675 compat_ptr(regs->u_regs[base + UREG_I2]), regs); 676 677 putname(filename); 678 679 if (!error) { 680 fprs_write(0); 681 current_thread_info()->xfsr[0] = 0; 682 current_thread_info()->fpsaved[0] = 0; 683 regs->tstate &= ~TSTATE_PEF; 684 task_lock(current); 685 current->ptrace &= ~PT_DTRACE; 686 task_unlock(current); 687 } 688out: 689 return error; 690} 691 692#ifdef CONFIG_MODULES 693 694asmlinkage long sys32_init_module(void __user *umod, u32 len, 695 const char __user *uargs) 696{ 697 return sys_init_module(umod, len, uargs); 698} 699 700asmlinkage long sys32_delete_module(const char __user *name_user, 701 unsigned int flags) 702{ 703 return sys_delete_module(name_user, flags); 704} 705 706#else /* CONFIG_MODULES */ 707 708asmlinkage long sys32_init_module(const char __user *name_user, 709 struct module __user *mod_user) 710{ 711 return -ENOSYS; 712} 713 714asmlinkage long sys32_delete_module(const char __user *name_user) 715{ 716 return -ENOSYS; 717} 718 719#endif /* CONFIG_MODULES */ 720 721/* Translations due to time_t size differences. Which affects all 722 sorts of things, like timeval and itimerval. */ 723 724extern struct timezone sys_tz; 725 726asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, 727 struct timezone __user *tz) 728{ 729 if (tv) { 730 struct timeval ktv; 731 do_gettimeofday(&ktv); 732 if (put_tv32(tv, &ktv)) 733 return -EFAULT; 734 } 735 if (tz) { 736 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) 737 return -EFAULT; 738 } 739 return 0; 740} 741 742static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) 743{ 744 long usec; 745 746 if (!access_ok(VERIFY_READ, i, sizeof(*i))) 747 return -EFAULT; 748 if (__get_user(o->tv_sec, &i->tv_sec)) 749 return -EFAULT; 750 if (__get_user(usec, &i->tv_usec)) 751 return -EFAULT; 752 o->tv_nsec = usec * 1000; 753 return 0; 754} 755 756asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, 757 struct timezone __user *tz) 758{ 759 struct timespec kts; 760 struct timezone ktz; 761 762 if (tv) { 763 if (get_ts32(&kts, tv)) 764 return -EFAULT; 765 } 766 if (tz) { 767 if (copy_from_user(&ktz, tz, sizeof(ktz))) 768 return -EFAULT; 769 } 770 771 return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); 772} 773 774asmlinkage long sys32_utimes(char __user *filename, 775 struct compat_timeval __user *tvs) 776{ 777 struct timespec tv[2]; 778 779 if (tvs) { 780 struct timeval ktvs[2]; 781 if (get_tv32(&ktvs[0], tvs) || 782 get_tv32(&ktvs[1], 1+tvs)) 783 return -EFAULT; 784 785 if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 || 786 ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000) 787 return -EINVAL; 788 789 tv[0].tv_sec = ktvs[0].tv_sec; 790 tv[0].tv_nsec = 1000 * ktvs[0].tv_usec; 791 tv[1].tv_sec = ktvs[1].tv_sec; 792 tv[1].tv_nsec = 1000 * ktvs[1].tv_usec; 793 } 794 795 return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0); 796} 797 798/* These are here just in case some old sparc32 binary calls it. */ 799asmlinkage long sys32_pause(void) 800{ 801 current->state = TASK_INTERRUPTIBLE; 802 schedule(); 803 return -ERESTARTNOHAND; 804} 805 806asmlinkage compat_ssize_t sys32_pread64(unsigned int fd, 807 char __user *ubuf, 808 compat_size_t count, 809 unsigned long poshi, 810 unsigned long poslo) 811{ 812 return sys_pread64(fd, ubuf, count, (poshi << 32) | poslo); 813} 814 815asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd, 816 char __user *ubuf, 817 compat_size_t count, 818 unsigned long poshi, 819 unsigned long poslo) 820{ 821 return sys_pwrite64(fd, ubuf, count, (poshi << 32) | poslo); 822} 823 824asmlinkage long compat_sys_readahead(int fd, 825 unsigned long offhi, 826 unsigned long offlo, 827 compat_size_t count) 828{ 829 return sys_readahead(fd, (offhi << 32) | offlo, count); 830} 831 832long compat_sys_fadvise64(int fd, 833 unsigned long offhi, 834 unsigned long offlo, 835 compat_size_t len, int advice) 836{ 837 return sys_fadvise64_64(fd, (offhi << 32) | offlo, len, advice); 838} 839 840long compat_sys_fadvise64_64(int fd, 841 unsigned long offhi, unsigned long offlo, 842 unsigned long lenhi, unsigned long lenlo, 843 int advice) 844{ 845 return sys_fadvise64_64(fd, 846 (offhi << 32) | offlo, 847 (lenhi << 32) | lenlo, 848 advice); 849} 850 851asmlinkage long compat_sys_sendfile(int out_fd, int in_fd, 852 compat_off_t __user *offset, 853 compat_size_t count) 854{ 855 mm_segment_t old_fs = get_fs(); 856 int ret; 857 off_t of; 858 859 if (offset && get_user(of, offset)) 860 return -EFAULT; 861 862 set_fs(KERNEL_DS); 863 ret = sys_sendfile(out_fd, in_fd, 864 offset ? (off_t __user *) &of : NULL, 865 count); 866 set_fs(old_fs); 867 868 if (offset && put_user(of, offset)) 869 return -EFAULT; 870 871 return ret; 872} 873 874asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd, 875 compat_loff_t __user *offset, 876 compat_size_t count) 877{ 878 mm_segment_t old_fs = get_fs(); 879 int ret; 880 loff_t lof; 881 882 if (offset && get_user(lof, offset)) 883 return -EFAULT; 884 885 set_fs(KERNEL_DS); 886 ret = sys_sendfile64(out_fd, in_fd, 887 offset ? (loff_t __user *) &lof : NULL, 888 count); 889 set_fs(old_fs); 890 891 if (offset && put_user(lof, offset)) 892 return -EFAULT; 893 894 return ret; 895} 896 897/* This is just a version for 32-bit applications which does 898 * not force O_LARGEFILE on. 899 */ 900 901asmlinkage long sparc32_open(const char __user *filename, 902 int flags, int mode) 903{ 904 return do_sys_open(AT_FDCWD, filename, flags, mode); 905} 906 907extern unsigned long do_mremap(unsigned long addr, 908 unsigned long old_len, unsigned long new_len, 909 unsigned long flags, unsigned long new_addr); 910 911asmlinkage unsigned long sys32_mremap(unsigned long addr, 912 unsigned long old_len, unsigned long new_len, 913 unsigned long flags, u32 __new_addr) 914{ 915 struct vm_area_struct *vma; 916 unsigned long ret = -EINVAL; 917 unsigned long new_addr = __new_addr; 918 919 if (old_len > STACK_TOP32 || new_len > STACK_TOP32) 920 goto out; 921 if (addr > STACK_TOP32 - old_len) 922 goto out; 923 down_write(¤t->mm->mmap_sem); 924 if (flags & MREMAP_FIXED) { 925 if (new_addr > STACK_TOP32 - new_len) 926 goto out_sem; 927 } else if (addr > STACK_TOP32 - new_len) { 928 unsigned long map_flags = 0; 929 struct file *file = NULL; 930 931 ret = -ENOMEM; 932 if (!(flags & MREMAP_MAYMOVE)) 933 goto out_sem; 934 935 vma = find_vma(current->mm, addr); 936 if (vma) { 937 if (vma->vm_flags & VM_SHARED) 938 map_flags |= MAP_SHARED; 939 file = vma->vm_file; 940 } 941 942 /* MREMAP_FIXED checked above. */ 943 new_addr = get_unmapped_area(file, addr, new_len, 944 vma ? vma->vm_pgoff : 0, 945 map_flags); 946 ret = new_addr; 947 if (new_addr & ~PAGE_MASK) 948 goto out_sem; 949 flags |= MREMAP_FIXED; 950 } 951 ret = do_mremap(addr, old_len, new_len, flags, new_addr); 952out_sem: 953 up_write(¤t->mm->mmap_sem); 954out: 955 return ret; 956} 957 958struct __sysctl_args32 { 959 u32 name; 960 int nlen; 961 u32 oldval; 962 u32 oldlenp; 963 u32 newval; 964 u32 newlen; 965 u32 __unused[4]; 966}; 967 968asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) 969{ 970#ifndef CONFIG_SYSCTL_SYSCALL 971 return -ENOSYS; 972#else 973 struct __sysctl_args32 tmp; 974 int error; 975 size_t oldlen, __user *oldlenp = NULL; 976 unsigned long addr = (((unsigned long)&args->__unused[0]) + 7UL) & ~7UL; 977 978 if (copy_from_user(&tmp, args, sizeof(tmp))) 979 return -EFAULT; 980 981 if (tmp.oldval && tmp.oldlenp) { 982 /* Duh, this is ugly and might not work if sysctl_args 983 is in read-only memory, but do_sysctl does indirectly 984 a lot of uaccess in both directions and we'd have to 985 basically copy the whole sysctl.c here, and 986 glibc's __sysctl uses rw memory for the structure 987 anyway. */ 988 if (get_user(oldlen, (u32 __user *)(unsigned long)tmp.oldlenp) || 989 put_user(oldlen, (size_t __user *)addr)) 990 return -EFAULT; 991 oldlenp = (size_t __user *)addr; 992 } 993 994 lock_kernel(); 995 error = do_sysctl((int __user *)(unsigned long) tmp.name, 996 tmp.nlen, 997 (void __user *)(unsigned long) tmp.oldval, 998 oldlenp, 999 (void __user *)(unsigned long) tmp.newval, 1000 tmp.newlen); 1001 unlock_kernel(); 1002 if (oldlenp) { 1003 if (!error) { 1004 if (get_user(oldlen, (size_t __user *)addr) || 1005 put_user(oldlen, (u32 __user *)(unsigned long) tmp.oldlenp)) 1006 error = -EFAULT; 1007 } 1008 if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused))) 1009 error = -EFAULT; 1010 } 1011 return error; 1012#endif 1013} 1014 1015long sys32_lookup_dcookie(unsigned long cookie_high, 1016 unsigned long cookie_low, 1017 char __user *buf, size_t len) 1018{ 1019 return sys_lookup_dcookie((cookie_high << 32) | cookie_low, 1020 buf, len); 1021} 1022 1023long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags) 1024{ 1025 return sys_sync_file_range(fd, 1026 (off_high << 32) | off_low, 1027 (nb_high << 32) | nb_low, 1028 flags); 1029} 1030