Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull vdso timer fixes from Thomas Gleixner:
"A series of commits to deal with the regression caused by the generic
VDSO implementation.

The usage of clock_gettime64() for 32bit compat fallback syscalls
caused seccomp filters to kill innocent processes because they only
allow clock_gettime().

Handle the compat syscalls with clock_gettime() as before, which is
not a functional problem for the VDSO as the legacy compat application
interface is not y2038 safe anyway. It's just extra fallback code
which needs to be implemented on every architecture.

It's opt in for now so that it does not break the compile of already
converted architectures in linux-next. Once these are fixed, the
#ifdeffery goes away.

So much for trying to be smart and reuse code..."

* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
arm64: compat: vdso: Use legacy syscalls as fallback
x86/vdso/32: Use 32bit syscall fallback
lib/vdso/32: Provide legacy syscall fallbacks
lib/vdso: Move fallback invocation to the callers
lib/vdso/32: Remove inconsistent NULL pointer checks

+123 -32
+40
arch/arm64/include/asm/vdso/compat_gettimeofday.h
··· 16 16 17 17 #define VDSO_HAS_CLOCK_GETRES 1 18 18 19 + #define VDSO_HAS_32BIT_FALLBACK 1 20 + 19 21 static __always_inline 20 22 int gettimeofday_fallback(struct __kernel_old_timeval *_tv, 21 23 struct timezone *_tz) ··· 54 52 } 55 53 56 54 static __always_inline 55 + long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) 56 + { 57 + register struct old_timespec32 *ts asm("r1") = _ts; 58 + register clockid_t clkid asm("r0") = _clkid; 59 + register long ret asm ("r0"); 60 + register long nr asm("r7") = __NR_compat_clock_gettime; 61 + 62 + asm volatile( 63 + " swi #0\n" 64 + : "=r" (ret) 65 + : "r" (clkid), "r" (ts), "r" (nr) 66 + : "memory"); 67 + 68 + return ret; 69 + } 70 + 71 + static __always_inline 57 72 int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) 58 73 { 59 74 register struct __kernel_timespec *ts asm("r1") = _ts; 60 75 register clockid_t clkid asm("r0") = _clkid; 61 76 register long ret asm ("r0"); 62 77 register long nr asm("r7") = __NR_compat_clock_getres_time64; 78 + 79 + /* The checks below are required for ABI consistency with arm */ 80 + if ((_clkid >= MAX_CLOCKS) && (_ts == NULL)) 81 + return -EINVAL; 82 + 83 + asm volatile( 84 + " swi #0\n" 85 + : "=r" (ret) 86 + : "r" (clkid), "r" (ts), "r" (nr) 87 + : "memory"); 88 + 89 + return ret; 90 + } 91 + 92 + static __always_inline 93 + int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) 94 + { 95 + register struct old_timespec32 *ts asm("r1") = _ts; 96 + register clockid_t clkid asm("r0") = _clkid; 97 + register long ret asm ("r0"); 98 + register long nr asm("r7") = __NR_compat_clock_getres; 63 99 64 100 /* The checks below are required for ABI consistency with arm */ 65 101 if ((_clkid >= MAX_CLOCKS) && (_ts == NULL))
+36
arch/x86/include/asm/vdso/gettimeofday.h
··· 96 96 97 97 #else 98 98 99 + #define VDSO_HAS_32BIT_FALLBACK 1 100 + 99 101 static __always_inline 100 102 long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) 101 103 { ··· 110 108 "mov %%edx, %%ebx \n" 111 109 : "=a" (ret), "=m" (*_ts) 112 110 : "0" (__NR_clock_gettime64), [clock] "g" (_clkid), "c" (_ts) 111 + : "edx"); 112 + 113 + return ret; 114 + } 115 + 116 + static __always_inline 117 + long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) 118 + { 119 + long ret; 120 + 121 + asm ( 122 + "mov %%ebx, %%edx \n" 123 + "mov %[clock], %%ebx \n" 124 + "call __kernel_vsyscall \n" 125 + "mov %%edx, %%ebx \n" 126 + : "=a" (ret), "=m" (*_ts) 127 + : "0" (__NR_clock_gettime), [clock] "g" (_clkid), "c" (_ts) 113 128 : "edx"); 114 129 115 130 return ret; ··· 162 143 "mov %%edx, %%ebx \n" 163 144 : "=a" (ret), "=m" (*_ts) 164 145 : "0" (__NR_clock_getres_time64), [clock] "g" (_clkid), "c" (_ts) 146 + : "edx"); 147 + 148 + return ret; 149 + } 150 + 151 + static __always_inline 152 + long clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) 153 + { 154 + long ret; 155 + 156 + asm ( 157 + "mov %%ebx, %%edx \n" 158 + "mov %[clock], %%ebx \n" 159 + "call __kernel_vsyscall \n" 160 + "mov %%edx, %%ebx \n" 161 + : "=a" (ret), "=m" (*_ts) 162 + : "0" (__NR_clock_getres), [clock] "g" (_clkid), "c" (_ts) 165 163 : "edx"); 166 164 167 165 return ret;
+47 -32
lib/vdso/gettimeofday.c
··· 51 51 ns = vdso_ts->nsec; 52 52 last = vd->cycle_last; 53 53 if (unlikely((s64)cycles < 0)) 54 - return clock_gettime_fallback(clk, ts); 54 + return -1; 55 55 56 56 ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult); 57 57 ns >>= vd->shift; ··· 82 82 } 83 83 84 84 static __maybe_unused int 85 - __cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) 85 + __cvdso_clock_gettime_common(clockid_t clock, struct __kernel_timespec *ts) 86 86 { 87 87 const struct vdso_data *vd = __arch_get_vdso_data(); 88 88 u32 msk; 89 89 90 90 /* Check for negative values or invalid clocks */ 91 91 if (unlikely((u32) clock >= MAX_CLOCKS)) 92 - goto fallback; 92 + return -1; 93 93 94 94 /* 95 95 * Convert the clockid to a bitmask and use it to check which ··· 104 104 } else if (msk & VDSO_RAW) { 105 105 return do_hres(&vd[CS_RAW], clock, ts); 106 106 } 107 + return -1; 108 + } 107 109 108 - fallback: 109 - return clock_gettime_fallback(clock, ts); 110 + static __maybe_unused int 111 + __cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) 112 + { 113 + int ret = __cvdso_clock_gettime_common(clock, ts); 114 + 115 + if (unlikely(ret)) 116 + return clock_gettime_fallback(clock, ts); 117 + return 0; 110 118 } 111 119 112 120 static __maybe_unused int ··· 123 115 struct __kernel_timespec ts; 124 116 int ret; 125 117 126 - if (res == NULL) 127 - goto fallback; 118 + ret = __cvdso_clock_gettime_common(clock, &ts); 128 119 129 - ret = __cvdso_clock_gettime(clock, &ts); 120 + #ifdef VDSO_HAS_32BIT_FALLBACK 121 + if (unlikely(ret)) 122 + return clock_gettime32_fallback(clock, res); 123 + #else 124 + if (unlikely(ret)) 125 + ret = clock_gettime_fallback(clock, &ts); 126 + #endif 130 127 131 - if (ret == 0) { 128 + if (likely(!ret)) { 132 129 res->tv_sec = ts.tv_sec; 133 130 res->tv_nsec = ts.tv_nsec; 134 131 } 135 - 136 132 return ret; 137 - 138 - fallback: 139 - return clock_gettime_fallback(clock, (struct __kernel_timespec *)res); 140 133 } 141 134 142 135 static __maybe_unused int ··· 178 169 179 170 #ifdef VDSO_HAS_CLOCK_GETRES 180 171 static __maybe_unused 181 - int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) 172 + int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res) 182 173 { 183 174 const struct vdso_data *vd = __arch_get_vdso_data(); 184 - u64 ns; 175 + u64 hrtimer_res; 185 176 u32 msk; 186 - u64 hrtimer_res = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res); 177 + u64 ns; 187 178 188 179 /* Check for negative values or invalid clocks */ 189 180 if (unlikely((u32) clock >= MAX_CLOCKS)) 190 - goto fallback; 181 + return -1; 191 182 183 + hrtimer_res = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res); 192 184 /* 193 185 * Convert the clockid to a bitmask and use it to check which 194 186 * clocks are handled in the VDSO directly. ··· 211 201 */ 212 202 ns = hrtimer_res; 213 203 } else { 214 - goto fallback; 204 + return -1; 215 205 } 216 206 217 - if (res) { 218 - res->tv_sec = 0; 219 - res->tv_nsec = ns; 220 - } 207 + res->tv_sec = 0; 208 + res->tv_nsec = ns; 221 209 222 210 return 0; 211 + } 223 212 224 - fallback: 225 - return clock_getres_fallback(clock, res); 213 + int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) 214 + { 215 + int ret = __cvdso_clock_getres_common(clock, res); 216 + 217 + if (unlikely(ret)) 218 + return clock_getres_fallback(clock, res); 219 + return 0; 226 220 } 227 221 228 222 static __maybe_unused int ··· 235 221 struct __kernel_timespec ts; 236 222 int ret; 237 223 238 - if (res == NULL) 239 - goto fallback; 224 + ret = __cvdso_clock_getres_common(clock, &ts); 240 225 241 - ret = __cvdso_clock_getres(clock, &ts); 226 + #ifdef VDSO_HAS_32BIT_FALLBACK 227 + if (unlikely(ret)) 228 + return clock_getres32_fallback(clock, res); 229 + #else 230 + if (unlikely(ret)) 231 + ret = clock_getres_fallback(clock, &ts); 232 + #endif 242 233 243 - if (ret == 0) { 234 + if (likely(!ret)) { 244 235 res->tv_sec = ts.tv_sec; 245 236 res->tv_nsec = ts.tv_nsec; 246 237 } 247 - 248 238 return ret; 249 - 250 - fallback: 251 - return clock_getres_fallback(clock, (struct __kernel_timespec *)res); 252 239 } 253 240 #endif /* VDSO_HAS_CLOCK_GETRES */