diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2019-01-02 07:28:47 -0500 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2019-02-06 18:13:27 -0500 |
| commit | 4d5f007eedb74d71a7bde2bff69b6a31ad8ab427 (patch) | |
| tree | 9704984d9137621c8bdbba2e1c86018e5d3c755f | |
| parent | 805089c2f77047d81f47ddc227435d606ceb180e (diff) | |
time: make adjtime compat handling available for 32 bit
We want to reuse the compat_timex handling on 32-bit architectures the
same way we are using the compat handling for timespec when moving to
64-bit time_t.
Move all definitions related to compat_timex out of the compat code
into the normal timekeeping code, along with a rename to old_timex32,
corresponding to the timespec/timeval structures, and make it controlled
by CONFIG_COMPAT_32BIT_TIME, which 32-bit architectures will then select.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
| -rw-r--r-- | include/linux/compat.h | 35 | ||||
| -rw-r--r-- | include/linux/time32.h | 32 | ||||
| -rw-r--r-- | kernel/compat.c | 64 | ||||
| -rw-r--r-- | kernel/time/posix-timers.c | 14 | ||||
| -rw-r--r-- | kernel/time/time.c | 70 |
5 files changed, 102 insertions, 113 deletions
diff --git a/include/linux/compat.h b/include/linux/compat.h index 056be0d03722..657ca6abd855 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
| @@ -132,37 +132,6 @@ struct compat_tms { | |||
| 132 | compat_clock_t tms_cstime; | 132 | compat_clock_t tms_cstime; |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | struct compat_timex { | ||
| 136 | compat_uint_t modes; | ||
| 137 | compat_long_t offset; | ||
| 138 | compat_long_t freq; | ||
| 139 | compat_long_t maxerror; | ||
| 140 | compat_long_t esterror; | ||
| 141 | compat_int_t status; | ||
| 142 | compat_long_t constant; | ||
| 143 | compat_long_t precision; | ||
| 144 | compat_long_t tolerance; | ||
| 145 | struct old_timeval32 time; | ||
| 146 | compat_long_t tick; | ||
| 147 | compat_long_t ppsfreq; | ||
| 148 | compat_long_t jitter; | ||
| 149 | compat_int_t shift; | ||
| 150 | compat_long_t stabil; | ||
| 151 | compat_long_t jitcnt; | ||
| 152 | compat_long_t calcnt; | ||
| 153 | compat_long_t errcnt; | ||
| 154 | compat_long_t stbcnt; | ||
| 155 | compat_int_t tai; | ||
| 156 | |||
| 157 | compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32; | ||
| 158 | compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32; | ||
| 159 | compat_int_t:32; compat_int_t:32; compat_int_t:32; | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct timex; | ||
| 163 | int compat_get_timex(struct timex *, const struct compat_timex __user *); | ||
| 164 | int compat_put_timex(struct compat_timex __user *, const struct timex *); | ||
| 165 | |||
| 166 | #define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) | 135 | #define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) |
| 167 | 136 | ||
| 168 | typedef struct { | 137 | typedef struct { |
| @@ -808,7 +777,7 @@ asmlinkage long compat_sys_gettimeofday(struct old_timeval32 __user *tv, | |||
| 808 | struct timezone __user *tz); | 777 | struct timezone __user *tz); |
| 809 | asmlinkage long compat_sys_settimeofday(struct old_timeval32 __user *tv, | 778 | asmlinkage long compat_sys_settimeofday(struct old_timeval32 __user *tv, |
| 810 | struct timezone __user *tz); | 779 | struct timezone __user *tz); |
| 811 | asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); | 780 | asmlinkage long compat_sys_adjtimex(struct old_timex32 __user *utp); |
| 812 | 781 | ||
| 813 | /* kernel/timer.c */ | 782 | /* kernel/timer.c */ |
| 814 | asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info); | 783 | asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info); |
| @@ -911,7 +880,7 @@ asmlinkage long compat_sys_open_by_handle_at(int mountdirfd, | |||
| 911 | struct file_handle __user *handle, | 880 | struct file_handle __user *handle, |
| 912 | int flags); | 881 | int flags); |
| 913 | asmlinkage long compat_sys_clock_adjtime(clockid_t which_clock, | 882 | asmlinkage long compat_sys_clock_adjtime(clockid_t which_clock, |
| 914 | struct compat_timex __user *tp); | 883 | struct old_timex32 __user *tp); |
| 915 | asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg, | 884 | asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg, |
| 916 | unsigned vlen, unsigned int flags); | 885 | unsigned vlen, unsigned int flags); |
| 917 | asmlinkage ssize_t compat_sys_process_vm_readv(compat_pid_t pid, | 886 | asmlinkage ssize_t compat_sys_process_vm_readv(compat_pid_t pid, |
diff --git a/include/linux/time32.h b/include/linux/time32.h index 118b9977080c..820a22e2b98b 100644 --- a/include/linux/time32.h +++ b/include/linux/time32.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/time64.h> | 12 | #include <linux/time64.h> |
| 13 | #include <linux/timex.h> | ||
| 13 | 14 | ||
| 14 | #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) | 15 | #define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) |
| 15 | 16 | ||
| @@ -35,13 +36,42 @@ struct old_utimbuf32 { | |||
| 35 | old_time32_t modtime; | 36 | old_time32_t modtime; |
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 39 | struct old_timex32 { | ||
| 40 | u32 modes; | ||
| 41 | s32 offset; | ||
| 42 | s32 freq; | ||
| 43 | s32 maxerror; | ||
| 44 | s32 esterror; | ||
| 45 | s32 status; | ||
| 46 | s32 constant; | ||
| 47 | s32 precision; | ||
| 48 | s32 tolerance; | ||
| 49 | struct old_timeval32 time; | ||
| 50 | s32 tick; | ||
| 51 | s32 ppsfreq; | ||
| 52 | s32 jitter; | ||
| 53 | s32 shift; | ||
| 54 | s32 stabil; | ||
| 55 | s32 jitcnt; | ||
| 56 | s32 calcnt; | ||
| 57 | s32 errcnt; | ||
| 58 | s32 stbcnt; | ||
| 59 | s32 tai; | ||
| 60 | |||
| 61 | s32:32; s32:32; s32:32; s32:32; | ||
| 62 | s32:32; s32:32; s32:32; s32:32; | ||
| 63 | s32:32; s32:32; s32:32; | ||
| 64 | }; | ||
| 65 | |||
| 38 | extern int get_old_timespec32(struct timespec64 *, const void __user *); | 66 | extern int get_old_timespec32(struct timespec64 *, const void __user *); |
| 39 | extern int put_old_timespec32(const struct timespec64 *, void __user *); | 67 | extern int put_old_timespec32(const struct timespec64 *, void __user *); |
| 40 | extern int get_old_itimerspec32(struct itimerspec64 *its, | 68 | extern int get_old_itimerspec32(struct itimerspec64 *its, |
| 41 | const struct old_itimerspec32 __user *uits); | 69 | const struct old_itimerspec32 __user *uits); |
| 42 | extern int put_old_itimerspec32(const struct itimerspec64 *its, | 70 | extern int put_old_itimerspec32(const struct itimerspec64 *its, |
| 43 | struct old_itimerspec32 __user *uits); | 71 | struct old_itimerspec32 __user *uits); |
| 44 | 72 | struct timex; | |
| 73 | int get_old_timex32(struct timex *, const struct old_timex32 __user *); | ||
| 74 | int put_old_timex32(struct old_timex32 __user *, const struct timex *); | ||
| 45 | 75 | ||
| 46 | #if __BITS_PER_LONG == 64 | 76 | #if __BITS_PER_LONG == 64 |
| 47 | 77 | ||
diff --git a/kernel/compat.c b/kernel/compat.c index f01affa17e22..d8a36c6ad7c9 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
| 21 | #include <linux/unistd.h> | 21 | #include <linux/unistd.h> |
| 22 | #include <linux/security.h> | 22 | #include <linux/security.h> |
| 23 | #include <linux/timex.h> | ||
| 24 | #include <linux/export.h> | 23 | #include <linux/export.h> |
| 25 | #include <linux/migrate.h> | 24 | #include <linux/migrate.h> |
| 26 | #include <linux/posix-timers.h> | 25 | #include <linux/posix-timers.h> |
| @@ -30,69 +29,6 @@ | |||
| 30 | 29 | ||
| 31 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
| 32 | 31 | ||
| 33 | int compat_get_timex(struct timex *txc, const struct compat_timex __user *utp) | ||
| 34 | { | ||
| 35 | struct compat_timex tx32; | ||
| 36 | |||
| 37 | memset(txc, 0, sizeof(struct timex)); | ||
| 38 | if (copy_from_user(&tx32, utp, sizeof(struct compat_timex))) | ||
| 39 | return -EFAULT; | ||
| 40 | |||
| 41 | txc->modes = tx32.modes; | ||
| 42 | txc->offset = tx32.offset; | ||
| 43 | txc->freq = tx32.freq; | ||
| 44 | txc->maxerror = tx32.maxerror; | ||
| 45 | txc->esterror = tx32.esterror; | ||
| 46 | txc->status = tx32.status; | ||
| 47 | txc->constant = tx32.constant; | ||
| 48 | txc->precision = tx32.precision; | ||
| 49 | txc->tolerance = tx32.tolerance; | ||
| 50 | txc->time.tv_sec = tx32.time.tv_sec; | ||
| 51 | txc->time.tv_usec = tx32.time.tv_usec; | ||
| 52 | txc->tick = tx32.tick; | ||
| 53 | txc->ppsfreq = tx32.ppsfreq; | ||
| 54 | txc->jitter = tx32.jitter; | ||
| 55 | txc->shift = tx32.shift; | ||
| 56 | txc->stabil = tx32.stabil; | ||
| 57 | txc->jitcnt = tx32.jitcnt; | ||
| 58 | txc->calcnt = tx32.calcnt; | ||
| 59 | txc->errcnt = tx32.errcnt; | ||
| 60 | txc->stbcnt = tx32.stbcnt; | ||
| 61 | |||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc) | ||
| 66 | { | ||
| 67 | struct compat_timex tx32; | ||
| 68 | |||
| 69 | memset(&tx32, 0, sizeof(struct compat_timex)); | ||
| 70 | tx32.modes = txc->modes; | ||
| 71 | tx32.offset = txc->offset; | ||
| 72 | tx32.freq = txc->freq; | ||
| 73 | tx32.maxerror = txc->maxerror; | ||
| 74 | tx32.esterror = txc->esterror; | ||
| 75 | tx32.status = txc->status; | ||
| 76 | tx32.constant = txc->constant; | ||
| 77 | tx32.precision = txc->precision; | ||
| 78 | tx32.tolerance = txc->tolerance; | ||
| 79 | tx32.time.tv_sec = txc->time.tv_sec; | ||
| 80 | tx32.time.tv_usec = txc->time.tv_usec; | ||
| 81 | tx32.tick = txc->tick; | ||
| 82 | tx32.ppsfreq = txc->ppsfreq; | ||
| 83 | tx32.jitter = txc->jitter; | ||
| 84 | tx32.shift = txc->shift; | ||
| 85 | tx32.stabil = txc->stabil; | ||
| 86 | tx32.jitcnt = txc->jitcnt; | ||
| 87 | tx32.calcnt = txc->calcnt; | ||
| 88 | tx32.errcnt = txc->errcnt; | ||
| 89 | tx32.stbcnt = txc->stbcnt; | ||
| 90 | tx32.tai = txc->tai; | ||
| 91 | if (copy_to_user(utp, &tx32, sizeof(struct compat_timex))) | ||
| 92 | return -EFAULT; | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int __compat_get_timeval(struct timeval *tv, const struct old_timeval32 __user *ctv) | 32 | static int __compat_get_timeval(struct timeval *tv, const struct old_timeval32 __user *ctv) |
| 97 | { | 33 | { |
| 98 | return (!access_ok(ctv, sizeof(*ctv)) || | 34 | return (!access_ok(ctv, sizeof(*ctv)) || |
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 0e84bb72a3da..8955f32f2a36 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c | |||
| @@ -1123,12 +1123,8 @@ COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, | |||
| 1123 | return err; | 1123 | return err; |
| 1124 | } | 1124 | } |
| 1125 | 1125 | ||
| 1126 | #endif | ||
| 1127 | |||
| 1128 | #ifdef CONFIG_COMPAT | ||
| 1129 | |||
| 1130 | COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, | 1126 | COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, |
| 1131 | struct compat_timex __user *, utp) | 1127 | struct old_timex32 __user *, utp) |
| 1132 | { | 1128 | { |
| 1133 | const struct k_clock *kc = clockid_to_kclock(which_clock); | 1129 | const struct k_clock *kc = clockid_to_kclock(which_clock); |
| 1134 | struct timex ktx; | 1130 | struct timex ktx; |
| @@ -1139,22 +1135,18 @@ COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, | |||
| 1139 | if (!kc->clock_adj) | 1135 | if (!kc->clock_adj) |
| 1140 | return -EOPNOTSUPP; | 1136 | return -EOPNOTSUPP; |
| 1141 | 1137 | ||
| 1142 | err = compat_get_timex(&ktx, utp); | 1138 | err = get_old_timex32(&ktx, utp); |
| 1143 | if (err) | 1139 | if (err) |
| 1144 | return err; | 1140 | return err; |
| 1145 | 1141 | ||
| 1146 | err = kc->clock_adj(which_clock, &ktx); | 1142 | err = kc->clock_adj(which_clock, &ktx); |
| 1147 | 1143 | ||
| 1148 | if (err >= 0) | 1144 | if (err >= 0) |
| 1149 | err = compat_put_timex(utp, &ktx); | 1145 | err = put_old_timex32(utp, &ktx); |
| 1150 | 1146 | ||
| 1151 | return err; | 1147 | return err; |
| 1152 | } | 1148 | } |
| 1153 | 1149 | ||
| 1154 | #endif | ||
| 1155 | |||
| 1156 | #ifdef CONFIG_COMPAT_32BIT_TIME | ||
| 1157 | |||
| 1158 | COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, | 1150 | COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, |
| 1159 | struct old_timespec32 __user *, tp) | 1151 | struct old_timespec32 __user *, tp) |
| 1160 | { | 1152 | { |
diff --git a/kernel/time/time.c b/kernel/time/time.c index 2edb5088a70b..2d013bc2b271 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c | |||
| @@ -278,20 +278,82 @@ SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) | |||
| 278 | return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret; | 278 | return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | #ifdef CONFIG_COMPAT | 281 | #ifdef CONFIG_COMPAT_32BIT_TIME |
| 282 | int get_old_timex32(struct timex *txc, const struct old_timex32 __user *utp) | ||
| 283 | { | ||
| 284 | struct old_timex32 tx32; | ||
| 285 | |||
| 286 | memset(txc, 0, sizeof(struct timex)); | ||
| 287 | if (copy_from_user(&tx32, utp, sizeof(struct old_timex32))) | ||
| 288 | return -EFAULT; | ||
| 289 | |||
| 290 | txc->modes = tx32.modes; | ||
| 291 | txc->offset = tx32.offset; | ||
| 292 | txc->freq = tx32.freq; | ||
| 293 | txc->maxerror = tx32.maxerror; | ||
| 294 | txc->esterror = tx32.esterror; | ||
| 295 | txc->status = tx32.status; | ||
| 296 | txc->constant = tx32.constant; | ||
| 297 | txc->precision = tx32.precision; | ||
| 298 | txc->tolerance = tx32.tolerance; | ||
| 299 | txc->time.tv_sec = tx32.time.tv_sec; | ||
| 300 | txc->time.tv_usec = tx32.time.tv_usec; | ||
| 301 | txc->tick = tx32.tick; | ||
| 302 | txc->ppsfreq = tx32.ppsfreq; | ||
| 303 | txc->jitter = tx32.jitter; | ||
| 304 | txc->shift = tx32.shift; | ||
| 305 | txc->stabil = tx32.stabil; | ||
| 306 | txc->jitcnt = tx32.jitcnt; | ||
| 307 | txc->calcnt = tx32.calcnt; | ||
| 308 | txc->errcnt = tx32.errcnt; | ||
| 309 | txc->stbcnt = tx32.stbcnt; | ||
| 310 | |||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | int put_old_timex32(struct old_timex32 __user *utp, const struct timex *txc) | ||
| 315 | { | ||
| 316 | struct old_timex32 tx32; | ||
| 317 | |||
| 318 | memset(&tx32, 0, sizeof(struct old_timex32)); | ||
| 319 | tx32.modes = txc->modes; | ||
| 320 | tx32.offset = txc->offset; | ||
| 321 | tx32.freq = txc->freq; | ||
| 322 | tx32.maxerror = txc->maxerror; | ||
| 323 | tx32.esterror = txc->esterror; | ||
| 324 | tx32.status = txc->status; | ||
| 325 | tx32.constant = txc->constant; | ||
| 326 | tx32.precision = txc->precision; | ||
| 327 | tx32.tolerance = txc->tolerance; | ||
| 328 | tx32.time.tv_sec = txc->time.tv_sec; | ||
| 329 | tx32.time.tv_usec = txc->time.tv_usec; | ||
| 330 | tx32.tick = txc->tick; | ||
| 331 | tx32.ppsfreq = txc->ppsfreq; | ||
| 332 | tx32.jitter = txc->jitter; | ||
| 333 | tx32.shift = txc->shift; | ||
| 334 | tx32.stabil = txc->stabil; | ||
| 335 | tx32.jitcnt = txc->jitcnt; | ||
| 336 | tx32.calcnt = txc->calcnt; | ||
| 337 | tx32.errcnt = txc->errcnt; | ||
| 338 | tx32.stbcnt = txc->stbcnt; | ||
| 339 | tx32.tai = txc->tai; | ||
| 340 | if (copy_to_user(utp, &tx32, sizeof(struct old_timex32))) | ||
| 341 | return -EFAULT; | ||
| 342 | return 0; | ||
| 343 | } | ||
| 282 | 344 | ||
| 283 | COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp) | 345 | COMPAT_SYSCALL_DEFINE1(adjtimex, struct old_timex32 __user *, utp) |
| 284 | { | 346 | { |
| 285 | struct timex txc; | 347 | struct timex txc; |
| 286 | int err, ret; | 348 | int err, ret; |
| 287 | 349 | ||
| 288 | err = compat_get_timex(&txc, utp); | 350 | err = get_old_timex32(&txc, utp); |
| 289 | if (err) | 351 | if (err) |
| 290 | return err; | 352 | return err; |
| 291 | 353 | ||
| 292 | ret = do_adjtimex(&txc); | 354 | ret = do_adjtimex(&txc); |
| 293 | 355 | ||
| 294 | err = compat_put_timex(utp, &txc); | 356 | err = put_old_timex32(utp, &txc); |
| 295 | if (err) | 357 | if (err) |
| 296 | return err; | 358 | return err; |
| 297 | 359 | ||
