summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-04-08 18:10:56 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-04-17 12:52:24 -0400
commit80f0cce6aadebf6caf74d1f8ceb4b008ca72a9e9 (patch)
tree3ecede861f53ad46e44c0bd72a0353698aeeda33
parent0460b2a28b4b39cdd1ca9a420126353b27ebc954 (diff)
fcntl: move compat syscalls from compat.c
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/compat.c154
-rw-r--r--fs/fcntl.c157
2 files changed, 157 insertions, 154 deletions
diff --git a/fs/compat.c b/fs/compat.c
index b1c4bee28ede..000af26ef6b9 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -137,160 +137,6 @@ COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
137 return error; 137 return error;
138} 138}
139 139
140static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
141{
142 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
143 __get_user(kfl->l_type, &ufl->l_type) ||
144 __get_user(kfl->l_whence, &ufl->l_whence) ||
145 __get_user(kfl->l_start, &ufl->l_start) ||
146 __get_user(kfl->l_len, &ufl->l_len) ||
147 __get_user(kfl->l_pid, &ufl->l_pid))
148 return -EFAULT;
149 return 0;
150}
151
152static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
153{
154 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
155 __put_user(kfl->l_type, &ufl->l_type) ||
156 __put_user(kfl->l_whence, &ufl->l_whence) ||
157 __put_user(kfl->l_start, &ufl->l_start) ||
158 __put_user(kfl->l_len, &ufl->l_len) ||
159 __put_user(kfl->l_pid, &ufl->l_pid))
160 return -EFAULT;
161 return 0;
162}
163
164#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
165static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
166{
167 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
168 __get_user(kfl->l_type, &ufl->l_type) ||
169 __get_user(kfl->l_whence, &ufl->l_whence) ||
170 __get_user(kfl->l_start, &ufl->l_start) ||
171 __get_user(kfl->l_len, &ufl->l_len) ||
172 __get_user(kfl->l_pid, &ufl->l_pid))
173 return -EFAULT;
174 return 0;
175}
176#endif
177
178#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
179static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
180{
181 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
182 __put_user(kfl->l_type, &ufl->l_type) ||
183 __put_user(kfl->l_whence, &ufl->l_whence) ||
184 __put_user(kfl->l_start, &ufl->l_start) ||
185 __put_user(kfl->l_len, &ufl->l_len) ||
186 __put_user(kfl->l_pid, &ufl->l_pid))
187 return -EFAULT;
188 return 0;
189}
190#endif
191
192static unsigned int
193convert_fcntl_cmd(unsigned int cmd)
194{
195 switch (cmd) {
196 case F_GETLK64:
197 return F_GETLK;
198 case F_SETLK64:
199 return F_SETLK;
200 case F_SETLKW64:
201 return F_SETLKW;
202 }
203
204 return cmd;
205}
206
207COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
208 compat_ulong_t, arg)
209{
210 mm_segment_t old_fs;
211 struct flock f;
212 long ret;
213 unsigned int conv_cmd;
214
215 switch (cmd) {
216 case F_GETLK:
217 case F_SETLK:
218 case F_SETLKW:
219 ret = get_compat_flock(&f, compat_ptr(arg));
220 if (ret != 0)
221 break;
222 old_fs = get_fs();
223 set_fs(KERNEL_DS);
224 ret = sys_fcntl(fd, cmd, (unsigned long)&f);
225 set_fs(old_fs);
226 if (cmd == F_GETLK && ret == 0) {
227 /* GETLK was successful and we need to return the data...
228 * but it needs to fit in the compat structure.
229 * l_start shouldn't be too big, unless the original
230 * start + end is greater than COMPAT_OFF_T_MAX, in which
231 * case the app was asking for trouble, so we return
232 * -EOVERFLOW in that case.
233 * l_len could be too big, in which case we just truncate it,
234 * and only allow the app to see that part of the conflicting
235 * lock that might make sense to it anyway
236 */
237
238 if (f.l_start > COMPAT_OFF_T_MAX)
239 ret = -EOVERFLOW;
240 if (f.l_len > COMPAT_OFF_T_MAX)
241 f.l_len = COMPAT_OFF_T_MAX;
242 if (ret == 0)
243 ret = put_compat_flock(&f, compat_ptr(arg));
244 }
245 break;
246
247 case F_GETLK64:
248 case F_SETLK64:
249 case F_SETLKW64:
250 case F_OFD_GETLK:
251 case F_OFD_SETLK:
252 case F_OFD_SETLKW:
253 ret = get_compat_flock64(&f, compat_ptr(arg));
254 if (ret != 0)
255 break;
256 old_fs = get_fs();
257 set_fs(KERNEL_DS);
258 conv_cmd = convert_fcntl_cmd(cmd);
259 ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f);
260 set_fs(old_fs);
261 if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) {
262 /* need to return lock information - see above for commentary */
263 if (f.l_start > COMPAT_LOFF_T_MAX)
264 ret = -EOVERFLOW;
265 if (f.l_len > COMPAT_LOFF_T_MAX)
266 f.l_len = COMPAT_LOFF_T_MAX;
267 if (ret == 0)
268 ret = put_compat_flock64(&f, compat_ptr(arg));
269 }
270 break;
271
272 default:
273 ret = sys_fcntl(fd, cmd, arg);
274 break;
275 }
276 return ret;
277}
278
279COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
280 compat_ulong_t, arg)
281{
282 switch (cmd) {
283 case F_GETLK64:
284 case F_SETLK64:
285 case F_SETLKW64:
286 case F_OFD_GETLK:
287 case F_OFD_SETLK:
288 case F_OFD_SETLKW:
289 return -EINVAL;
290 }
291 return compat_sys_fcntl64(fd, cmd, arg);
292}
293
294/* A write operation does a read from user space and vice versa */ 140/* A write operation does a read from user space and vice versa */
295#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) 141#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
296 142
diff --git a/fs/fcntl.c b/fs/fcntl.c
index be8fbe289087..8bd81c2e89b2 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -23,6 +23,7 @@
23#include <linux/pid_namespace.h> 23#include <linux/pid_namespace.h>
24#include <linux/user_namespace.h> 24#include <linux/user_namespace.h>
25#include <linux/shmem_fs.h> 25#include <linux/shmem_fs.h>
26#include <linux/compat.h>
26 27
27#include <asm/poll.h> 28#include <asm/poll.h>
28#include <asm/siginfo.h> 29#include <asm/siginfo.h>
@@ -420,6 +421,162 @@ out:
420} 421}
421#endif 422#endif
422 423
424#ifdef CONFIG_COMPAT
425static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
426{
427 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
428 __get_user(kfl->l_type, &ufl->l_type) ||
429 __get_user(kfl->l_whence, &ufl->l_whence) ||
430 __get_user(kfl->l_start, &ufl->l_start) ||
431 __get_user(kfl->l_len, &ufl->l_len) ||
432 __get_user(kfl->l_pid, &ufl->l_pid))
433 return -EFAULT;
434 return 0;
435}
436
437static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
438{
439 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
440 __put_user(kfl->l_type, &ufl->l_type) ||
441 __put_user(kfl->l_whence, &ufl->l_whence) ||
442 __put_user(kfl->l_start, &ufl->l_start) ||
443 __put_user(kfl->l_len, &ufl->l_len) ||
444 __put_user(kfl->l_pid, &ufl->l_pid))
445 return -EFAULT;
446 return 0;
447}
448
449#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
450static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
451{
452 if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
453 __get_user(kfl->l_type, &ufl->l_type) ||
454 __get_user(kfl->l_whence, &ufl->l_whence) ||
455 __get_user(kfl->l_start, &ufl->l_start) ||
456 __get_user(kfl->l_len, &ufl->l_len) ||
457 __get_user(kfl->l_pid, &ufl->l_pid))
458 return -EFAULT;
459 return 0;
460}
461#endif
462
463#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
464static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
465{
466 if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
467 __put_user(kfl->l_type, &ufl->l_type) ||
468 __put_user(kfl->l_whence, &ufl->l_whence) ||
469 __put_user(kfl->l_start, &ufl->l_start) ||
470 __put_user(kfl->l_len, &ufl->l_len) ||
471 __put_user(kfl->l_pid, &ufl->l_pid))
472 return -EFAULT;
473 return 0;
474}
475#endif
476
477static unsigned int
478convert_fcntl_cmd(unsigned int cmd)
479{
480 switch (cmd) {
481 case F_GETLK64:
482 return F_GETLK;
483 case F_SETLK64:
484 return F_SETLK;
485 case F_SETLKW64:
486 return F_SETLKW;
487 }
488
489 return cmd;
490}
491
492COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
493 compat_ulong_t, arg)
494{
495 mm_segment_t old_fs;
496 struct flock f;
497 long ret;
498 unsigned int conv_cmd;
499
500 switch (cmd) {
501 case F_GETLK:
502 case F_SETLK:
503 case F_SETLKW:
504 ret = get_compat_flock(&f, compat_ptr(arg));
505 if (ret != 0)
506 break;
507 old_fs = get_fs();
508 set_fs(KERNEL_DS);
509 ret = sys_fcntl(fd, cmd, (unsigned long)&f);
510 set_fs(old_fs);
511 if (cmd == F_GETLK && ret == 0) {
512 /* GETLK was successful and we need to return the data...
513 * but it needs to fit in the compat structure.
514 * l_start shouldn't be too big, unless the original
515 * start + end is greater than COMPAT_OFF_T_MAX, in which
516 * case the app was asking for trouble, so we return
517 * -EOVERFLOW in that case.
518 * l_len could be too big, in which case we just truncate it,
519 * and only allow the app to see that part of the conflicting
520 * lock that might make sense to it anyway
521 */
522
523 if (f.l_start > COMPAT_OFF_T_MAX)
524 ret = -EOVERFLOW;
525 if (f.l_len > COMPAT_OFF_T_MAX)
526 f.l_len = COMPAT_OFF_T_MAX;
527 if (ret == 0)
528 ret = put_compat_flock(&f, compat_ptr(arg));
529 }
530 break;
531
532 case F_GETLK64:
533 case F_SETLK64:
534 case F_SETLKW64:
535 case F_OFD_GETLK:
536 case F_OFD_SETLK:
537 case F_OFD_SETLKW:
538 ret = get_compat_flock64(&f, compat_ptr(arg));
539 if (ret != 0)
540 break;
541 old_fs = get_fs();
542 set_fs(KERNEL_DS);
543 conv_cmd = convert_fcntl_cmd(cmd);
544 ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f);
545 set_fs(old_fs);
546 if ((conv_cmd == F_GETLK || conv_cmd == F_OFD_GETLK) && ret == 0) {
547 /* need to return lock information - see above for commentary */
548 if (f.l_start > COMPAT_LOFF_T_MAX)
549 ret = -EOVERFLOW;
550 if (f.l_len > COMPAT_LOFF_T_MAX)
551 f.l_len = COMPAT_LOFF_T_MAX;
552 if (ret == 0)
553 ret = put_compat_flock64(&f, compat_ptr(arg));
554 }
555 break;
556
557 default:
558 ret = sys_fcntl(fd, cmd, arg);
559 break;
560 }
561 return ret;
562}
563
564COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
565 compat_ulong_t, arg)
566{
567 switch (cmd) {
568 case F_GETLK64:
569 case F_SETLK64:
570 case F_SETLKW64:
571 case F_OFD_GETLK:
572 case F_OFD_SETLK:
573 case F_OFD_SETLKW:
574 return -EINVAL;
575 }
576 return compat_sys_fcntl64(fd, cmd, arg);
577}
578#endif
579
423/* Table to convert sigio signal codes into poll band bitmaps */ 580/* Table to convert sigio signal codes into poll band bitmaps */
424 581
425static const long band_table[NSIGPOLL] = { 582static const long band_table[NSIGPOLL] = {