diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2014-09-06 06:18:07 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2014-09-06 06:58:18 -0400 |
| commit | 849151dd5481bc8acb1d287a299b5d6a4ca9f1c3 (patch) | |
| tree | e14c9ddf3bda4da1668d4c4c52a77d5e74aea293 | |
| parent | 40bea039593dfc7f3f9814dab844f6db43ae580b (diff) | |
compat: nanosleep: Clarify error handling
The error handling in compat_sys_nanosleep() is correct, but
completely non obvious. Document it and restrict it to the
-ERESTART_RESTARTBLOCK return value for clarity.
Reported-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | kernel/compat.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index 633394f442f8..ebb3c369d03d 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -226,7 +226,7 @@ static long compat_nanosleep_restart(struct restart_block *restart) | |||
| 226 | ret = hrtimer_nanosleep_restart(restart); | 226 | ret = hrtimer_nanosleep_restart(restart); |
| 227 | set_fs(oldfs); | 227 | set_fs(oldfs); |
| 228 | 228 | ||
| 229 | if (ret) { | 229 | if (ret == -ERESTART_RESTARTBLOCK) { |
| 230 | rmtp = restart->nanosleep.compat_rmtp; | 230 | rmtp = restart->nanosleep.compat_rmtp; |
| 231 | 231 | ||
| 232 | if (rmtp && compat_put_timespec(&rmt, rmtp)) | 232 | if (rmtp && compat_put_timespec(&rmt, rmtp)) |
| @@ -256,7 +256,26 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, | |||
| 256 | HRTIMER_MODE_REL, CLOCK_MONOTONIC); | 256 | HRTIMER_MODE_REL, CLOCK_MONOTONIC); |
| 257 | set_fs(oldfs); | 257 | set_fs(oldfs); |
| 258 | 258 | ||
| 259 | if (ret) { | 259 | /* |
| 260 | * hrtimer_nanosleep() can only return 0 or | ||
| 261 | * -ERESTART_RESTARTBLOCK here because: | ||
| 262 | * | ||
| 263 | * - we call it with HRTIMER_MODE_REL and therefor exclude the | ||
| 264 | * -ERESTARTNOHAND return path. | ||
| 265 | * | ||
| 266 | * - we supply the rmtp argument from the task stack (due to | ||
| 267 | * the necessary compat conversion. So the update cannot | ||
| 268 | * fail, which excludes the -EFAULT return path as well. If | ||
| 269 | * it fails nevertheless we have a bigger problem and wont | ||
| 270 | * reach this place anymore. | ||
| 271 | * | ||
| 272 | * - if the return value is 0, we do not have to update rmtp | ||
| 273 | * because there is no remaining time. | ||
| 274 | * | ||
| 275 | * We check for -ERESTART_RESTARTBLOCK nevertheless if the | ||
| 276 | * core implementation decides to return random nonsense. | ||
| 277 | */ | ||
| 278 | if (ret == -ERESTART_RESTARTBLOCK) { | ||
| 260 | struct restart_block *restart | 279 | struct restart_block *restart |
| 261 | = ¤t_thread_info()->restart_block; | 280 | = ¤t_thread_info()->restart_block; |
| 262 | 281 | ||
| @@ -266,7 +285,6 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, | |||
| 266 | if (rmtp && compat_put_timespec(&rmt, rmtp)) | 285 | if (rmtp && compat_put_timespec(&rmt, rmtp)) |
| 267 | return -EFAULT; | 286 | return -EFAULT; |
| 268 | } | 287 | } |
| 269 | |||
| 270 | return ret; | 288 | return ret; |
| 271 | } | 289 | } |
| 272 | 290 | ||
