.. | .. |
---|
97 | 97 | struct poll_table_page { |
---|
98 | 98 | struct poll_table_page * next; |
---|
99 | 99 | struct poll_table_entry * entry; |
---|
100 | | - struct poll_table_entry entries[0]; |
---|
| 100 | + struct poll_table_entry entries[]; |
---|
101 | 101 | }; |
---|
102 | 102 | |
---|
103 | 103 | #define POLL_TABLE_FULL(table) \ |
---|
.. | .. |
---|
287 | 287 | return 0; |
---|
288 | 288 | } |
---|
289 | 289 | |
---|
290 | | -static int poll_select_copy_remaining(struct timespec64 *end_time, |
---|
291 | | - void __user *p, |
---|
292 | | - int timeval, int ret) |
---|
| 290 | +enum poll_time_type { |
---|
| 291 | + PT_TIMEVAL = 0, |
---|
| 292 | + PT_OLD_TIMEVAL = 1, |
---|
| 293 | + PT_TIMESPEC = 2, |
---|
| 294 | + PT_OLD_TIMESPEC = 3, |
---|
| 295 | +}; |
---|
| 296 | + |
---|
| 297 | +static int poll_select_finish(struct timespec64 *end_time, |
---|
| 298 | + void __user *p, |
---|
| 299 | + enum poll_time_type pt_type, int ret) |
---|
293 | 300 | { |
---|
294 | 301 | struct timespec64 rts; |
---|
295 | | - struct timeval rtv; |
---|
| 302 | + |
---|
| 303 | + restore_saved_sigmask_unless(ret == -ERESTARTNOHAND); |
---|
296 | 304 | |
---|
297 | 305 | if (!p) |
---|
298 | 306 | return ret; |
---|
.. | .. |
---|
310 | 318 | rts.tv_sec = rts.tv_nsec = 0; |
---|
311 | 319 | |
---|
312 | 320 | |
---|
313 | | - if (timeval) { |
---|
314 | | - if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec)) |
---|
315 | | - memset(&rtv, 0, sizeof(rtv)); |
---|
316 | | - rtv.tv_sec = rts.tv_sec; |
---|
317 | | - rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; |
---|
| 321 | + switch (pt_type) { |
---|
| 322 | + case PT_TIMEVAL: |
---|
| 323 | + { |
---|
| 324 | + struct __kernel_old_timeval rtv; |
---|
318 | 325 | |
---|
319 | | - if (!copy_to_user(p, &rtv, sizeof(rtv))) |
---|
| 326 | + if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec)) |
---|
| 327 | + memset(&rtv, 0, sizeof(rtv)); |
---|
| 328 | + rtv.tv_sec = rts.tv_sec; |
---|
| 329 | + rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; |
---|
| 330 | + if (!copy_to_user(p, &rtv, sizeof(rtv))) |
---|
| 331 | + return ret; |
---|
| 332 | + } |
---|
| 333 | + break; |
---|
| 334 | + case PT_OLD_TIMEVAL: |
---|
| 335 | + { |
---|
| 336 | + struct old_timeval32 rtv; |
---|
| 337 | + |
---|
| 338 | + rtv.tv_sec = rts.tv_sec; |
---|
| 339 | + rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; |
---|
| 340 | + if (!copy_to_user(p, &rtv, sizeof(rtv))) |
---|
| 341 | + return ret; |
---|
| 342 | + } |
---|
| 343 | + break; |
---|
| 344 | + case PT_TIMESPEC: |
---|
| 345 | + if (!put_timespec64(&rts, p)) |
---|
320 | 346 | return ret; |
---|
321 | | - |
---|
322 | | - } else if (!put_timespec64(&rts, p)) |
---|
323 | | - return ret; |
---|
324 | | - |
---|
| 347 | + break; |
---|
| 348 | + case PT_OLD_TIMESPEC: |
---|
| 349 | + if (!put_old_timespec32(&rts, p)) |
---|
| 350 | + return ret; |
---|
| 351 | + break; |
---|
| 352 | + default: |
---|
| 353 | + BUG(); |
---|
| 354 | + } |
---|
325 | 355 | /* |
---|
326 | 356 | * If an application puts its timeval in read-only memory, we |
---|
327 | 357 | * don't want the Linux-specific update to the timeval to |
---|
.. | .. |
---|
353 | 383 | #define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long)) |
---|
354 | 384 | |
---|
355 | 385 | /* |
---|
356 | | - * We do a VERIFY_WRITE here even though we are only reading this time: |
---|
357 | | - * we'll write to it eventually.. |
---|
358 | | - * |
---|
359 | 386 | * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. |
---|
360 | 387 | */ |
---|
361 | 388 | static inline |
---|
.. | .. |
---|
674 | 701 | } |
---|
675 | 702 | |
---|
676 | 703 | static int kern_select(int n, fd_set __user *inp, fd_set __user *outp, |
---|
677 | | - fd_set __user *exp, struct timeval __user *tvp) |
---|
| 704 | + fd_set __user *exp, struct __kernel_old_timeval __user *tvp) |
---|
678 | 705 | { |
---|
679 | 706 | struct timespec64 end_time, *to = NULL; |
---|
680 | | - struct timeval tv; |
---|
| 707 | + struct __kernel_old_timeval tv; |
---|
681 | 708 | int ret; |
---|
682 | 709 | |
---|
683 | 710 | if (tvp) { |
---|
.. | .. |
---|
692 | 719 | } |
---|
693 | 720 | |
---|
694 | 721 | ret = core_sys_select(n, inp, outp, exp, to); |
---|
695 | | - ret = poll_select_copy_remaining(&end_time, tvp, 1, ret); |
---|
696 | | - |
---|
697 | | - return ret; |
---|
| 722 | + return poll_select_finish(&end_time, tvp, PT_TIMEVAL, ret); |
---|
698 | 723 | } |
---|
699 | 724 | |
---|
700 | 725 | SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, |
---|
701 | | - fd_set __user *, exp, struct timeval __user *, tvp) |
---|
| 726 | + fd_set __user *, exp, struct __kernel_old_timeval __user *, tvp) |
---|
702 | 727 | { |
---|
703 | 728 | return kern_select(n, inp, outp, exp, tvp); |
---|
704 | 729 | } |
---|
705 | 730 | |
---|
706 | 731 | static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, |
---|
707 | | - fd_set __user *exp, struct timespec __user *tsp, |
---|
708 | | - const sigset_t __user *sigmask, size_t sigsetsize) |
---|
| 732 | + fd_set __user *exp, void __user *tsp, |
---|
| 733 | + const sigset_t __user *sigmask, size_t sigsetsize, |
---|
| 734 | + enum poll_time_type type) |
---|
709 | 735 | { |
---|
710 | | - sigset_t ksigmask, sigsaved; |
---|
711 | 736 | struct timespec64 ts, end_time, *to = NULL; |
---|
712 | 737 | int ret; |
---|
713 | 738 | |
---|
714 | 739 | if (tsp) { |
---|
715 | | - if (get_timespec64(&ts, tsp)) |
---|
716 | | - return -EFAULT; |
---|
| 740 | + switch (type) { |
---|
| 741 | + case PT_TIMESPEC: |
---|
| 742 | + if (get_timespec64(&ts, tsp)) |
---|
| 743 | + return -EFAULT; |
---|
| 744 | + break; |
---|
| 745 | + case PT_OLD_TIMESPEC: |
---|
| 746 | + if (get_old_timespec32(&ts, tsp)) |
---|
| 747 | + return -EFAULT; |
---|
| 748 | + break; |
---|
| 749 | + default: |
---|
| 750 | + BUG(); |
---|
| 751 | + } |
---|
717 | 752 | |
---|
718 | 753 | to = &end_time; |
---|
719 | 754 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) |
---|
720 | 755 | return -EINVAL; |
---|
721 | 756 | } |
---|
722 | 757 | |
---|
723 | | - if (sigmask) { |
---|
724 | | - /* XXX: Don't preclude handling different sized sigset_t's. */ |
---|
725 | | - if (sigsetsize != sizeof(sigset_t)) |
---|
726 | | - return -EINVAL; |
---|
727 | | - if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) |
---|
728 | | - return -EFAULT; |
---|
729 | | - |
---|
730 | | - sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); |
---|
731 | | - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
---|
732 | | - } |
---|
| 758 | + ret = set_user_sigmask(sigmask, sigsetsize); |
---|
| 759 | + if (ret) |
---|
| 760 | + return ret; |
---|
733 | 761 | |
---|
734 | 762 | ret = core_sys_select(n, inp, outp, exp, to); |
---|
735 | | - ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
---|
736 | | - |
---|
737 | | - if (ret == -ERESTARTNOHAND) { |
---|
738 | | - /* |
---|
739 | | - * Don't restore the signal mask yet. Let do_signal() deliver |
---|
740 | | - * the signal on the way back to userspace, before the signal |
---|
741 | | - * mask is restored. |
---|
742 | | - */ |
---|
743 | | - if (sigmask) { |
---|
744 | | - memcpy(¤t->saved_sigmask, &sigsaved, |
---|
745 | | - sizeof(sigsaved)); |
---|
746 | | - set_restore_sigmask(); |
---|
747 | | - } |
---|
748 | | - } else if (sigmask) |
---|
749 | | - sigprocmask(SIG_SETMASK, &sigsaved, NULL); |
---|
750 | | - |
---|
751 | | - return ret; |
---|
| 763 | + return poll_select_finish(&end_time, tsp, type, ret); |
---|
752 | 764 | } |
---|
753 | 765 | |
---|
754 | 766 | /* |
---|
.. | .. |
---|
757 | 769 | * which has a pointer to the sigset_t itself followed by a size_t containing |
---|
758 | 770 | * the sigset size. |
---|
759 | 771 | */ |
---|
| 772 | +struct sigset_argpack { |
---|
| 773 | + sigset_t __user *p; |
---|
| 774 | + size_t size; |
---|
| 775 | +}; |
---|
| 776 | + |
---|
| 777 | +static inline int get_sigset_argpack(struct sigset_argpack *to, |
---|
| 778 | + struct sigset_argpack __user *from) |
---|
| 779 | +{ |
---|
| 780 | + // the path is hot enough for overhead of copy_from_user() to matter |
---|
| 781 | + if (from) { |
---|
| 782 | + if (!user_read_access_begin(from, sizeof(*from))) |
---|
| 783 | + return -EFAULT; |
---|
| 784 | + unsafe_get_user(to->p, &from->p, Efault); |
---|
| 785 | + unsafe_get_user(to->size, &from->size, Efault); |
---|
| 786 | + user_read_access_end(); |
---|
| 787 | + } |
---|
| 788 | + return 0; |
---|
| 789 | +Efault: |
---|
| 790 | + user_access_end(); |
---|
| 791 | + return -EFAULT; |
---|
| 792 | +} |
---|
| 793 | + |
---|
760 | 794 | SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp, |
---|
761 | | - fd_set __user *, exp, struct timespec __user *, tsp, |
---|
| 795 | + fd_set __user *, exp, struct __kernel_timespec __user *, tsp, |
---|
762 | 796 | void __user *, sig) |
---|
763 | 797 | { |
---|
764 | | - size_t sigsetsize = 0; |
---|
765 | | - sigset_t __user *up = NULL; |
---|
| 798 | + struct sigset_argpack x = {NULL, 0}; |
---|
766 | 799 | |
---|
767 | | - if (sig) { |
---|
768 | | - if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t)) |
---|
769 | | - || __get_user(up, (sigset_t __user * __user *)sig) |
---|
770 | | - || __get_user(sigsetsize, |
---|
771 | | - (size_t __user *)(sig+sizeof(void *)))) |
---|
772 | | - return -EFAULT; |
---|
773 | | - } |
---|
| 800 | + if (get_sigset_argpack(&x, sig)) |
---|
| 801 | + return -EFAULT; |
---|
774 | 802 | |
---|
775 | | - return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize); |
---|
| 803 | + return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_TIMESPEC); |
---|
776 | 804 | } |
---|
| 805 | + |
---|
| 806 | +#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) |
---|
| 807 | + |
---|
| 808 | +SYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *, outp, |
---|
| 809 | + fd_set __user *, exp, struct old_timespec32 __user *, tsp, |
---|
| 810 | + void __user *, sig) |
---|
| 811 | +{ |
---|
| 812 | + struct sigset_argpack x = {NULL, 0}; |
---|
| 813 | + |
---|
| 814 | + if (get_sigset_argpack(&x, sig)) |
---|
| 815 | + return -EFAULT; |
---|
| 816 | + |
---|
| 817 | + return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_OLD_TIMESPEC); |
---|
| 818 | +} |
---|
| 819 | + |
---|
| 820 | +#endif |
---|
777 | 821 | |
---|
778 | 822 | #ifdef __ARCH_WANT_SYS_OLD_SELECT |
---|
779 | 823 | struct sel_arg_struct { |
---|
780 | 824 | unsigned long n; |
---|
781 | 825 | fd_set __user *inp, *outp, *exp; |
---|
782 | | - struct timeval __user *tvp; |
---|
| 826 | + struct __kernel_old_timeval __user *tvp; |
---|
783 | 827 | }; |
---|
784 | 828 | |
---|
785 | 829 | SYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg) |
---|
.. | .. |
---|
795 | 839 | struct poll_list { |
---|
796 | 840 | struct poll_list *next; |
---|
797 | 841 | int len; |
---|
798 | | - struct pollfd entries[0]; |
---|
| 842 | + struct pollfd entries[]; |
---|
799 | 843 | }; |
---|
800 | 844 | |
---|
801 | 845 | #define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd)) |
---|
.. | .. |
---|
891 | 935 | if (!count) { |
---|
892 | 936 | count = wait->error; |
---|
893 | 937 | if (signal_pending(current)) |
---|
894 | | - count = -EINTR; |
---|
| 938 | + count = -ERESTARTNOHAND; |
---|
895 | 939 | } |
---|
896 | 940 | if (count || timed_out) |
---|
897 | 941 | break; |
---|
.. | .. |
---|
930 | 974 | struct timespec64 *end_time) |
---|
931 | 975 | { |
---|
932 | 976 | struct poll_wqueues table; |
---|
933 | | - int err = -EFAULT, fdcount, len, size; |
---|
| 977 | + int err = -EFAULT, fdcount, len; |
---|
934 | 978 | /* Allocate small arguments on the stack to save memory and be |
---|
935 | 979 | faster - use long to make sure the buffer is aligned properly |
---|
936 | 980 | on 64 bit archs to avoid unaligned access */ |
---|
.. | .. |
---|
958 | 1002 | break; |
---|
959 | 1003 | |
---|
960 | 1004 | len = min(todo, POLLFD_PER_PAGE); |
---|
961 | | - size = sizeof(struct poll_list) + sizeof(struct pollfd) * len; |
---|
962 | | - walk = walk->next = kmalloc(size, GFP_KERNEL); |
---|
| 1005 | + walk = walk->next = kmalloc(struct_size(walk, entries, len), |
---|
| 1006 | + GFP_KERNEL); |
---|
963 | 1007 | if (!walk) { |
---|
964 | 1008 | err = -ENOMEM; |
---|
965 | 1009 | goto out_fds; |
---|
.. | .. |
---|
970 | 1014 | fdcount = do_poll(head, &table, end_time); |
---|
971 | 1015 | poll_freewait(&table); |
---|
972 | 1016 | |
---|
| 1017 | + if (!user_write_access_begin(ufds, nfds * sizeof(*ufds))) |
---|
| 1018 | + goto out_fds; |
---|
| 1019 | + |
---|
973 | 1020 | for (walk = head; walk; walk = walk->next) { |
---|
974 | 1021 | struct pollfd *fds = walk->entries; |
---|
975 | 1022 | int j; |
---|
976 | 1023 | |
---|
977 | | - for (j = 0; j < walk->len; j++, ufds++) |
---|
978 | | - if (__put_user(fds[j].revents, &ufds->revents)) |
---|
979 | | - goto out_fds; |
---|
| 1024 | + for (j = walk->len; j; fds++, ufds++, j--) |
---|
| 1025 | + unsafe_put_user(fds->revents, &ufds->revents, Efault); |
---|
980 | 1026 | } |
---|
| 1027 | + user_write_access_end(); |
---|
981 | 1028 | |
---|
982 | 1029 | err = fdcount; |
---|
983 | 1030 | out_fds: |
---|
.. | .. |
---|
989 | 1036 | } |
---|
990 | 1037 | |
---|
991 | 1038 | return err; |
---|
| 1039 | + |
---|
| 1040 | +Efault: |
---|
| 1041 | + user_write_access_end(); |
---|
| 1042 | + err = -EFAULT; |
---|
| 1043 | + goto out_fds; |
---|
992 | 1044 | } |
---|
993 | 1045 | |
---|
994 | 1046 | static long do_restart_poll(struct restart_block *restart_block) |
---|
.. | .. |
---|
1006 | 1058 | |
---|
1007 | 1059 | ret = do_sys_poll(ufds, nfds, to); |
---|
1008 | 1060 | |
---|
1009 | | - if (ret == -EINTR) |
---|
| 1061 | + if (ret == -ERESTARTNOHAND) |
---|
1010 | 1062 | ret = set_restart_fn(restart_block, do_restart_poll); |
---|
1011 | 1063 | |
---|
1012 | 1064 | return ret; |
---|
.. | .. |
---|
1026 | 1078 | |
---|
1027 | 1079 | ret = do_sys_poll(ufds, nfds, to); |
---|
1028 | 1080 | |
---|
1029 | | - if (ret == -EINTR) { |
---|
| 1081 | + if (ret == -ERESTARTNOHAND) { |
---|
1030 | 1082 | struct restart_block *restart_block; |
---|
1031 | 1083 | |
---|
1032 | 1084 | restart_block = ¤t->restart_block; |
---|
.. | .. |
---|
1046 | 1098 | } |
---|
1047 | 1099 | |
---|
1048 | 1100 | SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, |
---|
1049 | | - struct timespec __user *, tsp, const sigset_t __user *, sigmask, |
---|
| 1101 | + struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask, |
---|
1050 | 1102 | size_t, sigsetsize) |
---|
1051 | 1103 | { |
---|
1052 | | - sigset_t ksigmask, sigsaved; |
---|
1053 | 1104 | struct timespec64 ts, end_time, *to = NULL; |
---|
1054 | 1105 | int ret; |
---|
1055 | 1106 | |
---|
.. | .. |
---|
1062 | 1113 | return -EINVAL; |
---|
1063 | 1114 | } |
---|
1064 | 1115 | |
---|
1065 | | - if (sigmask) { |
---|
1066 | | - /* XXX: Don't preclude handling different sized sigset_t's. */ |
---|
1067 | | - if (sigsetsize != sizeof(sigset_t)) |
---|
1068 | | - return -EINVAL; |
---|
1069 | | - if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) |
---|
1070 | | - return -EFAULT; |
---|
1071 | | - |
---|
1072 | | - sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); |
---|
1073 | | - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
---|
1074 | | - } |
---|
| 1116 | + ret = set_user_sigmask(sigmask, sigsetsize); |
---|
| 1117 | + if (ret) |
---|
| 1118 | + return ret; |
---|
1075 | 1119 | |
---|
1076 | 1120 | ret = do_sys_poll(ufds, nfds, to); |
---|
1077 | | - |
---|
1078 | | - /* We can restart this syscall, usually */ |
---|
1079 | | - if (ret == -EINTR) { |
---|
1080 | | - /* |
---|
1081 | | - * Don't restore the signal mask yet. Let do_signal() deliver |
---|
1082 | | - * the signal on the way back to userspace, before the signal |
---|
1083 | | - * mask is restored. |
---|
1084 | | - */ |
---|
1085 | | - if (sigmask) { |
---|
1086 | | - memcpy(¤t->saved_sigmask, &sigsaved, |
---|
1087 | | - sizeof(sigsaved)); |
---|
1088 | | - set_restore_sigmask(); |
---|
1089 | | - } |
---|
1090 | | - ret = -ERESTARTNOHAND; |
---|
1091 | | - } else if (sigmask) |
---|
1092 | | - sigprocmask(SIG_SETMASK, &sigsaved, NULL); |
---|
1093 | | - |
---|
1094 | | - ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); |
---|
1095 | | - |
---|
1096 | | - return ret; |
---|
| 1121 | + return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret); |
---|
1097 | 1122 | } |
---|
| 1123 | + |
---|
| 1124 | +#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT) |
---|
| 1125 | + |
---|
| 1126 | +SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds, |
---|
| 1127 | + struct old_timespec32 __user *, tsp, const sigset_t __user *, sigmask, |
---|
| 1128 | + size_t, sigsetsize) |
---|
| 1129 | +{ |
---|
| 1130 | + struct timespec64 ts, end_time, *to = NULL; |
---|
| 1131 | + int ret; |
---|
| 1132 | + |
---|
| 1133 | + if (tsp) { |
---|
| 1134 | + if (get_old_timespec32(&ts, tsp)) |
---|
| 1135 | + return -EFAULT; |
---|
| 1136 | + |
---|
| 1137 | + to = &end_time; |
---|
| 1138 | + if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) |
---|
| 1139 | + return -EINVAL; |
---|
| 1140 | + } |
---|
| 1141 | + |
---|
| 1142 | + ret = set_user_sigmask(sigmask, sigsetsize); |
---|
| 1143 | + if (ret) |
---|
| 1144 | + return ret; |
---|
| 1145 | + |
---|
| 1146 | + ret = do_sys_poll(ufds, nfds, to); |
---|
| 1147 | + return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret); |
---|
| 1148 | +} |
---|
| 1149 | +#endif |
---|
1098 | 1150 | |
---|
1099 | 1151 | #ifdef CONFIG_COMPAT |
---|
1100 | 1152 | #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) |
---|
1101 | | - |
---|
1102 | | -static |
---|
1103 | | -int compat_poll_select_copy_remaining(struct timespec64 *end_time, void __user *p, |
---|
1104 | | - int timeval, int ret) |
---|
1105 | | -{ |
---|
1106 | | - struct timespec64 ts; |
---|
1107 | | - |
---|
1108 | | - if (!p) |
---|
1109 | | - return ret; |
---|
1110 | | - |
---|
1111 | | - if (current->personality & STICKY_TIMEOUTS) |
---|
1112 | | - goto sticky; |
---|
1113 | | - |
---|
1114 | | - /* No update for zero timeout */ |
---|
1115 | | - if (!end_time->tv_sec && !end_time->tv_nsec) |
---|
1116 | | - return ret; |
---|
1117 | | - |
---|
1118 | | - ktime_get_ts64(&ts); |
---|
1119 | | - ts = timespec64_sub(*end_time, ts); |
---|
1120 | | - if (ts.tv_sec < 0) |
---|
1121 | | - ts.tv_sec = ts.tv_nsec = 0; |
---|
1122 | | - |
---|
1123 | | - if (timeval) { |
---|
1124 | | - struct compat_timeval rtv; |
---|
1125 | | - |
---|
1126 | | - rtv.tv_sec = ts.tv_sec; |
---|
1127 | | - rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC; |
---|
1128 | | - |
---|
1129 | | - if (!copy_to_user(p, &rtv, sizeof(rtv))) |
---|
1130 | | - return ret; |
---|
1131 | | - } else { |
---|
1132 | | - if (!compat_put_timespec64(&ts, p)) |
---|
1133 | | - return ret; |
---|
1134 | | - } |
---|
1135 | | - /* |
---|
1136 | | - * If an application puts its timeval in read-only memory, we |
---|
1137 | | - * don't want the Linux-specific update to the timeval to |
---|
1138 | | - * cause a fault after the select has completed |
---|
1139 | | - * successfully. However, because we're not updating the |
---|
1140 | | - * timeval, we can't restart the system call. |
---|
1141 | | - */ |
---|
1142 | | - |
---|
1143 | | -sticky: |
---|
1144 | | - if (ret == -ERESTARTNOHAND) |
---|
1145 | | - ret = -EINTR; |
---|
1146 | | - return ret; |
---|
1147 | | -} |
---|
1148 | 1153 | |
---|
1149 | 1154 | /* |
---|
1150 | 1155 | * Ooo, nasty. We need here to frob 32-bit unsigned longs to |
---|
.. | .. |
---|
1258 | 1263 | |
---|
1259 | 1264 | static int do_compat_select(int n, compat_ulong_t __user *inp, |
---|
1260 | 1265 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, |
---|
1261 | | - struct compat_timeval __user *tvp) |
---|
| 1266 | + struct old_timeval32 __user *tvp) |
---|
1262 | 1267 | { |
---|
1263 | 1268 | struct timespec64 end_time, *to = NULL; |
---|
1264 | | - struct compat_timeval tv; |
---|
| 1269 | + struct old_timeval32 tv; |
---|
1265 | 1270 | int ret; |
---|
1266 | 1271 | |
---|
1267 | 1272 | if (tvp) { |
---|
.. | .. |
---|
1276 | 1281 | } |
---|
1277 | 1282 | |
---|
1278 | 1283 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
---|
1279 | | - ret = compat_poll_select_copy_remaining(&end_time, tvp, 1, ret); |
---|
1280 | | - |
---|
1281 | | - return ret; |
---|
| 1284 | + return poll_select_finish(&end_time, tvp, PT_OLD_TIMEVAL, ret); |
---|
1282 | 1285 | } |
---|
1283 | 1286 | |
---|
1284 | 1287 | COMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp, |
---|
1285 | 1288 | compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, |
---|
1286 | | - struct compat_timeval __user *, tvp) |
---|
| 1289 | + struct old_timeval32 __user *, tvp) |
---|
1287 | 1290 | { |
---|
1288 | 1291 | return do_compat_select(n, inp, outp, exp, tvp); |
---|
1289 | 1292 | } |
---|
.. | .. |
---|
1308 | 1311 | |
---|
1309 | 1312 | static long do_compat_pselect(int n, compat_ulong_t __user *inp, |
---|
1310 | 1313 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, |
---|
1311 | | - struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, |
---|
1312 | | - compat_size_t sigsetsize) |
---|
| 1314 | + void __user *tsp, compat_sigset_t __user *sigmask, |
---|
| 1315 | + compat_size_t sigsetsize, enum poll_time_type type) |
---|
1313 | 1316 | { |
---|
1314 | | - sigset_t ksigmask, sigsaved; |
---|
1315 | 1317 | struct timespec64 ts, end_time, *to = NULL; |
---|
1316 | 1318 | int ret; |
---|
1317 | 1319 | |
---|
1318 | 1320 | if (tsp) { |
---|
1319 | | - if (compat_get_timespec64(&ts, tsp)) |
---|
1320 | | - return -EFAULT; |
---|
| 1321 | + switch (type) { |
---|
| 1322 | + case PT_OLD_TIMESPEC: |
---|
| 1323 | + if (get_old_timespec32(&ts, tsp)) |
---|
| 1324 | + return -EFAULT; |
---|
| 1325 | + break; |
---|
| 1326 | + case PT_TIMESPEC: |
---|
| 1327 | + if (get_timespec64(&ts, tsp)) |
---|
| 1328 | + return -EFAULT; |
---|
| 1329 | + break; |
---|
| 1330 | + default: |
---|
| 1331 | + BUG(); |
---|
| 1332 | + } |
---|
1321 | 1333 | |
---|
1322 | 1334 | to = &end_time; |
---|
1323 | 1335 | if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) |
---|
1324 | 1336 | return -EINVAL; |
---|
1325 | 1337 | } |
---|
1326 | 1338 | |
---|
1327 | | - if (sigmask) { |
---|
1328 | | - if (sigsetsize != sizeof(compat_sigset_t)) |
---|
1329 | | - return -EINVAL; |
---|
1330 | | - if (get_compat_sigset(&ksigmask, sigmask)) |
---|
1331 | | - return -EFAULT; |
---|
1332 | | - |
---|
1333 | | - sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); |
---|
1334 | | - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
---|
1335 | | - } |
---|
| 1339 | + ret = set_compat_user_sigmask(sigmask, sigsetsize); |
---|
| 1340 | + if (ret) |
---|
| 1341 | + return ret; |
---|
1336 | 1342 | |
---|
1337 | 1343 | ret = compat_core_sys_select(n, inp, outp, exp, to); |
---|
1338 | | - ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret); |
---|
1339 | | - |
---|
1340 | | - if (ret == -ERESTARTNOHAND) { |
---|
1341 | | - /* |
---|
1342 | | - * Don't restore the signal mask yet. Let do_signal() deliver |
---|
1343 | | - * the signal on the way back to userspace, before the signal |
---|
1344 | | - * mask is restored. |
---|
1345 | | - */ |
---|
1346 | | - if (sigmask) { |
---|
1347 | | - memcpy(¤t->saved_sigmask, &sigsaved, |
---|
1348 | | - sizeof(sigsaved)); |
---|
1349 | | - set_restore_sigmask(); |
---|
1350 | | - } |
---|
1351 | | - } else if (sigmask) |
---|
1352 | | - sigprocmask(SIG_SETMASK, &sigsaved, NULL); |
---|
1353 | | - |
---|
1354 | | - return ret; |
---|
| 1344 | + return poll_select_finish(&end_time, tsp, type, ret); |
---|
1355 | 1345 | } |
---|
1356 | 1346 | |
---|
1357 | | -COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp, |
---|
1358 | | - compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, |
---|
1359 | | - struct compat_timespec __user *, tsp, void __user *, sig) |
---|
| 1347 | +struct compat_sigset_argpack { |
---|
| 1348 | + compat_uptr_t p; |
---|
| 1349 | + compat_size_t size; |
---|
| 1350 | +}; |
---|
| 1351 | +static inline int get_compat_sigset_argpack(struct compat_sigset_argpack *to, |
---|
| 1352 | + struct compat_sigset_argpack __user *from) |
---|
1360 | 1353 | { |
---|
1361 | | - compat_size_t sigsetsize = 0; |
---|
1362 | | - compat_uptr_t up = 0; |
---|
1363 | | - |
---|
1364 | | - if (sig) { |
---|
1365 | | - if (!access_ok(VERIFY_READ, sig, |
---|
1366 | | - sizeof(compat_uptr_t)+sizeof(compat_size_t)) || |
---|
1367 | | - __get_user(up, (compat_uptr_t __user *)sig) || |
---|
1368 | | - __get_user(sigsetsize, |
---|
1369 | | - (compat_size_t __user *)(sig+sizeof(up)))) |
---|
| 1354 | + if (from) { |
---|
| 1355 | + if (!user_read_access_begin(from, sizeof(*from))) |
---|
1370 | 1356 | return -EFAULT; |
---|
| 1357 | + unsafe_get_user(to->p, &from->p, Efault); |
---|
| 1358 | + unsafe_get_user(to->size, &from->size, Efault); |
---|
| 1359 | + user_read_access_end(); |
---|
1371 | 1360 | } |
---|
1372 | | - return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), |
---|
1373 | | - sigsetsize); |
---|
| 1361 | + return 0; |
---|
| 1362 | +Efault: |
---|
| 1363 | + user_access_end(); |
---|
| 1364 | + return -EFAULT; |
---|
1374 | 1365 | } |
---|
1375 | 1366 | |
---|
1376 | | -COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, |
---|
1377 | | - unsigned int, nfds, struct compat_timespec __user *, tsp, |
---|
| 1367 | +COMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp, |
---|
| 1368 | + compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, |
---|
| 1369 | + struct __kernel_timespec __user *, tsp, void __user *, sig) |
---|
| 1370 | +{ |
---|
| 1371 | + struct compat_sigset_argpack x = {0, 0}; |
---|
| 1372 | + |
---|
| 1373 | + if (get_compat_sigset_argpack(&x, sig)) |
---|
| 1374 | + return -EFAULT; |
---|
| 1375 | + |
---|
| 1376 | + return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p), |
---|
| 1377 | + x.size, PT_TIMESPEC); |
---|
| 1378 | +} |
---|
| 1379 | + |
---|
| 1380 | +#if defined(CONFIG_COMPAT_32BIT_TIME) |
---|
| 1381 | + |
---|
| 1382 | +COMPAT_SYSCALL_DEFINE6(pselect6_time32, int, n, compat_ulong_t __user *, inp, |
---|
| 1383 | + compat_ulong_t __user *, outp, compat_ulong_t __user *, exp, |
---|
| 1384 | + struct old_timespec32 __user *, tsp, void __user *, sig) |
---|
| 1385 | +{ |
---|
| 1386 | + struct compat_sigset_argpack x = {0, 0}; |
---|
| 1387 | + |
---|
| 1388 | + if (get_compat_sigset_argpack(&x, sig)) |
---|
| 1389 | + return -EFAULT; |
---|
| 1390 | + |
---|
| 1391 | + return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p), |
---|
| 1392 | + x.size, PT_OLD_TIMESPEC); |
---|
| 1393 | +} |
---|
| 1394 | + |
---|
| 1395 | +#endif |
---|
| 1396 | + |
---|
| 1397 | +#if defined(CONFIG_COMPAT_32BIT_TIME) |
---|
| 1398 | +COMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, |
---|
| 1399 | + unsigned int, nfds, struct old_timespec32 __user *, tsp, |
---|
1378 | 1400 | const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) |
---|
1379 | 1401 | { |
---|
1380 | | - sigset_t ksigmask, sigsaved; |
---|
1381 | 1402 | struct timespec64 ts, end_time, *to = NULL; |
---|
1382 | 1403 | int ret; |
---|
1383 | 1404 | |
---|
1384 | 1405 | if (tsp) { |
---|
1385 | | - if (compat_get_timespec64(&ts, tsp)) |
---|
| 1406 | + if (get_old_timespec32(&ts, tsp)) |
---|
1386 | 1407 | return -EFAULT; |
---|
1387 | 1408 | |
---|
1388 | 1409 | to = &end_time; |
---|
.. | .. |
---|
1390 | 1411 | return -EINVAL; |
---|
1391 | 1412 | } |
---|
1392 | 1413 | |
---|
1393 | | - if (sigmask) { |
---|
1394 | | - if (sigsetsize != sizeof(compat_sigset_t)) |
---|
1395 | | - return -EINVAL; |
---|
1396 | | - if (get_compat_sigset(&ksigmask, sigmask)) |
---|
1397 | | - return -EFAULT; |
---|
1398 | | - |
---|
1399 | | - sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); |
---|
1400 | | - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); |
---|
1401 | | - } |
---|
| 1414 | + ret = set_compat_user_sigmask(sigmask, sigsetsize); |
---|
| 1415 | + if (ret) |
---|
| 1416 | + return ret; |
---|
1402 | 1417 | |
---|
1403 | 1418 | ret = do_sys_poll(ufds, nfds, to); |
---|
1404 | | - |
---|
1405 | | - /* We can restart this syscall, usually */ |
---|
1406 | | - if (ret == -EINTR) { |
---|
1407 | | - /* |
---|
1408 | | - * Don't restore the signal mask yet. Let do_signal() deliver |
---|
1409 | | - * the signal on the way back to userspace, before the signal |
---|
1410 | | - * mask is restored. |
---|
1411 | | - */ |
---|
1412 | | - if (sigmask) { |
---|
1413 | | - memcpy(¤t->saved_sigmask, &sigsaved, |
---|
1414 | | - sizeof(sigsaved)); |
---|
1415 | | - set_restore_sigmask(); |
---|
1416 | | - } |
---|
1417 | | - ret = -ERESTARTNOHAND; |
---|
1418 | | - } else if (sigmask) |
---|
1419 | | - sigprocmask(SIG_SETMASK, &sigsaved, NULL); |
---|
1420 | | - |
---|
1421 | | - ret = compat_poll_select_copy_remaining(&end_time, tsp, 0, ret); |
---|
1422 | | - |
---|
1423 | | - return ret; |
---|
| 1419 | + return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret); |
---|
1424 | 1420 | } |
---|
1425 | 1421 | #endif |
---|
| 1422 | + |
---|
| 1423 | +/* New compat syscall for 64 bit time_t*/ |
---|
| 1424 | +COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, |
---|
| 1425 | + unsigned int, nfds, struct __kernel_timespec __user *, tsp, |
---|
| 1426 | + const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) |
---|
| 1427 | +{ |
---|
| 1428 | + struct timespec64 ts, end_time, *to = NULL; |
---|
| 1429 | + int ret; |
---|
| 1430 | + |
---|
| 1431 | + if (tsp) { |
---|
| 1432 | + if (get_timespec64(&ts, tsp)) |
---|
| 1433 | + return -EFAULT; |
---|
| 1434 | + |
---|
| 1435 | + to = &end_time; |
---|
| 1436 | + if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) |
---|
| 1437 | + return -EINVAL; |
---|
| 1438 | + } |
---|
| 1439 | + |
---|
| 1440 | + ret = set_compat_user_sigmask(sigmask, sigsetsize); |
---|
| 1441 | + if (ret) |
---|
| 1442 | + return ret; |
---|
| 1443 | + |
---|
| 1444 | + ret = do_sys_poll(ufds, nfds, to); |
---|
| 1445 | + return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret); |
---|
| 1446 | +} |
---|
| 1447 | + |
---|
| 1448 | +#endif |
---|