Skip to content

Commit e024707

Browse files
deepa-hubarndb
authored andcommitted
pselect6: use __kernel_timespec
struct timespec is not y2038 safe. struct __kernel_timespec is the new y2038 safe structure for all syscalls that are using struct timespec. Update pselect interfaces to use struct __kernel_timespec. sigset_t also has different representations on 32 bit and 64 bit architectures. Hence, we need to support the following different syscalls: New y2038 safe syscalls: (Controlled by CONFIG_64BIT_TIME for 32 bit ABIs) Native 64 bit(unchanged) and native 32 bit : sys_pselect6 Compat : compat_sys_pselect6_time64 Older y2038 unsafe syscalls: (Controlled by CONFIG_32BIT_COMPAT_TIME for 32 bit ABIs) Native 32 bit : pselect6_time32 Compat : compat_sys_pselect6 Note that all other versions of select syscalls will not have y2038 safe versions. Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
1 parent 8bd27a3 commit e024707

3 files changed

Lines changed: 90 additions & 14 deletions

File tree

fs/select.c

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -729,16 +729,27 @@ SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
729729
}
730730

731731
static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
732-
fd_set __user *exp, struct timespec __user *tsp,
733-
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)
734735
{
735736
sigset_t ksigmask, sigsaved;
736737
struct timespec64 ts, end_time, *to = NULL;
737738
int ret;
738739

739740
if (tsp) {
740-
if (get_timespec64(&ts, tsp))
741-
return -EFAULT;
741+
switch (type) {
742+
case PT_TIMESPEC:
743+
if (get_timespec64(&ts, tsp))
744+
return -EFAULT;
745+
break;
746+
case PT_OLD_TIMESPEC:
747+
if (get_old_timespec32(&ts, tsp))
748+
return -EFAULT;
749+
break;
750+
default:
751+
BUG();
752+
}
742753

743754
to = &end_time;
744755
if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
@@ -750,7 +761,7 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
750761
return ret;
751762

752763
ret = core_sys_select(n, inp, outp, exp, to);
753-
ret = poll_select_copy_remaining(&end_time, tsp, PT_TIMESPEC, ret);
764+
ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
754765

755766
restore_user_sigmask(sigmask, &sigsaved);
756767

@@ -764,7 +775,27 @@ static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
764775
* the sigset size.
765776
*/
766777
SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
767-
fd_set __user *, exp, struct timespec __user *, tsp,
778+
fd_set __user *, exp, struct __kernel_timespec __user *, tsp,
779+
void __user *, sig)
780+
{
781+
size_t sigsetsize = 0;
782+
sigset_t __user *up = NULL;
783+
784+
if (sig) {
785+
if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t))
786+
|| __get_user(up, (sigset_t __user * __user *)sig)
787+
|| __get_user(sigsetsize,
788+
(size_t __user *)(sig+sizeof(void *))))
789+
return -EFAULT;
790+
}
791+
792+
return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize, PT_TIMESPEC);
793+
}
794+
795+
#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
796+
797+
SYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *, outp,
798+
fd_set __user *, exp, struct old_timespec32 __user *, tsp,
768799
void __user *, sig)
769800
{
770801
size_t sigsetsize = 0;
@@ -778,9 +809,11 @@ SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
778809
return -EFAULT;
779810
}
780811

781-
return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize);
812+
return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize, PT_OLD_TIMESPEC);
782813
}
783814

815+
#endif
816+
784817
#ifdef __ARCH_WANT_SYS_OLD_SELECT
785818
struct sel_arg_struct {
786819
unsigned long n;
@@ -1289,16 +1322,26 @@ COMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg)
12891322

12901323
static long do_compat_pselect(int n, compat_ulong_t __user *inp,
12911324
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
1292-
struct old_timespec32 __user *tsp, compat_sigset_t __user *sigmask,
1293-
compat_size_t sigsetsize)
1325+
void __user *tsp, compat_sigset_t __user *sigmask,
1326+
compat_size_t sigsetsize, enum poll_time_type type)
12941327
{
12951328
sigset_t ksigmask, sigsaved;
12961329
struct timespec64 ts, end_time, *to = NULL;
12971330
int ret;
12981331

12991332
if (tsp) {
1300-
if (get_old_timespec32(&ts, tsp))
1301-
return -EFAULT;
1333+
switch (type) {
1334+
case PT_OLD_TIMESPEC:
1335+
if (get_old_timespec32(&ts, tsp))
1336+
return -EFAULT;
1337+
break;
1338+
case PT_TIMESPEC:
1339+
if (get_timespec64(&ts, tsp))
1340+
return -EFAULT;
1341+
break;
1342+
default:
1343+
BUG();
1344+
}
13021345

13031346
to = &end_time;
13041347
if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
@@ -1310,13 +1353,35 @@ static long do_compat_pselect(int n, compat_ulong_t __user *inp,
13101353
return ret;
13111354

13121355
ret = compat_core_sys_select(n, inp, outp, exp, to);
1313-
ret = poll_select_copy_remaining(&end_time, tsp, PT_OLD_TIMESPEC, ret);
1356+
ret = poll_select_copy_remaining(&end_time, tsp, type, ret);
13141357

13151358
restore_user_sigmask(sigmask, &sigsaved);
13161359

13171360
return ret;
13181361
}
13191362

1363+
COMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp,
1364+
compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
1365+
struct __kernel_timespec __user *, tsp, void __user *, sig)
1366+
{
1367+
compat_size_t sigsetsize = 0;
1368+
compat_uptr_t up = 0;
1369+
1370+
if (sig) {
1371+
if (!access_ok(VERIFY_READ, sig,
1372+
sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
1373+
__get_user(up, (compat_uptr_t __user *)sig) ||
1374+
__get_user(sigsetsize,
1375+
(compat_size_t __user *)(sig+sizeof(up))))
1376+
return -EFAULT;
1377+
}
1378+
1379+
return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
1380+
sigsetsize, PT_TIMESPEC);
1381+
}
1382+
1383+
#if defined(CONFIG_COMPAT_32BIT_TIME)
1384+
13201385
COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp,
13211386
compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
13221387
struct old_timespec32 __user *, tsp, void __user *, sig)
@@ -1332,10 +1397,13 @@ COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp,
13321397
(compat_size_t __user *)(sig+sizeof(up))))
13331398
return -EFAULT;
13341399
}
1400+
13351401
return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
1336-
sigsetsize);
1402+
sigsetsize, PT_OLD_TIMESPEC);
13371403
}
13381404

1405+
#endif
1406+
13391407
#if defined(CONFIG_COMPAT_32BIT_TIME)
13401408
COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
13411409
unsigned int, nfds, struct old_timespec32 __user *, tsp,

include/linux/compat.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,11 @@ asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
647647
compat_ulong_t __user *exp,
648648
struct old_timespec32 __user *tsp,
649649
void __user *sig);
650+
asmlinkage long compat_sys_pselect6_time64(int n, compat_ulong_t __user *inp,
651+
compat_ulong_t __user *outp,
652+
compat_ulong_t __user *exp,
653+
struct __kernel_timespec __user *tsp,
654+
void __user *sig);
650655
asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
651656
unsigned int nfds,
652657
struct old_timespec32 __user *tsp,

include/linux/syscalls.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,10 @@ asmlinkage long sys_sendfile64(int out_fd, int in_fd,
466466

467467
/* fs/select.c */
468468
asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
469-
fd_set __user *, struct timespec __user *,
469+
fd_set __user *, struct __kernel_timespec __user *,
470+
void __user *);
471+
asmlinkage long sys_pselect6_time32(int, fd_set __user *, fd_set __user *,
472+
fd_set __user *, struct old_timespec32 __user *,
470473
void __user *);
471474
asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
472475
struct __kernel_timespec __user *, const sigset_t __user *,

0 commit comments

Comments
 (0)