1 /* 2 * Conversion between 32-bit and 64-bit native system calls. 3 * 4 * Copyright (C) 2000 Silicon Graphics, Inc. 5 * Written by Ulf Carlsson (ulfc@engr.sgi.com) 6 * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com) 7 */ 8 #include <linux/compiler.h> 9 #include <linux/mm.h> 10 #include <linux/errno.h> 11 #include <linux/file.h> 12 #include <linux/smp_lock.h> 13 #include <linux/highuid.h> 14 #include <linux/dirent.h> 15 #include <linux/resource.h> 16 #include <linux/highmem.h> 17 #include <linux/time.h> 18 #include <linux/times.h> 19 #include <linux/poll.h> 20 #include <linux/slab.h> 21 #include <linux/skbuff.h> 22 #include <linux/filter.h> 23 #include <linux/shm.h> 24 #include <linux/sem.h> 25 #include <linux/msg.h> 26 #include <linux/icmpv6.h> 27 #include <linux/syscalls.h> 28 #include <linux/sysctl.h> 29 #include <linux/utime.h> 30 #include <linux/utsname.h> 31 #include <linux/personality.h> 32 #include <linux/dnotify.h> 33 #include <linux/module.h> 34 #include <linux/binfmts.h> 35 #include <linux/security.h> 36 #include <linux/compat.h> 37 #include <linux/vfs.h> 38 #include <linux/ipc.h> 39 40 #include <net/sock.h> 41 #include <net/scm.h> 42 43 #include <asm/compat-signal.h> 44 #include <asm/sim.h> 45 #include <asm/uaccess.h> 46 #include <asm/mmu_context.h> 47 #include <asm/mman.h> 48 49 /* Use this to get at 32-bit user passed pointers. */ 50 /* A() macro should be used for places where you e.g. 51 have some internal variable u32 and just want to get 52 rid of a compiler warning. AA() has to be used in 53 places where you want to convert a function argument 54 to 32bit pointer or when you e.g. access pt_regs 55 structure and want to consider 32bit registers only. 56 */ 57 #define A(__x) ((unsigned long)(__x)) 58 #define AA(__x) ((unsigned long)((int)__x)) 59 60 #ifdef __MIPSEB__ 61 #define merge_64(r1, r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL)) 62 #endif 63 #ifdef __MIPSEL__ 64 #define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL)) 65 #endif 66 67 /* 68 * Revalidate the inode. This is required for proper NFS attribute caching. 69 */ 70 71 int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 72 { 73 struct compat_stat tmp; 74 75 if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) 76 return -EOVERFLOW; 77 78 memset(&tmp, 0, sizeof(tmp)); 79 tmp.st_dev = new_encode_dev(stat->dev); 80 tmp.st_ino = stat->ino; 81 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 82 return -EOVERFLOW; 83 tmp.st_mode = stat->mode; 84 tmp.st_nlink = stat->nlink; 85 SET_UID(tmp.st_uid, stat->uid); 86 SET_GID(tmp.st_gid, stat->gid); 87 tmp.st_rdev = new_encode_dev(stat->rdev); 88 tmp.st_size = stat->size; 89 tmp.st_atime = stat->atime.tv_sec; 90 tmp.st_mtime = stat->mtime.tv_sec; 91 tmp.st_ctime = stat->ctime.tv_sec; 92 #ifdef STAT_HAVE_NSEC 93 tmp.st_atime_nsec = stat->atime.tv_nsec; 94 tmp.st_mtime_nsec = stat->mtime.tv_nsec; 95 tmp.st_ctime_nsec = stat->ctime.tv_nsec; 96 #endif 97 tmp.st_blocks = stat->blocks; 98 tmp.st_blksize = stat->blksize; 99 return copy_to_user(statbuf, &tmp, sizeof(tmp)) ? -EFAULT : 0; 100 } 101 102 asmlinkage unsigned long 103 sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 104 unsigned long flags, unsigned long fd, unsigned long pgoff) 105 { 106 struct file * file = NULL; 107 unsigned long error; 108 109 error = -EINVAL; 110 if (pgoff & (~PAGE_MASK >> 12)) 111 goto out; 112 pgoff >>= PAGE_SHIFT-12; 113 114 if (!(flags & MAP_ANONYMOUS)) { 115 error = -EBADF; 116 file = fget(fd); 117 if (!file) 118 goto out; 119 } 120 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 121 122 down_write(¤t->mm->mmap_sem); 123 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); 124 up_write(¤t->mm->mmap_sem); 125 if (file) 126 fput(file); 127 128 out: 129 return error; 130 } 131 132 /* 133 * sys_execve() executes a new program. 134 */ 135 asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs) 136 { 137 int error; 138 char * filename; 139 140 filename = getname(compat_ptr(regs.regs[4])); 141 error = PTR_ERR(filename); 142 if (IS_ERR(filename)) 143 goto out; 144 error = compat_do_execve(filename, compat_ptr(regs.regs[5]), 145 compat_ptr(regs.regs[6]), ®s); 146 putname(filename); 147 148 out: 149 return error; 150 } 151 152 #define RLIM_INFINITY32 0x7fffffff 153 #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) 154 155 struct rlimit32 { 156 int rlim_cur; 157 int rlim_max; 158 }; 159 160 asmlinkage long sys32_truncate64(const char __user * path, 161 unsigned long __dummy, int a2, int a3) 162 { 163 return sys_truncate(path, merge_64(a2, a3)); 164 } 165 166 asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy, 167 int a2, int a3) 168 { 169 return sys_ftruncate(fd, merge_64(a2, a3)); 170 } 171 172 static inline long 173 get_tv32(struct timeval *o, struct compat_timeval __user *i) 174 { 175 return (!access_ok(VERIFY_READ, i, sizeof(*i)) || 176 (__get_user(o->tv_sec, &i->tv_sec) | 177 __get_user(o->tv_usec, &i->tv_usec))); 178 } 179 180 static inline long 181 put_tv32(struct compat_timeval __user *o, struct timeval *i) 182 { 183 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || 184 (__put_user(i->tv_sec, &o->tv_sec) | 185 __put_user(i->tv_usec, &o->tv_usec))); 186 } 187 188 extern struct timezone sys_tz; 189 190 asmlinkage int 191 sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) 192 { 193 if (tv) { 194 struct timeval ktv; 195 do_gettimeofday(&ktv); 196 if (put_tv32(tv, &ktv)) 197 return -EFAULT; 198 } 199 if (tz) { 200 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) 201 return -EFAULT; 202 } 203 return 0; 204 } 205 206 static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) 207 { 208 long usec; 209 210 if (!access_ok(VERIFY_READ, i, sizeof(*i))) 211 return -EFAULT; 212 if (__get_user(o->tv_sec, &i->tv_sec)) 213 return -EFAULT; 214 if (__get_user(usec, &i->tv_usec)) 215 return -EFAULT; 216 o->tv_nsec = usec * 1000; 217 return 0; 218 } 219 220 asmlinkage int 221 sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) 222 { 223 struct timespec kts; 224 struct timezone ktz; 225 226 if (tv) { 227 if (get_ts32(&kts, tv)) 228 return -EFAULT; 229 } 230 if (tz) { 231 if (copy_from_user(&ktz, tz, sizeof(ktz))) 232 return -EFAULT; 233 } 234 235 return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); 236 } 237 238 asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high, 239 unsigned int offset_low, loff_t __user * result, 240 unsigned int origin) 241 { 242 return sys_llseek(fd, offset_high, offset_low, result, origin); 243 } 244 245 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op + 246 lseek back to original location. They fail just like lseek does on 247 non-seekable files. */ 248 249 asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf, 250 size_t count, u32 unused, u64 a4, u64 a5) 251 { 252 return sys_pread64(fd, buf, count, merge_64(a4, a5)); 253 } 254 255 asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf, 256 size_t count, u32 unused, u64 a4, u64 a5) 257 { 258 return sys_pwrite64(fd, buf, count, merge_64(a4, a5)); 259 } 260 261 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, 262 struct compat_timespec __user *interval) 263 { 264 struct timespec t; 265 int ret; 266 mm_segment_t old_fs = get_fs(); 267 268 set_fs(KERNEL_DS); 269 ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); 270 set_fs(old_fs); 271 if (put_user (t.tv_sec, &interval->tv_sec) || 272 __put_user(t.tv_nsec, &interval->tv_nsec)) 273 return -EFAULT; 274 return ret; 275 } 276 277 #ifdef CONFIG_SYSVIPC 278 279 asmlinkage long 280 sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) 281 { 282 int version, err; 283 284 version = call >> 16; /* hack for backward compatibility */ 285 call &= 0xffff; 286 287 switch (call) { 288 case SEMOP: 289 /* struct sembuf is the same on 32 and 64bit :)) */ 290 err = sys_semtimedop(first, compat_ptr(ptr), second, NULL); 291 break; 292 case SEMTIMEDOP: 293 err = compat_sys_semtimedop(first, compat_ptr(ptr), second, 294 compat_ptr(fifth)); 295 break; 296 case SEMGET: 297 err = sys_semget(first, second, third); 298 break; 299 case SEMCTL: 300 err = compat_sys_semctl(first, second, third, compat_ptr(ptr)); 301 break; 302 case MSGSND: 303 err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr)); 304 break; 305 case MSGRCV: 306 err = compat_sys_msgrcv(first, second, fifth, third, 307 version, compat_ptr(ptr)); 308 break; 309 case MSGGET: 310 err = sys_msgget((key_t) first, second); 311 break; 312 case MSGCTL: 313 err = compat_sys_msgctl(first, second, compat_ptr(ptr)); 314 break; 315 case SHMAT: 316 err = compat_sys_shmat(first, second, third, version, 317 compat_ptr(ptr)); 318 break; 319 case SHMDT: 320 err = sys_shmdt(compat_ptr(ptr)); 321 break; 322 case SHMGET: 323 err = sys_shmget(first, (unsigned)second, third); 324 break; 325 case SHMCTL: 326 err = compat_sys_shmctl(first, second, compat_ptr(ptr)); 327 break; 328 default: 329 err = -EINVAL; 330 break; 331 } 332 333 return err; 334 } 335 336 #else 337 338 asmlinkage long 339 sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) 340 { 341 return -ENOSYS; 342 } 343 344 #endif /* CONFIG_SYSVIPC */ 345 346 #ifdef CONFIG_MIPS32_N32 347 asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, u32 arg) 348 { 349 /* compat_sys_semctl expects a pointer to union semun */ 350 u32 __user *uptr = compat_alloc_user_space(sizeof(u32)); 351 if (put_user(arg, uptr)) 352 return -EFAULT; 353 return compat_sys_semctl(semid, semnum, cmd, uptr); 354 } 355 356 asmlinkage long sysn32_msgsnd(int msqid, u32 msgp, unsigned msgsz, int msgflg) 357 { 358 return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp)); 359 } 360 361 asmlinkage long sysn32_msgrcv(int msqid, u32 msgp, size_t msgsz, int msgtyp, 362 int msgflg) 363 { 364 return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64, 365 compat_ptr(msgp)); 366 } 367 #endif 368 369 struct sysctl_args32 370 { 371 compat_caddr_t name; 372 int nlen; 373 compat_caddr_t oldval; 374 compat_caddr_t oldlenp; 375 compat_caddr_t newval; 376 compat_size_t newlen; 377 unsigned int __unused[4]; 378 }; 379 380 #ifdef CONFIG_SYSCTL_SYSCALL 381 382 asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args) 383 { 384 struct sysctl_args32 tmp; 385 int error; 386 size_t oldlen; 387 size_t __user *oldlenp = NULL; 388 unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7; 389 390 if (copy_from_user(&tmp, args, sizeof(tmp))) 391 return -EFAULT; 392 393 if (tmp.oldval && tmp.oldlenp) { 394 /* Duh, this is ugly and might not work if sysctl_args 395 is in read-only memory, but do_sysctl does indirectly 396 a lot of uaccess in both directions and we'd have to 397 basically copy the whole sysctl.c here, and 398 glibc's __sysctl uses rw memory for the structure 399 anyway. */ 400 if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) || 401 put_user(oldlen, (size_t __user *)addr)) 402 return -EFAULT; 403 oldlenp = (size_t __user *)addr; 404 } 405 406 lock_kernel(); 407 error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval), 408 oldlenp, (void __user *)A(tmp.newval), tmp.newlen); 409 unlock_kernel(); 410 if (oldlenp) { 411 if (!error) { 412 if (get_user(oldlen, (size_t __user *)addr) || 413 put_user(oldlen, (u32 __user *)A(tmp.oldlenp))) 414 error = -EFAULT; 415 } 416 copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); 417 } 418 return error; 419 } 420 421 #endif /* CONFIG_SYSCTL_SYSCALL */ 422 423 asmlinkage long sys32_newuname(struct new_utsname __user * name) 424 { 425 int ret = 0; 426 427 down_read(&uts_sem); 428 if (copy_to_user(name, utsname(), sizeof *name)) 429 ret = -EFAULT; 430 up_read(&uts_sem); 431 432 if (current->personality == PER_LINUX32 && !ret) 433 if (copy_to_user(name->machine, "mips\0\0\0", 8)) 434 ret = -EFAULT; 435 436 return ret; 437 } 438 439 asmlinkage int sys32_personality(unsigned long personality) 440 { 441 int ret; 442 personality &= 0xffffffff; 443 if (personality(current->personality) == PER_LINUX32 && 444 personality == PER_LINUX) 445 personality = PER_LINUX32; 446 ret = sys_personality(personality); 447 if (ret == PER_LINUX32) 448 ret = PER_LINUX; 449 return ret; 450 } 451 452 /* ustat compatibility */ 453 struct ustat32 { 454 compat_daddr_t f_tfree; 455 compat_ino_t f_tinode; 456 char f_fname[6]; 457 char f_fpack[6]; 458 }; 459 460 extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf); 461 462 asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) 463 { 464 int err; 465 struct ustat tmp; 466 struct ustat32 tmp32; 467 mm_segment_t old_fs = get_fs(); 468 469 set_fs(KERNEL_DS); 470 err = sys_ustat(dev, (struct ustat __user *)&tmp); 471 set_fs(old_fs); 472 473 if (err) 474 goto out; 475 476 memset(&tmp32, 0, sizeof(struct ustat32)); 477 tmp32.f_tfree = tmp.f_tfree; 478 tmp32.f_tinode = tmp.f_tinode; 479 480 err = copy_to_user(ubuf32, &tmp32, sizeof(struct ustat32)) ? -EFAULT : 0; 481 482 out: 483 return err; 484 } 485 486 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, 487 s32 count) 488 { 489 mm_segment_t old_fs = get_fs(); 490 int ret; 491 off_t of; 492 493 if (offset && get_user(of, offset)) 494 return -EFAULT; 495 496 set_fs(KERNEL_DS); 497 ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count); 498 set_fs(old_fs); 499 500 if (offset && put_user(of, offset)) 501 return -EFAULT; 502 503 return ret; 504 } 505 506 asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3, 507 size_t count) 508 { 509 return sys_readahead(fd, merge_64(a2, a3), count); 510 } 511 512 asmlinkage long sys32_sync_file_range(int fd, int __pad, 513 unsigned long a2, unsigned long a3, 514 unsigned long a4, unsigned long a5, 515 int flags) 516 { 517 return sys_sync_file_range(fd, 518 merge_64(a2, a3), merge_64(a4, a5), 519 flags); 520 } 521 522 asmlinkage long sys32_fadvise64_64(int fd, int __pad, 523 unsigned long a2, unsigned long a3, 524 unsigned long a4, unsigned long a5, 525 int flags) 526 { 527 return sys_fadvise64_64(fd, 528 merge_64(a2, a3), merge_64(a4, a5), 529 flags); 530 } 531 532 asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2, 533 unsigned offset_a3, unsigned len_a4, unsigned len_a5) 534 { 535 return sys_fallocate(fd, mode, merge_64(offset_a2, offset_a3), 536 merge_64(len_a4, len_a5)); 537 } 538 539 save_static_function(sys32_clone); 540 static int noinline __used 541 _sys32_clone(nabi_no_regargs struct pt_regs regs) 542 { 543 unsigned long clone_flags; 544 unsigned long newsp; 545 int __user *parent_tidptr, *child_tidptr; 546 547 clone_flags = regs.regs[4]; 548 newsp = regs.regs[5]; 549 if (!newsp) 550 newsp = regs.regs[29]; 551 parent_tidptr = (int __user *) regs.regs[6]; 552 553 /* Use __dummy4 instead of getting it off the stack, so that 554 syscall() works. */ 555 child_tidptr = (int __user *) __dummy4; 556 return do_fork(clone_flags, newsp, ®s, 0, 557 parent_tidptr, child_tidptr); 558 } 559