.. | .. |
---|
| 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; |
---|