1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/kernel/compat.c 4 * 5 * Kernel compatibililty routines for e.g. 32 bit syscall support 6 * on 64 bit kernels. 7 * 8 * Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation 9 */ 10 11 #include <linux/linkage.h> 12 #include <linux/compat.h> 13 #include <linux/errno.h> 14 #include <linux/time.h> 15 #include <linux/signal.h> 16 #include <linux/sched.h> /* for MAX_SCHEDULE_TIMEOUT */ 17 #include <linux/syscalls.h> 18 #include <linux/unistd.h> 19 #include <linux/security.h> 20 #include <linux/export.h> 21 #include <linux/migrate.h> 22 #include <linux/posix-timers.h> 23 #include <linux/times.h> 24 #include <linux/ptrace.h> 25 #include <linux/gfp.h> 26 27 #include <linux/uaccess.h> 28 29 static int __compat_get_timeval(struct timeval *tv, const struct old_timeval32 __user *ctv) 30 { 31 return (!access_ok(ctv, sizeof(*ctv)) || 32 __get_user(tv->tv_sec, &ctv->tv_sec) || 33 __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; 34 } 35 36 static int __compat_put_timeval(const struct timeval *tv, struct old_timeval32 __user *ctv) 37 { 38 return (!access_ok(ctv, sizeof(*ctv)) || 39 __put_user(tv->tv_sec, &ctv->tv_sec) || 40 __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; 41 } 42 43 static int __compat_get_timespec(struct timespec *ts, const struct old_timespec32 __user *cts) 44 { 45 return (!access_ok(cts, sizeof(*cts)) || 46 __get_user(ts->tv_sec, &cts->tv_sec) || 47 __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; 48 } 49 50 static int __compat_put_timespec(const struct timespec *ts, struct old_timespec32 __user *cts) 51 { 52 return (!access_ok(cts, sizeof(*cts)) || 53 __put_user(ts->tv_sec, &cts->tv_sec) || 54 __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0; 55 } 56 57 int compat_get_timeval(struct timeval *tv, const void __user *utv) 58 { 59 if (COMPAT_USE_64BIT_TIME) 60 return copy_from_user(tv, utv, sizeof(*tv)) ? -EFAULT : 0; 61 else 62 return __compat_get_timeval(tv, utv); 63 } 64 EXPORT_SYMBOL_GPL(compat_get_timeval); 65 66 int compat_put_timeval(const struct timeval *tv, void __user *utv) 67 { 68 if (COMPAT_USE_64BIT_TIME) 69 return copy_to_user(utv, tv, sizeof(*tv)) ? -EFAULT : 0; 70 else 71 return __compat_put_timeval(tv, utv); 72 } 73 EXPORT_SYMBOL_GPL(compat_put_timeval); 74 75 int compat_get_timespec(struct timespec *ts, const void __user *uts) 76 { 77 if (COMPAT_USE_64BIT_TIME) 78 return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0; 79 else 80 return __compat_get_timespec(ts, uts); 81 } 82 EXPORT_SYMBOL_GPL(compat_get_timespec); 83 84 int compat_put_timespec(const struct timespec *ts, void __user *uts) 85 { 86 if (COMPAT_USE_64BIT_TIME) 87 return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0; 88 else 89 return __compat_put_timespec(ts, uts); 90 } 91 EXPORT_SYMBOL_GPL(compat_put_timespec); 92 93 #ifdef __ARCH_WANT_SYS_SIGPROCMASK 94 95 /* 96 * sys_sigprocmask SIG_SETMASK sets the first (compat) word of the 97 * blocked set of signals to the supplied signal set 98 */ 99 static inline void compat_sig_setmask(sigset_t *blocked, compat_sigset_word set) 100 { 101 memcpy(blocked->sig, &set, sizeof(set)); 102 } 103 104 COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how, 105 compat_old_sigset_t __user *, nset, 106 compat_old_sigset_t __user *, oset) 107 { 108 old_sigset_t old_set, new_set; 109 sigset_t new_blocked; 110 111 old_set = current->blocked.sig[0]; 112 113 if (nset) { 114 if (get_user(new_set, nset)) 115 return -EFAULT; 116 new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); 117 118 new_blocked = current->blocked; 119 120 switch (how) { 121 case SIG_BLOCK: 122 sigaddsetmask(&new_blocked, new_set); 123 break; 124 case SIG_UNBLOCK: 125 sigdelsetmask(&new_blocked, new_set); 126 break; 127 case SIG_SETMASK: 128 compat_sig_setmask(&new_blocked, new_set); 129 break; 130 default: 131 return -EINVAL; 132 } 133 134 set_current_blocked(&new_blocked); 135 } 136 137 if (oset) { 138 if (put_user(old_set, oset)) 139 return -EFAULT; 140 } 141 142 return 0; 143 } 144 145 #endif 146 147 int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru) 148 { 149 struct compat_rusage r32; 150 memset(&r32, 0, sizeof(r32)); 151 r32.ru_utime.tv_sec = r->ru_utime.tv_sec; 152 r32.ru_utime.tv_usec = r->ru_utime.tv_usec; 153 r32.ru_stime.tv_sec = r->ru_stime.tv_sec; 154 r32.ru_stime.tv_usec = r->ru_stime.tv_usec; 155 r32.ru_maxrss = r->ru_maxrss; 156 r32.ru_ixrss = r->ru_ixrss; 157 r32.ru_idrss = r->ru_idrss; 158 r32.ru_isrss = r->ru_isrss; 159 r32.ru_minflt = r->ru_minflt; 160 r32.ru_majflt = r->ru_majflt; 161 r32.ru_nswap = r->ru_nswap; 162 r32.ru_inblock = r->ru_inblock; 163 r32.ru_oublock = r->ru_oublock; 164 r32.ru_msgsnd = r->ru_msgsnd; 165 r32.ru_msgrcv = r->ru_msgrcv; 166 r32.ru_nsignals = r->ru_nsignals; 167 r32.ru_nvcsw = r->ru_nvcsw; 168 r32.ru_nivcsw = r->ru_nivcsw; 169 if (copy_to_user(ru, &r32, sizeof(r32))) 170 return -EFAULT; 171 return 0; 172 } 173 174 static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr, 175 unsigned len, struct cpumask *new_mask) 176 { 177 unsigned long *k; 178 179 if (len < cpumask_size()) 180 memset(new_mask, 0, cpumask_size()); 181 else if (len > cpumask_size()) 182 len = cpumask_size(); 183 184 k = cpumask_bits(new_mask); 185 return compat_get_bitmap(k, user_mask_ptr, len * 8); 186 } 187 188 COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid, 189 unsigned int, len, 190 compat_ulong_t __user *, user_mask_ptr) 191 { 192 cpumask_var_t new_mask; 193 int retval; 194 195 if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) 196 return -ENOMEM; 197 198 retval = compat_get_user_cpu_mask(user_mask_ptr, len, new_mask); 199 if (retval) 200 goto out; 201 202 retval = sched_setaffinity(pid, new_mask); 203 out: 204 free_cpumask_var(new_mask); 205 return retval; 206 } 207 208 COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t, pid, unsigned int, len, 209 compat_ulong_t __user *, user_mask_ptr) 210 { 211 int ret; 212 cpumask_var_t mask; 213 214 if ((len * BITS_PER_BYTE) < nr_cpu_ids) 215 return -EINVAL; 216 if (len & (sizeof(compat_ulong_t)-1)) 217 return -EINVAL; 218 219 if (!alloc_cpumask_var(&mask, GFP_KERNEL)) 220 return -ENOMEM; 221 222 ret = sched_getaffinity(pid, mask); 223 if (ret == 0) { 224 unsigned int retlen = min(len, cpumask_size()); 225 226 if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8)) 227 ret = -EFAULT; 228 else 229 ret = retlen; 230 } 231 free_cpumask_var(mask); 232 233 return ret; 234 } 235 236 /* 237 * We currently only need the following fields from the sigevent 238 * structure: sigev_value, sigev_signo, sig_notify and (sometimes 239 * sigev_notify_thread_id). The others are handled in user mode. 240 * We also assume that copying sigev_value.sival_int is sufficient 241 * to keep all the bits of sigev_value.sival_ptr intact. 242 */ 243 int get_compat_sigevent(struct sigevent *event, 244 const struct compat_sigevent __user *u_event) 245 { 246 memset(event, 0, sizeof(*event)); 247 return (!access_ok(u_event, sizeof(*u_event)) || 248 __get_user(event->sigev_value.sival_int, 249 &u_event->sigev_value.sival_int) || 250 __get_user(event->sigev_signo, &u_event->sigev_signo) || 251 __get_user(event->sigev_notify, &u_event->sigev_notify) || 252 __get_user(event->sigev_notify_thread_id, 253 &u_event->sigev_notify_thread_id)) 254 ? -EFAULT : 0; 255 } 256 257 long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, 258 unsigned long bitmap_size) 259 { 260 unsigned long nr_compat_longs; 261 262 /* align bitmap up to nearest compat_long_t boundary */ 263 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); 264 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); 265 266 if (!user_access_begin(umask, bitmap_size / 8)) 267 return -EFAULT; 268 269 while (nr_compat_longs > 1) { 270 compat_ulong_t l1, l2; 271 unsafe_get_user(l1, umask++, Efault); 272 unsafe_get_user(l2, umask++, Efault); 273 *mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1; 274 nr_compat_longs -= 2; 275 } 276 if (nr_compat_longs) 277 unsafe_get_user(*mask, umask++, Efault); 278 user_access_end(); 279 return 0; 280 281 Efault: 282 user_access_end(); 283 return -EFAULT; 284 } 285 286 long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, 287 unsigned long bitmap_size) 288 { 289 unsigned long nr_compat_longs; 290 291 /* align bitmap up to nearest compat_long_t boundary */ 292 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); 293 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); 294 295 if (!user_access_begin(umask, bitmap_size / 8)) 296 return -EFAULT; 297 298 while (nr_compat_longs > 1) { 299 unsigned long m = *mask++; 300 unsafe_put_user((compat_ulong_t)m, umask++, Efault); 301 unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault); 302 nr_compat_longs -= 2; 303 } 304 if (nr_compat_longs) 305 unsafe_put_user((compat_ulong_t)*mask, umask++, Efault); 306 user_access_end(); 307 return 0; 308 Efault: 309 user_access_end(); 310 return -EFAULT; 311 } 312 313 int 314 get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat) 315 { 316 #ifdef __BIG_ENDIAN 317 compat_sigset_t v; 318 if (copy_from_user(&v, compat, sizeof(compat_sigset_t))) 319 return -EFAULT; 320 switch (_NSIG_WORDS) { 321 case 4: set->sig[3] = v.sig[6] | (((long)v.sig[7]) << 32 ); 322 /* fall through */ 323 case 3: set->sig[2] = v.sig[4] | (((long)v.sig[5]) << 32 ); 324 /* fall through */ 325 case 2: set->sig[1] = v.sig[2] | (((long)v.sig[3]) << 32 ); 326 /* fall through */ 327 case 1: set->sig[0] = v.sig[0] | (((long)v.sig[1]) << 32 ); 328 } 329 #else 330 if (copy_from_user(set, compat, sizeof(compat_sigset_t))) 331 return -EFAULT; 332 #endif 333 return 0; 334 } 335 EXPORT_SYMBOL_GPL(get_compat_sigset); 336 337 /* 338 * Allocate user-space memory for the duration of a single system call, 339 * in order to marshall parameters inside a compat thunk. 340 */ 341 void __user *compat_alloc_user_space(unsigned long len) 342 { 343 void __user *ptr; 344 345 /* If len would occupy more than half of the entire compat space... */ 346 if (unlikely(len > (((compat_uptr_t)~0) >> 1))) 347 return NULL; 348 349 ptr = arch_compat_alloc_user_space(len); 350 351 if (unlikely(!access_ok(ptr, len))) 352 return NULL; 353 354 return ptr; 355 } 356 EXPORT_SYMBOL_GPL(compat_alloc_user_space); 357