| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * linux/kernel/compat.c |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * on 64 bit kernels. |
|---|
| 6 | 7 | * |
|---|
| 7 | 8 | * Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 11 | | - * published by the Free Software Foundation. |
|---|
| 12 | 9 | */ |
|---|
| 13 | 10 | |
|---|
| 14 | 11 | #include <linux/linkage.h> |
|---|
| .. | .. |
|---|
| 20 | 17 | #include <linux/syscalls.h> |
|---|
| 21 | 18 | #include <linux/unistd.h> |
|---|
| 22 | 19 | #include <linux/security.h> |
|---|
| 23 | | -#include <linux/timex.h> |
|---|
| 24 | 20 | #include <linux/export.h> |
|---|
| 25 | 21 | #include <linux/migrate.h> |
|---|
| 26 | 22 | #include <linux/posix-timers.h> |
|---|
| .. | .. |
|---|
| 29 | 25 | #include <linux/gfp.h> |
|---|
| 30 | 26 | |
|---|
| 31 | 27 | #include <linux/uaccess.h> |
|---|
| 32 | | - |
|---|
| 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 compat_timeval __user *ctv) |
|---|
| 97 | | -{ |
|---|
| 98 | | - return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || |
|---|
| 99 | | - __get_user(tv->tv_sec, &ctv->tv_sec) || |
|---|
| 100 | | - __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; |
|---|
| 101 | | -} |
|---|
| 102 | | - |
|---|
| 103 | | -static int __compat_put_timeval(const struct timeval *tv, struct compat_timeval __user *ctv) |
|---|
| 104 | | -{ |
|---|
| 105 | | - return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) || |
|---|
| 106 | | - __put_user(tv->tv_sec, &ctv->tv_sec) || |
|---|
| 107 | | - __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; |
|---|
| 108 | | -} |
|---|
| 109 | | - |
|---|
| 110 | | -static int __compat_get_timespec(struct timespec *ts, const struct compat_timespec __user *cts) |
|---|
| 111 | | -{ |
|---|
| 112 | | - return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || |
|---|
| 113 | | - __get_user(ts->tv_sec, &cts->tv_sec) || |
|---|
| 114 | | - __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
|---|
| 115 | | -} |
|---|
| 116 | | - |
|---|
| 117 | | -static int __compat_put_timespec(const struct timespec *ts, struct compat_timespec __user *cts) |
|---|
| 118 | | -{ |
|---|
| 119 | | - return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) || |
|---|
| 120 | | - __put_user(ts->tv_sec, &cts->tv_sec) || |
|---|
| 121 | | - __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; |
|---|
| 122 | | -} |
|---|
| 123 | | - |
|---|
| 124 | | -int compat_get_timeval(struct timeval *tv, const void __user *utv) |
|---|
| 125 | | -{ |
|---|
| 126 | | - if (COMPAT_USE_64BIT_TIME) |
|---|
| 127 | | - return copy_from_user(tv, utv, sizeof(*tv)) ? -EFAULT : 0; |
|---|
| 128 | | - else |
|---|
| 129 | | - return __compat_get_timeval(tv, utv); |
|---|
| 130 | | -} |
|---|
| 131 | | -EXPORT_SYMBOL_GPL(compat_get_timeval); |
|---|
| 132 | | - |
|---|
| 133 | | -int compat_put_timeval(const struct timeval *tv, void __user *utv) |
|---|
| 134 | | -{ |
|---|
| 135 | | - if (COMPAT_USE_64BIT_TIME) |
|---|
| 136 | | - return copy_to_user(utv, tv, sizeof(*tv)) ? -EFAULT : 0; |
|---|
| 137 | | - else |
|---|
| 138 | | - return __compat_put_timeval(tv, utv); |
|---|
| 139 | | -} |
|---|
| 140 | | -EXPORT_SYMBOL_GPL(compat_put_timeval); |
|---|
| 141 | | - |
|---|
| 142 | | -int compat_get_timespec(struct timespec *ts, const void __user *uts) |
|---|
| 143 | | -{ |
|---|
| 144 | | - if (COMPAT_USE_64BIT_TIME) |
|---|
| 145 | | - return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0; |
|---|
| 146 | | - else |
|---|
| 147 | | - return __compat_get_timespec(ts, uts); |
|---|
| 148 | | -} |
|---|
| 149 | | -EXPORT_SYMBOL_GPL(compat_get_timespec); |
|---|
| 150 | | - |
|---|
| 151 | | -int compat_put_timespec(const struct timespec *ts, void __user *uts) |
|---|
| 152 | | -{ |
|---|
| 153 | | - if (COMPAT_USE_64BIT_TIME) |
|---|
| 154 | | - return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0; |
|---|
| 155 | | - else |
|---|
| 156 | | - return __compat_put_timespec(ts, uts); |
|---|
| 157 | | -} |
|---|
| 158 | | -EXPORT_SYMBOL_GPL(compat_put_timespec); |
|---|
| 159 | | - |
|---|
| 160 | | -int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i) |
|---|
| 161 | | -{ |
|---|
| 162 | | - struct compat_itimerval v32; |
|---|
| 163 | | - |
|---|
| 164 | | - if (copy_from_user(&v32, i, sizeof(struct compat_itimerval))) |
|---|
| 165 | | - return -EFAULT; |
|---|
| 166 | | - o->it_interval.tv_sec = v32.it_interval.tv_sec; |
|---|
| 167 | | - o->it_interval.tv_usec = v32.it_interval.tv_usec; |
|---|
| 168 | | - o->it_value.tv_sec = v32.it_value.tv_sec; |
|---|
| 169 | | - o->it_value.tv_usec = v32.it_value.tv_usec; |
|---|
| 170 | | - return 0; |
|---|
| 171 | | -} |
|---|
| 172 | | - |
|---|
| 173 | | -int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i) |
|---|
| 174 | | -{ |
|---|
| 175 | | - struct compat_itimerval v32; |
|---|
| 176 | | - |
|---|
| 177 | | - v32.it_interval.tv_sec = i->it_interval.tv_sec; |
|---|
| 178 | | - v32.it_interval.tv_usec = i->it_interval.tv_usec; |
|---|
| 179 | | - v32.it_value.tv_sec = i->it_value.tv_sec; |
|---|
| 180 | | - v32.it_value.tv_usec = i->it_value.tv_usec; |
|---|
| 181 | | - return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0; |
|---|
| 182 | | -} |
|---|
| 183 | 28 | |
|---|
| 184 | 29 | #ifdef __ARCH_WANT_SYS_SIGPROCMASK |
|---|
| 185 | 30 | |
|---|
| .. | .. |
|---|
| 307 | 152 | if (len & (sizeof(compat_ulong_t)-1)) |
|---|
| 308 | 153 | return -EINVAL; |
|---|
| 309 | 154 | |
|---|
| 310 | | - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) |
|---|
| 155 | + if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) |
|---|
| 311 | 156 | return -ENOMEM; |
|---|
| 312 | 157 | |
|---|
| 313 | 158 | ret = sched_getaffinity(pid, mask); |
|---|
| .. | .. |
|---|
| 335 | 180 | const struct compat_sigevent __user *u_event) |
|---|
| 336 | 181 | { |
|---|
| 337 | 182 | memset(event, 0, sizeof(*event)); |
|---|
| 338 | | - return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) || |
|---|
| 183 | + return (!access_ok(u_event, sizeof(*u_event)) || |
|---|
| 339 | 184 | __get_user(event->sigev_value.sival_int, |
|---|
| 340 | 185 | &u_event->sigev_value.sival_int) || |
|---|
| 341 | 186 | __get_user(event->sigev_signo, &u_event->sigev_signo) || |
|---|
| .. | .. |
|---|
| 354 | 199 | bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); |
|---|
| 355 | 200 | nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); |
|---|
| 356 | 201 | |
|---|
| 357 | | - if (!user_access_begin(VERIFY_READ, umask, bitmap_size / 8)) |
|---|
| 202 | + if (!user_read_access_begin(umask, bitmap_size / 8)) |
|---|
| 358 | 203 | return -EFAULT; |
|---|
| 359 | 204 | |
|---|
| 360 | 205 | while (nr_compat_longs > 1) { |
|---|
| .. | .. |
|---|
| 366 | 211 | } |
|---|
| 367 | 212 | if (nr_compat_longs) |
|---|
| 368 | 213 | unsafe_get_user(*mask, umask++, Efault); |
|---|
| 369 | | - user_access_end(); |
|---|
| 214 | + user_read_access_end(); |
|---|
| 370 | 215 | return 0; |
|---|
| 371 | 216 | |
|---|
| 372 | 217 | Efault: |
|---|
| 373 | | - user_access_end(); |
|---|
| 218 | + user_read_access_end(); |
|---|
| 374 | 219 | return -EFAULT; |
|---|
| 375 | 220 | } |
|---|
| 376 | 221 | |
|---|
| .. | .. |
|---|
| 383 | 228 | bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); |
|---|
| 384 | 229 | nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); |
|---|
| 385 | 230 | |
|---|
| 386 | | - if (!user_access_begin(VERIFY_WRITE, umask, bitmap_size / 8)) |
|---|
| 231 | + if (!user_write_access_begin(umask, bitmap_size / 8)) |
|---|
| 387 | 232 | return -EFAULT; |
|---|
| 388 | 233 | |
|---|
| 389 | 234 | while (nr_compat_longs > 1) { |
|---|
| .. | .. |
|---|
| 394 | 239 | } |
|---|
| 395 | 240 | if (nr_compat_longs) |
|---|
| 396 | 241 | unsafe_put_user((compat_ulong_t)*mask, umask++, Efault); |
|---|
| 397 | | - user_access_end(); |
|---|
| 242 | + user_write_access_end(); |
|---|
| 398 | 243 | return 0; |
|---|
| 399 | 244 | Efault: |
|---|
| 400 | | - user_access_end(); |
|---|
| 245 | + user_write_access_end(); |
|---|
| 401 | 246 | return -EFAULT; |
|---|
| 402 | 247 | } |
|---|
| 403 | 248 | |
|---|
| .. | .. |
|---|
| 410 | 255 | return -EFAULT; |
|---|
| 411 | 256 | switch (_NSIG_WORDS) { |
|---|
| 412 | 257 | case 4: set->sig[3] = v.sig[6] | (((long)v.sig[7]) << 32 ); |
|---|
| 258 | + fallthrough; |
|---|
| 413 | 259 | case 3: set->sig[2] = v.sig[4] | (((long)v.sig[5]) << 32 ); |
|---|
| 260 | + fallthrough; |
|---|
| 414 | 261 | case 2: set->sig[1] = v.sig[2] | (((long)v.sig[3]) << 32 ); |
|---|
| 262 | + fallthrough; |
|---|
| 415 | 263 | case 1: set->sig[0] = v.sig[0] | (((long)v.sig[1]) << 32 ); |
|---|
| 416 | 264 | } |
|---|
| 417 | 265 | #else |
|---|
| .. | .. |
|---|
| 436 | 284 | |
|---|
| 437 | 285 | ptr = arch_compat_alloc_user_space(len); |
|---|
| 438 | 286 | |
|---|
| 439 | | - if (unlikely(!access_ok(VERIFY_WRITE, ptr, len))) |
|---|
| 287 | + if (unlikely(!access_ok(ptr, len))) |
|---|
| 440 | 288 | return NULL; |
|---|
| 441 | 289 | |
|---|
| 442 | 290 | return ptr; |
|---|