@@ -766,22 +766,38 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
766
766
* which has a pointer to the sigset_t itself followed by a size_t containing
767
767
* the sigset size.
768
768
*/
769
+ struct sigset_argpack {
770
+ sigset_t __user * p ;
771
+ size_t size ;
772
+ };
773
+
774
+ static inline int get_sigset_argpack (struct sigset_argpack * to ,
775
+ struct sigset_argpack __user * from )
776
+ {
777
+ // the path is hot enough for overhead of copy_from_user() to matter
778
+ if (from ) {
779
+ if (!user_read_access_begin (from , sizeof (* from )))
780
+ return - EFAULT ;
781
+ unsafe_get_user (to -> p , & from -> p , Efault );
782
+ unsafe_get_user (to -> size , & from -> size , Efault );
783
+ user_read_access_end ();
784
+ }
785
+ return 0 ;
786
+ Efault :
787
+ user_access_end ();
788
+ return - EFAULT ;
789
+ }
790
+
769
791
SYSCALL_DEFINE6 (pselect6 , int , n , fd_set __user * , inp , fd_set __user * , outp ,
770
792
fd_set __user * , exp , struct __kernel_timespec __user * , tsp ,
771
793
void __user * , sig )
772
794
{
773
- size_t sigsetsize = 0 ;
774
- sigset_t __user * up = NULL ;
775
-
776
- if (sig ) {
777
- if (!access_ok (sig , sizeof (void * )+ sizeof (size_t ))
778
- || __get_user (up , (sigset_t __user * __user * )sig )
779
- || __get_user (sigsetsize ,
780
- (size_t __user * )(sig + sizeof (void * ))))
781
- return - EFAULT ;
782
- }
795
+ struct sigset_argpack x = {NULL , 0 };
796
+
797
+ if (get_sigset_argpack (& x , sig ))
798
+ return - EFAULT ;
783
799
784
- return do_pselect (n , inp , outp , exp , tsp , up , sigsetsize , PT_TIMESPEC );
800
+ return do_pselect (n , inp , outp , exp , tsp , x . p , x . size , PT_TIMESPEC );
785
801
}
786
802
787
803
#if defined(CONFIG_COMPAT_32BIT_TIME ) && !defined(CONFIG_64BIT )
@@ -790,18 +806,12 @@ SYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *,
790
806
fd_set __user * , exp , struct old_timespec32 __user * , tsp ,
791
807
void __user * , sig )
792
808
{
793
- size_t sigsetsize = 0 ;
794
- sigset_t __user * up = NULL ;
795
-
796
- if (sig ) {
797
- if (!access_ok (sig , sizeof (void * )+ sizeof (size_t ))
798
- || __get_user (up , (sigset_t __user * __user * )sig )
799
- || __get_user (sigsetsize ,
800
- (size_t __user * )(sig + sizeof (void * ))))
801
- return - EFAULT ;
802
- }
809
+ struct sigset_argpack x = {NULL , 0 };
810
+
811
+ if (get_sigset_argpack (& x , sig ))
812
+ return - EFAULT ;
803
813
804
- return do_pselect (n , inp , outp , exp , tsp , up , sigsetsize , PT_OLD_TIMESPEC );
814
+ return do_pselect (n , inp , outp , exp , tsp , x . p , x . size , PT_OLD_TIMESPEC );
805
815
}
806
816
807
817
#endif
@@ -1325,24 +1335,37 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
1325
1335
return poll_select_finish (& end_time , tsp , type , ret );
1326
1336
}
1327
1337
1338
+ struct compat_sigset_argpack {
1339
+ compat_uptr_t p ;
1340
+ compat_size_t size ;
1341
+ };
1342
+ static inline int get_compat_sigset_argpack (struct compat_sigset_argpack * to ,
1343
+ struct compat_sigset_argpack __user * from )
1344
+ {
1345
+ if (from ) {
1346
+ if (!user_read_access_begin (from , sizeof (* from )))
1347
+ return - EFAULT ;
1348
+ unsafe_get_user (to -> p , & from -> p , Efault );
1349
+ unsafe_get_user (to -> size , & from -> size , Efault );
1350
+ user_read_access_end ();
1351
+ }
1352
+ return 0 ;
1353
+ Efault :
1354
+ user_access_end ();
1355
+ return - EFAULT ;
1356
+ }
1357
+
1328
1358
COMPAT_SYSCALL_DEFINE6 (pselect6_time64 , int , n , compat_ulong_t __user * , inp ,
1329
1359
compat_ulong_t __user * , outp , compat_ulong_t __user * , exp ,
1330
1360
struct __kernel_timespec __user * , tsp , void __user * , sig )
1331
1361
{
1332
- compat_size_t sigsetsize = 0 ;
1333
- compat_uptr_t up = 0 ;
1334
-
1335
- if (sig ) {
1336
- if (!access_ok (sig ,
1337
- sizeof (compat_uptr_t )+ sizeof (compat_size_t )) ||
1338
- __get_user (up , (compat_uptr_t __user * )sig ) ||
1339
- __get_user (sigsetsize ,
1340
- (compat_size_t __user * )(sig + sizeof (up ))))
1341
- return - EFAULT ;
1342
- }
1362
+ struct compat_sigset_argpack x = {0 , 0 };
1363
+
1364
+ if (get_compat_sigset_argpack (& x , sig ))
1365
+ return - EFAULT ;
1343
1366
1344
- return do_compat_pselect (n , inp , outp , exp , tsp , compat_ptr (up ),
1345
- sigsetsize , PT_TIMESPEC );
1367
+ return do_compat_pselect (n , inp , outp , exp , tsp , compat_ptr (x . p ),
1368
+ x . size , PT_TIMESPEC );
1346
1369
}
1347
1370
1348
1371
#if defined(CONFIG_COMPAT_32BIT_TIME )
@@ -1351,20 +1374,13 @@ COMPAT_SYSCALL_DEFINE6(pselect6_time32, int, n, compat_ulong_t __user *, inp,
1351
1374
compat_ulong_t __user * , outp , compat_ulong_t __user * , exp ,
1352
1375
struct old_timespec32 __user * , tsp , void __user * , sig )
1353
1376
{
1354
- compat_size_t sigsetsize = 0 ;
1355
- compat_uptr_t up = 0 ;
1356
-
1357
- if (sig ) {
1358
- if (!access_ok (sig ,
1359
- sizeof (compat_uptr_t )+ sizeof (compat_size_t )) ||
1360
- __get_user (up , (compat_uptr_t __user * )sig ) ||
1361
- __get_user (sigsetsize ,
1362
- (compat_size_t __user * )(sig + sizeof (up ))))
1363
- return - EFAULT ;
1364
- }
1377
+ struct compat_sigset_argpack x = {0 , 0 };
1378
+
1379
+ if (get_compat_sigset_argpack (& x , sig ))
1380
+ return - EFAULT ;
1365
1381
1366
- return do_compat_pselect (n , inp , outp , exp , tsp , compat_ptr (up ),
1367
- sigsetsize , PT_OLD_TIMESPEC );
1382
+ return do_compat_pselect (n , inp , outp , exp , tsp , compat_ptr (x . p ),
1383
+ x . size , PT_OLD_TIMESPEC );
1368
1384
}
1369
1385
1370
1386
#endif
0 commit comments