1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * arch/arm/kernel/sys_oabi-compat.c |
4 | * |
5 | * Compatibility wrappers for syscalls that are used from |
6 | * old ABI user space binaries with an EABI kernel. |
7 | * |
8 | * Author: Nicolas Pitre |
9 | * Created: Oct 7, 2005 |
10 | * Copyright: MontaVista Software, Inc. |
11 | */ |
12 | |
13 | #include <asm/syscalls.h> |
14 | |
15 | /* |
16 | * The legacy ABI and the new ARM EABI have different rules making some |
17 | * syscalls incompatible especially with structure arguments. |
18 | * Most notably, Eabi says 64-bit members should be 64-bit aligned instead of |
19 | * simply word aligned. EABI also pads structures to the size of the largest |
20 | * member it contains instead of the invariant 32-bit. |
21 | * |
22 | * The following syscalls are affected: |
23 | * |
24 | * sys_stat64: |
25 | * sys_lstat64: |
26 | * sys_fstat64: |
27 | * sys_fstatat64: |
28 | * |
29 | * struct stat64 has different sizes and some members are shifted |
30 | * Compatibility wrappers are needed for them and provided below. |
31 | * |
32 | * sys_fcntl64: |
33 | * |
34 | * struct flock64 has different sizes and some members are shifted |
35 | * A compatibility wrapper is needed and provided below. |
36 | * |
37 | * sys_statfs64: |
38 | * sys_fstatfs64: |
39 | * |
40 | * struct statfs64 has extra padding with EABI growing its size from |
41 | * 84 to 88. This struct is now __attribute__((packed,aligned(4))) |
42 | * with a small assembly wrapper to force the sz argument to 84 if it is 88 |
43 | * to avoid copying the extra padding over user space unexpecting it. |
44 | * |
45 | * sys_newuname: |
46 | * |
47 | * struct new_utsname has no padding with EABI. No problem there. |
48 | * |
49 | * sys_epoll_ctl: |
50 | * sys_epoll_wait: |
51 | * |
52 | * struct epoll_event has its second member shifted also affecting the |
53 | * structure size. Compatibility wrappers are needed and provided below. |
54 | * |
55 | * sys_ipc: |
56 | * sys_semop: |
57 | * sys_semtimedop: |
58 | * |
59 | * struct sembuf loses its padding with EABI. Since arrays of them are |
60 | * used they have to be copyed to remove the padding. Compatibility wrappers |
61 | * provided below. |
62 | * |
63 | * sys_bind: |
64 | * sys_connect: |
65 | * sys_sendmsg: |
66 | * sys_sendto: |
67 | * sys_socketcall: |
68 | * |
69 | * struct sockaddr_un loses its padding with EABI. Since the size of the |
70 | * structure is used as a validation test in unix_mkname(), we need to |
71 | * change the length argument to 110 whenever it is 112. Compatibility |
72 | * wrappers provided below. |
73 | */ |
74 | |
75 | #include <linux/syscalls.h> |
76 | #include <linux/errno.h> |
77 | #include <linux/fs.h> |
78 | #include <linux/filelock.h> |
79 | #include <linux/cred.h> |
80 | #include <linux/fcntl.h> |
81 | #include <linux/eventpoll.h> |
82 | #include <linux/sem.h> |
83 | #include <linux/socket.h> |
84 | #include <linux/net.h> |
85 | #include <linux/ipc.h> |
86 | #include <linux/ipc_namespace.h> |
87 | #include <linux/uaccess.h> |
88 | #include <linux/slab.h> |
89 | |
90 | #include <asm/syscall.h> |
91 | |
92 | struct oldabi_stat64 { |
93 | unsigned long long st_dev; |
94 | unsigned int __pad1; |
95 | unsigned long __st_ino; |
96 | unsigned int st_mode; |
97 | unsigned int st_nlink; |
98 | |
99 | unsigned long st_uid; |
100 | unsigned long st_gid; |
101 | |
102 | unsigned long long st_rdev; |
103 | unsigned int __pad2; |
104 | |
105 | long long st_size; |
106 | unsigned long st_blksize; |
107 | unsigned long long st_blocks; |
108 | |
109 | unsigned long st_atime; |
110 | unsigned long st_atime_nsec; |
111 | |
112 | unsigned long st_mtime; |
113 | unsigned long st_mtime_nsec; |
114 | |
115 | unsigned long st_ctime; |
116 | unsigned long st_ctime_nsec; |
117 | |
118 | unsigned long long st_ino; |
119 | } __attribute__ ((packed,aligned(4))); |
120 | |
121 | static long cp_oldabi_stat64(struct kstat *stat, |
122 | struct oldabi_stat64 __user *statbuf) |
123 | { |
124 | struct oldabi_stat64 tmp; |
125 | |
126 | tmp.st_dev = huge_encode_dev(dev: stat->dev); |
127 | tmp.__pad1 = 0; |
128 | tmp.__st_ino = stat->ino; |
129 | tmp.st_mode = stat->mode; |
130 | tmp.st_nlink = stat->nlink; |
131 | tmp.st_uid = from_kuid_munged(current_user_ns(), uid: stat->uid); |
132 | tmp.st_gid = from_kgid_munged(current_user_ns(), gid: stat->gid); |
133 | tmp.st_rdev = huge_encode_dev(dev: stat->rdev); |
134 | tmp.st_size = stat->size; |
135 | tmp.st_blocks = stat->blocks; |
136 | tmp.__pad2 = 0; |
137 | tmp.st_blksize = stat->blksize; |
138 | tmp.st_atime = stat->atime.tv_sec; |
139 | tmp.st_atime_nsec = stat->atime.tv_nsec; |
140 | tmp.st_mtime = stat->mtime.tv_sec; |
141 | tmp.st_mtime_nsec = stat->mtime.tv_nsec; |
142 | tmp.st_ctime = stat->ctime.tv_sec; |
143 | tmp.st_ctime_nsec = stat->ctime.tv_nsec; |
144 | tmp.st_ino = stat->ino; |
145 | return copy_to_user(to: statbuf,from: &tmp,n: sizeof(tmp)) ? -EFAULT : 0; |
146 | } |
147 | |
148 | asmlinkage long sys_oabi_stat64(const char __user * filename, |
149 | struct oldabi_stat64 __user * statbuf) |
150 | { |
151 | struct kstat stat; |
152 | int error = vfs_stat(filename, stat: &stat); |
153 | if (!error) |
154 | error = cp_oldabi_stat64(stat: &stat, statbuf); |
155 | return error; |
156 | } |
157 | |
158 | asmlinkage long sys_oabi_lstat64(const char __user * filename, |
159 | struct oldabi_stat64 __user * statbuf) |
160 | { |
161 | struct kstat stat; |
162 | int error = vfs_lstat(name: filename, stat: &stat); |
163 | if (!error) |
164 | error = cp_oldabi_stat64(stat: &stat, statbuf); |
165 | return error; |
166 | } |
167 | |
168 | asmlinkage long sys_oabi_fstat64(unsigned long fd, |
169 | struct oldabi_stat64 __user * statbuf) |
170 | { |
171 | struct kstat stat; |
172 | int error = vfs_fstat(fd, stat: &stat); |
173 | if (!error) |
174 | error = cp_oldabi_stat64(stat: &stat, statbuf); |
175 | return error; |
176 | } |
177 | |
178 | asmlinkage long sys_oabi_fstatat64(int dfd, |
179 | const char __user *filename, |
180 | struct oldabi_stat64 __user *statbuf, |
181 | int flag) |
182 | { |
183 | struct kstat stat; |
184 | int error; |
185 | |
186 | error = vfs_fstatat(dfd, filename, stat: &stat, flags: flag); |
187 | if (error) |
188 | return error; |
189 | return cp_oldabi_stat64(stat: &stat, statbuf); |
190 | } |
191 | |
192 | struct oabi_flock64 { |
193 | short l_type; |
194 | short l_whence; |
195 | loff_t l_start; |
196 | loff_t l_len; |
197 | pid_t l_pid; |
198 | } __attribute__ ((packed,aligned(4))); |
199 | |
200 | static int get_oabi_flock(struct flock64 *kernel, struct oabi_flock64 __user *arg) |
201 | { |
202 | struct oabi_flock64 user; |
203 | |
204 | if (copy_from_user(to: &user, from: (struct oabi_flock64 __user *)arg, |
205 | n: sizeof(user))) |
206 | return -EFAULT; |
207 | |
208 | kernel->l_type = user.l_type; |
209 | kernel->l_whence = user.l_whence; |
210 | kernel->l_start = user.l_start; |
211 | kernel->l_len = user.l_len; |
212 | kernel->l_pid = user.l_pid; |
213 | |
214 | return 0; |
215 | } |
216 | |
217 | static int put_oabi_flock(struct flock64 *kernel, struct oabi_flock64 __user *arg) |
218 | { |
219 | struct oabi_flock64 user; |
220 | |
221 | user.l_type = kernel->l_type; |
222 | user.l_whence = kernel->l_whence; |
223 | user.l_start = kernel->l_start; |
224 | user.l_len = kernel->l_len; |
225 | user.l_pid = kernel->l_pid; |
226 | |
227 | if (copy_to_user(to: (struct oabi_flock64 __user *)arg, |
228 | from: &user, n: sizeof(user))) |
229 | return -EFAULT; |
230 | |
231 | return 0; |
232 | } |
233 | |
234 | asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, |
235 | unsigned long arg) |
236 | { |
237 | void __user *argp = (void __user *)arg; |
238 | struct fd f = fdget_raw(fd); |
239 | struct flock64 flock; |
240 | long err = -EBADF; |
241 | |
242 | if (!f.file) |
243 | goto out; |
244 | |
245 | switch (cmd) { |
246 | case F_GETLK64: |
247 | case F_OFD_GETLK: |
248 | err = security_file_fcntl(file: f.file, cmd, arg); |
249 | if (err) |
250 | break; |
251 | err = get_oabi_flock(kernel: &flock, arg: argp); |
252 | if (err) |
253 | break; |
254 | err = fcntl_getlk64(f.file, cmd, &flock); |
255 | if (!err) |
256 | err = put_oabi_flock(kernel: &flock, arg: argp); |
257 | break; |
258 | case F_SETLK64: |
259 | case F_SETLKW64: |
260 | case F_OFD_SETLK: |
261 | case F_OFD_SETLKW: |
262 | err = security_file_fcntl(file: f.file, cmd, arg); |
263 | if (err) |
264 | break; |
265 | err = get_oabi_flock(kernel: &flock, arg: argp); |
266 | if (err) |
267 | break; |
268 | err = fcntl_setlk64(fd, f.file, cmd, &flock); |
269 | break; |
270 | default: |
271 | err = sys_fcntl64(fd, cmd, arg); |
272 | break; |
273 | } |
274 | fdput(fd: f); |
275 | out: |
276 | return err; |
277 | } |
278 | |
279 | struct oabi_epoll_event { |
280 | __poll_t events; |
281 | __u64 data; |
282 | } __attribute__ ((packed,aligned(4))); |
283 | |
284 | #ifdef CONFIG_EPOLL |
285 | asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd, |
286 | struct oabi_epoll_event __user *event) |
287 | { |
288 | struct oabi_epoll_event user; |
289 | struct epoll_event kernel; |
290 | |
291 | if (ep_op_has_event(op) && |
292 | copy_from_user(to: &user, from: event, n: sizeof(user))) |
293 | return -EFAULT; |
294 | |
295 | kernel.events = user.events; |
296 | kernel.data = user.data; |
297 | |
298 | return do_epoll_ctl(epfd, op, fd, epds: &kernel, nonblock: false); |
299 | } |
300 | #else |
301 | asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd, |
302 | struct oabi_epoll_event __user *event) |
303 | { |
304 | return -EINVAL; |
305 | } |
306 | #endif |
307 | |
308 | struct epoll_event __user * |
309 | epoll_put_uevent(__poll_t revents, __u64 data, |
310 | struct epoll_event __user *uevent) |
311 | { |
312 | if (in_oabi_syscall()) { |
313 | struct oabi_epoll_event __user *oevent = (void __user *)uevent; |
314 | |
315 | if (__put_user(revents, &oevent->events) || |
316 | __put_user(data, &oevent->data)) |
317 | return NULL; |
318 | |
319 | return (void __user *)(oevent+1); |
320 | } |
321 | |
322 | if (__put_user(revents, &uevent->events) || |
323 | __put_user(data, &uevent->data)) |
324 | return NULL; |
325 | |
326 | return uevent+1; |
327 | } |
328 | |
329 | struct oabi_sembuf { |
330 | unsigned short sem_num; |
331 | short sem_op; |
332 | short sem_flg; |
333 | unsigned short __pad; |
334 | }; |
335 | |
336 | #define sc_semopm sem_ctls[2] |
337 | |
338 | #ifdef CONFIG_SYSVIPC |
339 | asmlinkage long sys_oabi_semtimedop(int semid, |
340 | struct oabi_sembuf __user *tsops, |
341 | unsigned nsops, |
342 | const struct old_timespec32 __user *timeout) |
343 | { |
344 | struct ipc_namespace *ns; |
345 | struct sembuf *sops; |
346 | long err; |
347 | int i; |
348 | |
349 | ns = current->nsproxy->ipc_ns; |
350 | if (nsops > ns->sc_semopm) |
351 | return -E2BIG; |
352 | if (nsops < 1 || nsops > SEMOPM) |
353 | return -EINVAL; |
354 | sops = kvmalloc_array(n: nsops, size: sizeof(*sops), GFP_KERNEL); |
355 | if (!sops) |
356 | return -ENOMEM; |
357 | err = 0; |
358 | for (i = 0; i < nsops; i++) { |
359 | struct oabi_sembuf osb; |
360 | err |= copy_from_user(to: &osb, from: tsops, n: sizeof(osb)); |
361 | sops[i].sem_num = osb.sem_num; |
362 | sops[i].sem_op = osb.sem_op; |
363 | sops[i].sem_flg = osb.sem_flg; |
364 | tsops++; |
365 | } |
366 | if (err) { |
367 | err = -EFAULT; |
368 | goto out; |
369 | } |
370 | |
371 | if (timeout) { |
372 | struct timespec64 ts; |
373 | err = get_old_timespec32(&ts, timeout); |
374 | if (err) |
375 | goto out; |
376 | err = __do_semtimedop(semid, tsems: sops, nsops, timeout: &ts, ns); |
377 | goto out; |
378 | } |
379 | err = __do_semtimedop(semid, tsems: sops, nsops, NULL, ns); |
380 | out: |
381 | kvfree(addr: sops); |
382 | return err; |
383 | } |
384 | |
385 | asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops, |
386 | unsigned nsops) |
387 | { |
388 | return sys_oabi_semtimedop(semid, tsops, nsops, NULL); |
389 | } |
390 | |
391 | asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third, |
392 | void __user *ptr, long fifth) |
393 | { |
394 | switch (call & 0xffff) { |
395 | case SEMOP: |
396 | return sys_oabi_semtimedop(semid: first, |
397 | tsops: (struct oabi_sembuf __user *)ptr, |
398 | nsops: second, NULL); |
399 | case SEMTIMEDOP: |
400 | return sys_oabi_semtimedop(semid: first, |
401 | tsops: (struct oabi_sembuf __user *)ptr, |
402 | nsops: second, |
403 | timeout: (const struct old_timespec32 __user *)fifth); |
404 | default: |
405 | return sys_ipc(call, first, second, third, ptr, fifth); |
406 | } |
407 | } |
408 | #else |
409 | asmlinkage long sys_oabi_semtimedop(int semid, |
410 | struct oabi_sembuf __user *tsops, |
411 | unsigned nsops, |
412 | const struct old_timespec32 __user *timeout) |
413 | { |
414 | return -ENOSYS; |
415 | } |
416 | |
417 | asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops, |
418 | unsigned nsops) |
419 | { |
420 | return -ENOSYS; |
421 | } |
422 | |
423 | asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third, |
424 | void __user *ptr, long fifth) |
425 | { |
426 | return -ENOSYS; |
427 | } |
428 | #endif |
429 | |
430 | asmlinkage long sys_oabi_bind(int fd, struct sockaddr __user *addr, int addrlen) |
431 | { |
432 | sa_family_t sa_family; |
433 | if (addrlen == 112 && |
434 | get_user(sa_family, &addr->sa_family) == 0 && |
435 | sa_family == AF_UNIX) |
436 | addrlen = 110; |
437 | return sys_bind(fd, addr, addrlen); |
438 | } |
439 | |
440 | asmlinkage long sys_oabi_connect(int fd, struct sockaddr __user *addr, int addrlen) |
441 | { |
442 | sa_family_t sa_family; |
443 | if (addrlen == 112 && |
444 | get_user(sa_family, &addr->sa_family) == 0 && |
445 | sa_family == AF_UNIX) |
446 | addrlen = 110; |
447 | return sys_connect(fd, addr, addrlen); |
448 | } |
449 | |
450 | asmlinkage long sys_oabi_sendto(int fd, void __user *buff, |
451 | size_t len, unsigned flags, |
452 | struct sockaddr __user *addr, |
453 | int addrlen) |
454 | { |
455 | sa_family_t sa_family; |
456 | if (addrlen == 112 && |
457 | get_user(sa_family, &addr->sa_family) == 0 && |
458 | sa_family == AF_UNIX) |
459 | addrlen = 110; |
460 | return sys_sendto(fd, buff, len, flags, addr, addrlen); |
461 | } |
462 | |
463 | asmlinkage long sys_oabi_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags) |
464 | { |
465 | struct sockaddr __user *addr; |
466 | int msg_namelen; |
467 | sa_family_t sa_family; |
468 | if (msg && |
469 | get_user(msg_namelen, &msg->msg_namelen) == 0 && |
470 | msg_namelen == 112 && |
471 | get_user(addr, &msg->msg_name) == 0 && |
472 | get_user(sa_family, &addr->sa_family) == 0 && |
473 | sa_family == AF_UNIX) |
474 | { |
475 | /* |
476 | * HACK ALERT: there is a limit to how much backward bending |
477 | * we should do for what is actually a transitional |
478 | * compatibility layer. This already has known flaws with |
479 | * a few ioctls that we don't intend to fix. Therefore |
480 | * consider this blatent hack as another one... and take care |
481 | * to run for cover. In most cases it will "just work fine". |
482 | * If it doesn't, well, tough. |
483 | */ |
484 | put_user(110, &msg->msg_namelen); |
485 | } |
486 | return sys_sendmsg(fd, msg, flags); |
487 | } |
488 | |
489 | asmlinkage long sys_oabi_socketcall(int call, unsigned long __user *args) |
490 | { |
491 | unsigned long r = -EFAULT, a[6]; |
492 | |
493 | switch (call) { |
494 | case SYS_BIND: |
495 | if (copy_from_user(to: a, from: args, n: 3 * sizeof(long)) == 0) |
496 | r = sys_oabi_bind(fd: a[0], addr: (struct sockaddr __user *)a[1], addrlen: a[2]); |
497 | break; |
498 | case SYS_CONNECT: |
499 | if (copy_from_user(to: a, from: args, n: 3 * sizeof(long)) == 0) |
500 | r = sys_oabi_connect(fd: a[0], addr: (struct sockaddr __user *)a[1], addrlen: a[2]); |
501 | break; |
502 | case SYS_SENDTO: |
503 | if (copy_from_user(to: a, from: args, n: 6 * sizeof(long)) == 0) |
504 | r = sys_oabi_sendto(fd: a[0], buff: (void __user *)a[1], len: a[2], flags: a[3], |
505 | addr: (struct sockaddr __user *)a[4], addrlen: a[5]); |
506 | break; |
507 | case SYS_SENDMSG: |
508 | if (copy_from_user(to: a, from: args, n: 3 * sizeof(long)) == 0) |
509 | r = sys_oabi_sendmsg(fd: a[0], msg: (struct user_msghdr __user *)a[1], flags: a[2]); |
510 | break; |
511 | default: |
512 | r = sys_socketcall(call, args); |
513 | } |
514 | |
515 | return r; |
516 | } |
517 | |