linux32.c 10.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*
 * Conversion between 32-bit and 64-bit native system calls.
 *
 * Copyright (C) 2000 Silicon Graphics, Inc.
 * Written by Ulf Carlsson (ulfc@engr.sgi.com)
 * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
 */
#include <linux/compiler.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/resource.h>
#include <linux/highmem.h>
#include <linux/time.h>
#include <linux/times.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/filter.h>
#include <linux/shm.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/icmpv6.h>
#include <linux/syscalls.h>
#include <linux/sysctl.h>
#include <linux/utime.h>
#include <linux/utsname.h>
#include <linux/personality.h>
#include <linux/dnotify.h>
#include <linux/module.h>
#include <linux/binfmts.h>
#include <linux/security.h>
35
#include <linux/syscalls.h>
L
Linus Torvalds 已提交
36 37
#include <linux/compat.h>
#include <linux/vfs.h>
A
Adrian Bunk 已提交
38
#include <linux/ipc.h>
L
Linus Torvalds 已提交
39 40 41 42

#include <net/sock.h>
#include <net/scm.h>

43
#include <asm/compat-signal.h>
L
Linus Torvalds 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#include <asm/sim.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/mman.h>

/* Use this to get at 32-bit user passed pointers. */
/* A() macro should be used for places where you e.g.
   have some internal variable u32 and just want to get
   rid of a compiler warning. AA() has to be used in
   places where you want to convert a function argument
   to 32bit pointer or when you e.g. access pt_regs
   structure and want to consider 32bit registers only.
 */
#define A(__x) ((unsigned long)(__x))
#define AA(__x) ((unsigned long)((int)__x))

#ifdef __MIPSEB__
61
#define merge_64(r1, r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL))
L
Linus Torvalds 已提交
62 63
#endif
#ifdef __MIPSEL__
64
#define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL))
L
Linus Torvalds 已提交
65 66
#endif

67 68 69
SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len,
	unsigned long, prot, unsigned long, flags, unsigned long, fd,
	unsigned long, pgoff)
L
Linus Torvalds 已提交
70 71 72 73 74
{
	struct file * file = NULL;
	unsigned long error;

	error = -EINVAL;
75 76 77 78
	if (pgoff & (~PAGE_MASK >> 12))
		goto out;
	pgoff >>= PAGE_SHIFT-12;

L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
	if (!(flags & MAP_ANONYMOUS)) {
		error = -EBADF;
		file = fget(fd);
		if (!file)
			goto out;
	}
	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);

	down_write(&current->mm->mmap_sem);
	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
	up_write(&current->mm->mmap_sem);
	if (file)
		fput(file);

out:
	return error;
}

/*
 * sys_execve() executes a new program.
 */
asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
{
	int error;
	char * filename;

	filename = getname(compat_ptr(regs.regs[4]));
	error = PTR_ERR(filename);
	if (IS_ERR(filename))
		goto out;
	error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
				 compat_ptr(regs.regs[6]), &regs);
	putname(filename);

out:
	return error;
}

#define RLIM_INFINITY32	0x7fffffff
#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)

struct rlimit32 {
	int	rlim_cur;
	int	rlim_max;
};

125 126
SYSCALL_DEFINE4(32_truncate64, const char __user *, path,
	unsigned long, __dummy, unsigned long, a2, unsigned long, a3)
L
Linus Torvalds 已提交
127
{
128
	return sys_truncate(path, merge_64(a2, a3));
L
Linus Torvalds 已提交
129 130
}

131 132
SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy,
	unsigned long, a2, unsigned long, a3)
L
Linus Torvalds 已提交
133
{
134
	return sys_ftruncate(fd, merge_64(a2, a3));
L
Linus Torvalds 已提交
135 136
}

137 138 139
SYSCALL_DEFINE5(32_llseek, unsigned long, fd, unsigned long, offset_high,
	unsigned long, offset_low, loff_t __user *, result,
	unsigned long, origin)
L
Linus Torvalds 已提交
140 141 142 143 144 145 146 147
{
	return sys_llseek(fd, offset_high, offset_low, result, origin);
}

/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
   lseek back to original location.  They fail just like lseek does on
   non-seekable files.  */

148 149
SYSCALL_DEFINE6(32_pread, unsigned long, fd, char __user *, buf, size_t, count,
	unsigned long, unused, unsigned long, a4, unsigned long, a5)
L
Linus Torvalds 已提交
150
{
A
Al Viro 已提交
151
	return sys_pread64(fd, buf, count, merge_64(a4, a5));
L
Linus Torvalds 已提交
152 153
}

154 155
SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf,
	size_t, count, u32, unused, u64, a4, u64, a5)
L
Linus Torvalds 已提交
156
{
A
Al Viro 已提交
157
	return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
L
Linus Torvalds 已提交
158 159
}

160 161
SYSCALL_DEFINE2(32_sched_rr_get_interval, compat_pid_t, pid,
	struct compat_timespec __user *, interval)
L
Linus Torvalds 已提交
162 163 164
{
	struct timespec t;
	int ret;
165
	mm_segment_t old_fs = get_fs();
L
Linus Torvalds 已提交
166

167
	set_fs(KERNEL_DS);
168
	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
169
	set_fs(old_fs);
L
Linus Torvalds 已提交
170
	if (put_user (t.tv_sec, &interval->tv_sec) ||
171
	    __put_user(t.tv_nsec, &interval->tv_nsec))
L
Linus Torvalds 已提交
172 173 174 175
		return -EFAULT;
	return ret;
}

176 177
#ifdef CONFIG_SYSVIPC

178 179
SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
	unsigned long, ptr, unsigned long, fifth)
L
Linus Torvalds 已提交
180 181 182 183 184 185 186 187 188
{
	int version, err;

	version = call >> 16; /* hack for backward compatibility */
	call &= 0xffff;

	switch (call) {
	case SEMOP:
		/* struct sembuf is the same on 32 and 64bit :)) */
189
		err = sys_semtimedop(first, compat_ptr(ptr), second, NULL);
L
Linus Torvalds 已提交
190 191
		break;
	case SEMTIMEDOP:
192 193
		err = compat_sys_semtimedop(first, compat_ptr(ptr), second,
					    compat_ptr(fifth));
L
Linus Torvalds 已提交
194 195
		break;
	case SEMGET:
196
		err = sys_semget(first, second, third);
L
Linus Torvalds 已提交
197 198
		break;
	case SEMCTL:
199
		err = compat_sys_semctl(first, second, third, compat_ptr(ptr));
L
Linus Torvalds 已提交
200 201
		break;
	case MSGSND:
202
		err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
L
Linus Torvalds 已提交
203 204
		break;
	case MSGRCV:
205 206
		err = compat_sys_msgrcv(first, second, fifth, third,
					version, compat_ptr(ptr));
L
Linus Torvalds 已提交
207 208
		break;
	case MSGGET:
209
		err = sys_msgget((key_t) first, second);
L
Linus Torvalds 已提交
210 211
		break;
	case MSGCTL:
212
		err = compat_sys_msgctl(first, second, compat_ptr(ptr));
L
Linus Torvalds 已提交
213 214
		break;
	case SHMAT:
215 216
		err = compat_sys_shmat(first, second, third, version,
				       compat_ptr(ptr));
L
Linus Torvalds 已提交
217 218
		break;
	case SHMDT:
219
		err = sys_shmdt(compat_ptr(ptr));
L
Linus Torvalds 已提交
220 221
		break;
	case SHMGET:
222
		err = sys_shmget(first, (unsigned)second, third);
L
Linus Torvalds 已提交
223 224
		break;
	case SHMCTL:
225
		err = compat_sys_shmctl(first, second, compat_ptr(ptr));
L
Linus Torvalds 已提交
226 227 228 229 230 231 232 233 234
		break;
	default:
		err = -EINVAL;
		break;
	}

	return err;
}

235 236
#else

237
SYSCALL_DEFINE6(32_ipc, u32, call, int, first, int, second, int, third,
238
	u32, ptr, u32, fifth)
239 240 241 242 243 244
{
	return -ENOSYS;
}

#endif /* CONFIG_SYSVIPC */

245
#ifdef CONFIG_MIPS32_N32
246
SYSCALL_DEFINE4(n32_semctl, int, semid, int, semnum, int, cmd, u32, arg)
L
Linus Torvalds 已提交
247
{
248 249
	/* compat_sys_semctl expects a pointer to union semun */
	u32 __user *uptr = compat_alloc_user_space(sizeof(u32));
250
	if (put_user(arg, uptr))
251 252
		return -EFAULT;
	return compat_sys_semctl(semid, semnum, cmd, uptr);
L
Linus Torvalds 已提交
253
}
254

255 256
SYSCALL_DEFINE4(n32_msgsnd, int, msqid, u32, msgp, unsigned int, msgsz,
	int, msgflg)
257 258 259 260
{
	return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp));
}

261 262
SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
	int, msgtyp, int, msgflg)
263 264 265 266
{
	return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64,
				 compat_ptr(msgp));
}
267
#endif
L
Linus Torvalds 已提交
268 269 270 271 272 273 274 275 276 277 278 279

struct sysctl_args32
{
	compat_caddr_t name;
	int nlen;
	compat_caddr_t oldval;
	compat_caddr_t oldlenp;
	compat_caddr_t newval;
	compat_size_t newlen;
	unsigned int __unused[4];
};

280
#ifdef CONFIG_SYSCTL_SYSCALL
L
Linus Torvalds 已提交
281

282
SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
L
Linus Torvalds 已提交
283 284 285
{
	struct sysctl_args32 tmp;
	int error;
286 287 288
	size_t oldlen;
	size_t __user *oldlenp = NULL;
	unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
L
Linus Torvalds 已提交
289 290 291 292 293 294 295 296 297 298 299

	if (copy_from_user(&tmp, args, sizeof(tmp)))
		return -EFAULT;

	if (tmp.oldval && tmp.oldlenp) {
		/* Duh, this is ugly and might not work if sysctl_args
		   is in read-only memory, but do_sysctl does indirectly
		   a lot of uaccess in both directions and we'd have to
		   basically copy the whole sysctl.c here, and
		   glibc's __sysctl uses rw memory for the structure
		   anyway.  */
300 301
		if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) ||
		    put_user(oldlen, (size_t __user *)addr))
L
Linus Torvalds 已提交
302
			return -EFAULT;
303
		oldlenp = (size_t __user *)addr;
L
Linus Torvalds 已提交
304 305 306
	}

	lock_kernel();
307 308
	error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval),
			  oldlenp, (void __user *)A(tmp.newval), tmp.newlen);
L
Linus Torvalds 已提交
309 310 311
	unlock_kernel();
	if (oldlenp) {
		if (!error) {
312 313
			if (get_user(oldlen, (size_t __user *)addr) ||
			    put_user(oldlen, (u32 __user *)A(tmp.oldlenp)))
L
Linus Torvalds 已提交
314 315 316 317 318 319 320
				error = -EFAULT;
		}
		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
	}
	return error;
}

321 322 323 324 325 326 327
#else

SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
{
	return -ENOSYS;
}

328
#endif /* CONFIG_SYSCTL_SYSCALL */
L
Linus Torvalds 已提交
329

330
SYSCALL_DEFINE1(32_newuname, struct new_utsname __user *, name)
L
Linus Torvalds 已提交
331 332 333 334
{
	int ret = 0;

	down_read(&uts_sem);
335
	if (copy_to_user(name, utsname(), sizeof *name))
L
Linus Torvalds 已提交
336 337 338 339 340 341 342 343 344 345
		ret = -EFAULT;
	up_read(&uts_sem);

	if (current->personality == PER_LINUX32 && !ret)
		if (copy_to_user(name->machine, "mips\0\0\0", 8))
			ret = -EFAULT;

	return ret;
}

346
SYSCALL_DEFINE1(32_personality, unsigned long, personality)
L
Linus Torvalds 已提交
347 348
{
	int ret;
349 350 351
	personality &= 0xffffffff;
	if (personality(current->personality) == PER_LINUX32 &&
	    personality == PER_LINUX)
L
Linus Torvalds 已提交
352 353 354 355 356 357 358
		personality = PER_LINUX32;
	ret = sys_personality(personality);
	if (ret == PER_LINUX32)
		ret = PER_LINUX;
	return ret;
}

359 360
SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
	compat_off_t __user *, offset, s32, count)
L
Linus Torvalds 已提交
361 362 363 364
{
	mm_segment_t old_fs = get_fs();
	int ret;
	off_t of;
365

L
Linus Torvalds 已提交
366 367
	if (offset && get_user(of, offset))
		return -EFAULT;
368

L
Linus Torvalds 已提交
369
	set_fs(KERNEL_DS);
370
	ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
L
Linus Torvalds 已提交
371
	set_fs(old_fs);
372

L
Linus Torvalds 已提交
373 374
	if (offset && put_user(of, offset))
		return -EFAULT;
375

L
Linus Torvalds 已提交
376 377 378 379 380 381 382 383 384
	return ret;
}

asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
                                   size_t count)
{
	return sys_readahead(fd, merge_64(a2, a3), count);
}

385 386 387 388 389 390 391 392 393 394
asmlinkage long sys32_sync_file_range(int fd, int __pad,
	unsigned long a2, unsigned long a3,
	unsigned long a4, unsigned long a5,
	int flags)
{
	return sys_sync_file_range(fd,
			merge_64(a2, a3), merge_64(a4, a5),
			flags);
}

395 396 397 398 399 400 401 402 403 404
asmlinkage long sys32_fadvise64_64(int fd, int __pad,
	unsigned long a2, unsigned long a3,
	unsigned long a4, unsigned long a5,
	int flags)
{
	return sys_fadvise64_64(fd,
			merge_64(a2, a3), merge_64(a4, a5),
			flags);
}

405 406 407 408 409 410 411
asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2,
	unsigned offset_a3, unsigned len_a4, unsigned len_a5)
{
	return sys_fallocate(fd, mode, merge_64(offset_a2, offset_a3),
	                     merge_64(len_a4, len_a5));
}

R
Ralf Baechle 已提交
412
save_static_function(sys32_clone);
413
static int noinline __used
R
Ralf Baechle 已提交
414 415 416 417 418 419 420 421 422 423
_sys32_clone(nabi_no_regargs struct pt_regs regs)
{
	unsigned long clone_flags;
	unsigned long newsp;
	int __user *parent_tidptr, *child_tidptr;

	clone_flags = regs.regs[4];
	newsp = regs.regs[5];
	if (!newsp)
		newsp = regs.regs[29];
424
	parent_tidptr = (int __user *) regs.regs[6];
R
Ralf Baechle 已提交
425 426 427 428 429 430 431

	/* Use __dummy4 instead of getting it off the stack, so that
	   syscall() works.  */
	child_tidptr = (int __user *) __dummy4;
	return do_fork(clone_flags, newsp, &regs, 0,
	               parent_tidptr, child_tidptr);
}