Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on
4 : : * sys_sparc32
5 : : *
6 : : * Copyright (C) 2000 VA Linux Co
7 : : * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
8 : : * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
9 : : * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
10 : : * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
11 : : * Copyright (C) 2000 Hewlett-Packard Co.
12 : : * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
13 : : * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port)
14 : : *
15 : : * These routines maintain argument size conversion between 32bit and 64bit
16 : : * environment. In 2.5 most of this should be moved to a generic directory.
17 : : *
18 : : * This file assumes that there is a hole at the end of user address space.
19 : : *
20 : : * Some of the functions are LE specific currently. These are
21 : : * hopefully all marked. This should be fixed.
22 : : */
23 : :
24 : : #include <linux/kernel.h>
25 : : #include <linux/sched.h>
26 : : #include <linux/fs.h>
27 : : #include <linux/file.h>
28 : : #include <linux/signal.h>
29 : : #include <linux/syscalls.h>
30 : : #include <linux/times.h>
31 : : #include <linux/utsname.h>
32 : : #include <linux/mm.h>
33 : : #include <linux/uio.h>
34 : : #include <linux/poll.h>
35 : : #include <linux/personality.h>
36 : : #include <linux/stat.h>
37 : : #include <linux/rwsem.h>
38 : : #include <linux/compat.h>
39 : : #include <linux/vfs.h>
40 : : #include <linux/ptrace.h>
41 : : #include <linux/highuid.h>
42 : : #include <linux/sysctl.h>
43 : : #include <linux/slab.h>
44 : : #include <linux/sched/task.h>
45 : : #include <asm/mman.h>
46 : : #include <asm/types.h>
47 : : #include <linux/uaccess.h>
48 : : #include <linux/atomic.h>
49 : : #include <asm/vgtod.h>
50 : : #include <asm/ia32.h>
51 : :
52 : : #define AA(__x) ((unsigned long)(__x))
53 : :
54 : :
55 : 0 : COMPAT_SYSCALL_DEFINE3(x86_truncate64, const char __user *, filename,
56 : : unsigned long, offset_low, unsigned long, offset_high)
57 : : {
58 : 0 : return ksys_truncate(filename,
59 : 0 : ((loff_t) offset_high << 32) | offset_low);
60 : : }
61 : :
62 : 0 : COMPAT_SYSCALL_DEFINE3(x86_ftruncate64, unsigned int, fd,
63 : : unsigned long, offset_low, unsigned long, offset_high)
64 : : {
65 : 0 : return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
66 : : }
67 : :
68 : : /*
69 : : * Another set for IA32/LFS -- x86_64 struct stat is different due to
70 : : * support for 64bit inode numbers.
71 : : */
72 : 0 : static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
73 : : {
74 : 0 : typeof(ubuf->st_uid) uid = 0;
75 : 0 : typeof(ubuf->st_gid) gid = 0;
76 [ # # ]: 0 : SET_UID(uid, from_kuid_munged(current_user_ns(), stat->uid));
77 [ # # ]: 0 : SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid));
78 [ # # ]: 0 : if (!access_ok(ubuf, sizeof(struct stat64)) ||
79 [ # # # # ]: 0 : __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
80 [ # # # # ]: 0 : __put_user(stat->ino, &ubuf->__st_ino) ||
81 [ # # # # ]: 0 : __put_user(stat->ino, &ubuf->st_ino) ||
82 [ # # # # ]: 0 : __put_user(stat->mode, &ubuf->st_mode) ||
83 [ # # # # ]: 0 : __put_user(stat->nlink, &ubuf->st_nlink) ||
84 [ # # # # ]: 0 : __put_user(uid, &ubuf->st_uid) ||
85 [ # # # # ]: 0 : __put_user(gid, &ubuf->st_gid) ||
86 [ # # # # ]: 0 : __put_user(huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
87 [ # # # # ]: 0 : __put_user(stat->size, &ubuf->st_size) ||
88 [ # # # # ]: 0 : __put_user(stat->atime.tv_sec, &ubuf->st_atime) ||
89 [ # # # # ]: 0 : __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec) ||
90 [ # # # # ]: 0 : __put_user(stat->mtime.tv_sec, &ubuf->st_mtime) ||
91 [ # # # # ]: 0 : __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
92 [ # # # # ]: 0 : __put_user(stat->ctime.tv_sec, &ubuf->st_ctime) ||
93 [ # # # # ]: 0 : __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
94 [ # # # # ]: 0 : __put_user(stat->blksize, &ubuf->st_blksize) ||
95 [ # # # # ]: 0 : __put_user(stat->blocks, &ubuf->st_blocks))
96 : 0 : return -EFAULT;
97 : : return 0;
98 : : }
99 : :
100 : 0 : COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename,
101 : : struct stat64 __user *, statbuf)
102 : : {
103 : 0 : struct kstat stat;
104 : 0 : int ret = vfs_stat(filename, &stat);
105 : :
106 [ # # ]: 0 : if (!ret)
107 : 0 : ret = cp_stat64(statbuf, &stat);
108 : 0 : return ret;
109 : : }
110 : :
111 : 0 : COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename,
112 : : struct stat64 __user *, statbuf)
113 : : {
114 : 0 : struct kstat stat;
115 : 0 : int ret = vfs_lstat(filename, &stat);
116 [ # # ]: 0 : if (!ret)
117 : 0 : ret = cp_stat64(statbuf, &stat);
118 : 0 : return ret;
119 : : }
120 : :
121 : 0 : COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd,
122 : : struct stat64 __user *, statbuf)
123 : : {
124 : 0 : struct kstat stat;
125 : 0 : int ret = vfs_fstat(fd, &stat);
126 [ # # ]: 0 : if (!ret)
127 : 0 : ret = cp_stat64(statbuf, &stat);
128 : 0 : return ret;
129 : : }
130 : :
131 : 0 : COMPAT_SYSCALL_DEFINE4(x86_fstatat, unsigned int, dfd,
132 : : const char __user *, filename,
133 : : struct stat64 __user *, statbuf, int, flag)
134 : : {
135 : 0 : struct kstat stat;
136 : 0 : int error;
137 : :
138 : 0 : error = vfs_fstatat(dfd, filename, &stat, flag);
139 [ # # ]: 0 : if (error)
140 : 0 : return error;
141 : 0 : return cp_stat64(statbuf, &stat);
142 : : }
143 : :
144 : : /*
145 : : * Linux/i386 didn't use to be able to handle more than
146 : : * 4 system call parameters, so these system calls used a memory
147 : : * block for parameter passing..
148 : : */
149 : :
150 : : struct mmap_arg_struct32 {
151 : : unsigned int addr;
152 : : unsigned int len;
153 : : unsigned int prot;
154 : : unsigned int flags;
155 : : unsigned int fd;
156 : : unsigned int offset;
157 : : };
158 : :
159 : 0 : COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg)
160 : : {
161 : 0 : struct mmap_arg_struct32 a;
162 : :
163 [ # # ]: 0 : if (copy_from_user(&a, arg, sizeof(a)))
164 : : return -EFAULT;
165 : :
166 [ # # ]: 0 : if (a.offset & ~PAGE_MASK)
167 : : return -EINVAL;
168 : :
169 : 0 : return ksys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
170 : 0 : a.offset>>PAGE_SHIFT);
171 : : }
172 : :
173 : : /* warning: next two assume little endian */
174 : 0 : COMPAT_SYSCALL_DEFINE5(x86_pread, unsigned int, fd, char __user *, ubuf,
175 : : u32, count, u32, poslo, u32, poshi)
176 : : {
177 : 0 : return ksys_pread64(fd, ubuf, count,
178 : 0 : ((loff_t)AA(poshi) << 32) | AA(poslo));
179 : : }
180 : :
181 : 0 : COMPAT_SYSCALL_DEFINE5(x86_pwrite, unsigned int, fd, const char __user *, ubuf,
182 : : u32, count, u32, poslo, u32, poshi)
183 : : {
184 : 0 : return ksys_pwrite64(fd, ubuf, count,
185 : 0 : ((loff_t)AA(poshi) << 32) | AA(poslo));
186 : : }
187 : :
188 : :
189 : : /*
190 : : * Some system calls that need sign extended arguments. This could be
191 : : * done by a generic wrapper.
192 : : */
193 : 0 : COMPAT_SYSCALL_DEFINE6(x86_fadvise64_64, int, fd, __u32, offset_low,
194 : : __u32, offset_high, __u32, len_low, __u32, len_high,
195 : : int, advice)
196 : : {
197 : 0 : return ksys_fadvise64_64(fd,
198 : 0 : (((u64)offset_high)<<32) | offset_low,
199 : 0 : (((u64)len_high)<<32) | len_low,
200 : : advice);
201 : : }
202 : :
203 : 0 : COMPAT_SYSCALL_DEFINE4(x86_readahead, int, fd, unsigned int, off_lo,
204 : : unsigned int, off_hi, size_t, count)
205 : : {
206 : 0 : return ksys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
207 : : }
208 : :
209 : 0 : COMPAT_SYSCALL_DEFINE6(x86_sync_file_range, int, fd, unsigned int, off_low,
210 : : unsigned int, off_hi, unsigned int, n_low,
211 : : unsigned int, n_hi, int, flags)
212 : : {
213 : 0 : return ksys_sync_file_range(fd,
214 : 0 : ((u64)off_hi << 32) | off_low,
215 : 0 : ((u64)n_hi << 32) | n_low, flags);
216 : : }
217 : :
218 : 0 : COMPAT_SYSCALL_DEFINE5(x86_fadvise64, int, fd, unsigned int, offset_lo,
219 : : unsigned int, offset_hi, size_t, len, int, advice)
220 : : {
221 : 0 : return ksys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
222 : : len, advice);
223 : : }
224 : :
225 : 0 : COMPAT_SYSCALL_DEFINE6(x86_fallocate, int, fd, int, mode,
226 : : unsigned int, offset_lo, unsigned int, offset_hi,
227 : : unsigned int, len_lo, unsigned int, len_hi)
228 : : {
229 : 0 : return ksys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
230 : 0 : ((u64)len_hi << 32) | len_lo);
231 : : }
232 : :
233 : : /*
234 : : * The 32-bit clone ABI is CONFIG_CLONE_BACKWARDS
235 : : */
236 : 0 : COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
237 : : unsigned long, newsp, int __user *, parent_tidptr,
238 : : unsigned long, tls_val, int __user *, child_tidptr)
239 : : {
240 : 0 : struct kernel_clone_args args = {
241 : 0 : .flags = (clone_flags & ~CSIGNAL),
242 : : .pidfd = parent_tidptr,
243 : : .child_tid = child_tidptr,
244 : : .parent_tid = parent_tidptr,
245 : 0 : .exit_signal = (clone_flags & CSIGNAL),
246 : : .stack = newsp,
247 : : .tls = tls_val,
248 : : };
249 : :
250 [ # # ]: 0 : if (!legacy_clone_args_valid(&args))
251 : : return -EINVAL;
252 : :
253 : 0 : return _do_fork(&args);
254 : : }
|