2 * Copyright (c) 2009-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <mach_assert.h>
30 #include <sys/errno.h>
31 #include <i386/param.h>
32 #include <i386/misc_protos.h>
33 #include <i386/cpu_data.h>
34 #include <i386/machine_cpu.h>
35 #include <i386/machine_routines.h>
36 #include <i386/cpuid.h>
39 #include <vm/vm_map.h>
40 #include <vm/vm_kern.h>
41 #include <vm/vm_fault.h>
42 #include <san/kasan.h>
44 #include <sys/kdebug.h>
46 #include <kern/copyout_shim.h>
47 #include <kern/zalloc_internal.h>
52 static int copyio(int, user_addr_t
, char *, vm_size_t
, vm_size_t
*, int);
53 static int copyio_phys(addr64_t
, addr64_t
, vm_size_t
, int);
56 * Copy sizes bigger than this value will cause a kernel panic.
58 * Yes, this is an arbitrary fixed limit, but it's almost certainly
59 * a programming error to be copying more than this amount between
60 * user and wired kernel memory in a single invocation on this
63 const int copysize_limit_panic
= (64 * MB
);
66 * The copy engine has the following characteristics
67 * - copyio() handles copies to/from user or kernel space
68 * - copypv() deals with physical or virtual addresses
70 * Readers familiar with the 32-bit kernel will expect Joe's thesis at this
71 * point describing the full glory of the copy window implementation. In K64,
72 * however, there is no need for windowing. Thanks to the vast shared address
73 * space, the kernel has direct access to userspace and to physical memory.
75 * User virtual addresses are accessible provided the user's cr3 is loaded.
76 * Physical addresses are accessible via the direct map and the PHYSMAP_PTOV()
79 * Copyin/out variants all boil done to just these 2 routines in locore.s which
80 * provide fault-recoverable copying:
82 extern int _bcopy(const void *, void *, vm_size_t
);
83 extern int _bcopystr(const void *, void *, vm_size_t
, vm_size_t
*);
84 extern int _copyin_atomic32(const char *src
, uint32_t *dst
);
85 extern int _copyin_atomic64(const char *src
, uint64_t *dst
);
86 extern int _copyout_atomic32(const uint32_t *u32
, char *src
);
87 extern int _copyout_atomic64(const uint64_t *u64
, char *src
);
92 #define COPYIN 0 /* from user virtual to kernel virtual */
93 #define COPYOUT 1 /* from kernel virtual to user virtual */
94 #define COPYINSTR 2 /* string variant of copyout */
95 #define COPYINPHYS 3 /* from user virtual to kernel physical */
96 #define COPYOUTPHYS 4 /* from kernel physical to user virtual */
97 #define COPYINATOMIC32 5 /* from user virtual to kernel virtual */
98 #define COPYINATOMIC64 6 /* from user virtual to kernel virtual */
99 #define COPYOUTATOMIC32 7 /* from user virtual to kernel virtual */
100 #define COPYOUTATOMIC64 8 /* from user virtual to kernel virtual */
109 uint8_t copyio_active
;
112 #define SMAPLOG_BUFFER_SIZE (50)
113 static smaplog_entry_t smaplog_cbuf
[SMAPLOG_BUFFER_SIZE
];
114 static uint32_t smaplog_head
= 0;
117 smaplog_add_entry(boolean_t enabling
)
120 thread_t thread
= current_thread();
123 index
= smaplog_head
;
124 } while (!OSCompareAndSwap(index
, (index
+ 1) % SMAPLOG_BUFFER_SIZE
, &smaplog_head
));
126 assert(index
< SMAPLOG_BUFFER_SIZE
);
127 assert(smaplog_head
< SMAPLOG_BUFFER_SIZE
);
130 smaplog_cbuf
[index
].timestamp
= mach_absolute_time();
131 smaplog_cbuf
[index
].thread
= thread
;
132 smaplog_cbuf
[index
].cpuid
= cpu_number();
133 smaplog_cbuf
[index
].cr4
= get_cr4();
134 smaplog_cbuf
[index
].smap_state
= enabling
;
135 smaplog_cbuf
[index
].copyio_active
= (thread
->machine
.specFlags
& CopyIOActive
) ? 1 : 0;
137 #endif /* ENABLE_SMAPLOG */
139 extern boolean_t pmap_smap_enabled
;
141 user_access_enable(void)
143 if (pmap_smap_enabled
) {
146 smaplog_add_entry(TRUE
);
151 user_access_disable(void)
153 if (pmap_smap_enabled
) {
156 smaplog_add_entry(FALSE
);
161 #if COPYIO_TRACE_ENABLED
162 #define COPYIO_TRACE(x, a, b, c, d, e) KERNEL_DEBUG_CONSTANT(x, a, b, c, d, e)
164 #define COPYIO_TRACE(x, a, b, c, d, e) do { } while(0)
168 copyio(int copy_type
, user_addr_t user_addr
, char *kernel_addr
,
169 vm_size_t nbytes
, vm_size_t
*lencopied
, int use_kernel_map
)
171 thread_t thread
= current_thread();
173 vm_size_t bytes_copied
;
175 boolean_t istate
= FALSE
;
176 boolean_t recursive_CopyIOActive
;
177 #if COPYIO_TRACE_ENABLED
178 int debug_type
= 0xeff70010;
179 debug_type
+= (copy_type
<< 2);
181 vm_size_t kernel_buf_size
= 0;
183 if (__improbable(nbytes
> copysize_limit_panic
)) {
184 panic("%s(%p, %p, %lu) - transfer too large", __func__
,
185 (void *)user_addr
, (void *)kernel_addr
, nbytes
);
188 COPYIO_TRACE(debug_type
| DBG_FUNC_START
,
189 user_addr
, kernel_addr
, nbytes
, use_kernel_map
, 0);
191 if (__improbable(nbytes
== 0)) {
195 pmap
= thread
->map
->pmap
;
196 boolean_t nopagezero
= thread
->map
->pmap
->pagezero_accessible
;
198 if ((copy_type
!= COPYINPHYS
) && (copy_type
!= COPYOUTPHYS
)) {
199 if (__improbable((vm_offset_t
)kernel_addr
< VM_MIN_KERNEL_AND_KEXT_ADDRESS
)) {
200 panic("Invalid copy parameter, copy type: %d, kernel address: %p", copy_type
, kernel_addr
);
202 if (__probable(!zalloc_disable_copyio_check
)) {
203 zone_t src_zone
= NULL
;
204 kernel_buf_size
= zone_element_size(kernel_addr
, &src_zone
);
206 * Size of elements in the permanent zone is not saved as a part of the
209 if (__improbable(src_zone
&& !src_zone
->permanent
&&
210 kernel_buf_size
< nbytes
)) {
211 panic("copyio: kernel buffer %p has size %lu < nbytes %lu", kernel_addr
, kernel_buf_size
, nbytes
);
216 /* Sanity and security check for addresses to/from a user */
218 if (__improbable(((pmap
!= kernel_pmap
) && (use_kernel_map
== 0)) &&
219 ((nbytes
&& (user_addr
+ nbytes
<= user_addr
)) || ((user_addr
+ nbytes
) > vm_map_max(thread
->map
))))) {
224 if (copy_type
>= COPYINATOMIC32
&& copy_type
<= COPYOUTATOMIC64
) {
225 if (__improbable(pmap
== kernel_pmap
)) {
237 __asan_storeN((uptr
)kernel_addr
, nbytes
);
240 case COPYOUTATOMIC32
:
241 case COPYOUTATOMIC64
:
242 __asan_loadN((uptr
)kernel_addr
, nbytes
);
243 kasan_check_uninitialized((vm_address_t
)kernel_addr
, nbytes
);
249 * If the no_shared_cr3 boot-arg is set (true), the kernel runs on
250 * its own pmap and cr3 rather than the user's -- so that wild accesses
251 * from kernel or kexts can be trapped. So, during copyin and copyout,
252 * we need to switch back to the user's map/cr3. The thread is flagged
253 * "CopyIOActive" at this time so that if the thread is pre-empted,
254 * we will later restore the correct cr3.
256 recursive_CopyIOActive
= thread
->machine
.specFlags
& CopyIOActive
;
258 boolean_t pdswitch
= no_shared_cr3
|| nopagezero
;
260 if (__improbable(pdswitch
)) {
261 istate
= ml_set_interrupts_enabled(FALSE
);
262 if (nopagezero
&& pmap_pcid_ncpus
) {
263 pmap_pcid_activate(pmap
, cpu_number(), TRUE
, TRUE
);
264 } else if (get_cr3_base() != pmap
->pm_cr3
) {
265 set_cr3_raw(pmap
->pm_cr3
);
267 thread
->machine
.specFlags
|= CopyIOActive
;
269 thread
->machine
.specFlags
|= CopyIOActive
;
272 user_access_enable();
274 #if DEVELOPMENT || DEBUG
276 * Ensure that we're running on the target thread's cr3.
278 if ((pmap
!= kernel_pmap
) && !use_kernel_map
&&
279 (get_cr3_base() != pmap
->pm_cr3
)) {
280 panic("copyio(%d,%p,%p,%ld,%p,%d) cr3 is %p expects %p",
281 copy_type
, (void *)user_addr
, kernel_addr
, nbytes
, lencopied
, use_kernel_map
,
282 (void *) get_cr3_raw(), (void *) pmap
->pm_cr3
);
286 if (__improbable(pdswitch
)) {
287 (void) ml_set_interrupts_enabled(istate
);
290 COPYIO_TRACE(0xeff70044 | DBG_FUNC_NONE
, user_addr
,
291 kernel_addr
, nbytes
, 0, 0);
295 error
= _bcopy((const void *) user_addr
,
301 error
= _bcopy(kernel_addr
,
307 error
= _bcopy((const void *) user_addr
,
308 PHYSMAP_PTOV(kernel_addr
),
313 error
= _bcopy((const void *) PHYSMAP_PTOV(kernel_addr
),
319 error
= _copyin_atomic32((const void *) user_addr
,
320 (void *) kernel_addr
);
324 error
= _copyin_atomic64((const void *) user_addr
,
325 (void *) kernel_addr
);
328 case COPYOUTATOMIC32
:
329 error
= _copyout_atomic32((const void *) kernel_addr
,
333 case COPYOUTATOMIC64
:
334 error
= _copyout_atomic64((const void *) kernel_addr
,
339 error
= _bcopystr((const void *) user_addr
,
345 * lencopied should be updated on success
346 * or ENAMETOOLONG... but not EFAULT
348 if (error
!= EFAULT
) {
349 *lencopied
= bytes_copied
;
358 if (*(kernel_addr
+ bytes_copied
- 1) == 0) {
360 * we found a NULL terminator... we're done
368 * no more room in the buffer and we haven't
369 * yet come across a NULL terminator
374 error
= ENAMETOOLONG
;
379 user_access_disable();
381 if (__improbable(pdswitch
)) {
382 istate
= ml_set_interrupts_enabled(FALSE
);
383 if (!recursive_CopyIOActive
&& (get_cr3_raw() != kernel_pmap
->pm_cr3
)) {
384 if (nopagezero
&& pmap_pcid_ncpus
) {
385 pmap_pcid_activate(pmap
, cpu_number(), TRUE
, FALSE
);
387 set_cr3_raw(kernel_pmap
->pm_cr3
);
391 if (!recursive_CopyIOActive
) {
392 thread
->machine
.specFlags
&= ~CopyIOActive
;
394 (void) ml_set_interrupts_enabled(istate
);
395 } else if (!recursive_CopyIOActive
) {
396 thread
->machine
.specFlags
&= ~CopyIOActive
;
400 COPYIO_TRACE(debug_type
| DBG_FUNC_END
, user_addr
, kernel_addr
, nbytes
, error
, 0);
407 copyio_phys(addr64_t source
, addr64_t sink
, vm_size_t csize
, int which
)
413 if (which
& cppvPsnk
) {
414 paddr
= (char *)sink
;
415 vaddr
= (user_addr_t
)source
;
418 paddr
= (char *)source
;
419 vaddr
= (user_addr_t
)sink
;
421 CALL_COPYOUT_SHIM_PHYS((void *)PHYSMAP_PTOV(source
), sink
, csize
)
423 return copyio(ctype
, vaddr
, paddr
, csize
, NULL
, which
& cppvKmap
);
427 copyinmsg(const user_addr_t user_addr
, char *kernel_addr
, mach_msg_size_t nbytes
)
429 return copyio(COPYIN
, user_addr
, kernel_addr
, nbytes
, NULL
, 0);
433 copyin(const user_addr_t user_addr
, void *kernel_addr
, vm_size_t nbytes
)
435 return copyio(COPYIN
, user_addr
, kernel_addr
, nbytes
, NULL
, 0);
439 * copy{in,out}_atomic{32,64}
440 * Read or store an aligned value from userspace as a single memory transaction.
441 * These functions support userspace synchronization features
444 copyin_atomic32(const user_addr_t user_addr
, uint32_t *kernel_addr
)
450 return copyio(COPYINATOMIC32
, user_addr
, (char *)(uintptr_t)kernel_addr
, 4, NULL
, 0);
454 copyin_atomic32_wait_if_equals(const user_addr_t user_addr
, uint32_t value
)
457 int result
= copyin_atomic32(user_addr
, &u32
);
458 if (__improbable(result
)) {
469 copyin_atomic64(const user_addr_t user_addr
, uint64_t *kernel_addr
)
475 return copyio(COPYINATOMIC64
, user_addr
, (char *)(uintptr_t)kernel_addr
, 8, NULL
, 0);
479 copyout_atomic32(uint32_t value
, user_addr_t user_addr
)
485 return copyio(COPYOUTATOMIC32
, user_addr
, (char *)&value
, 4, NULL
, 0);
489 copyout_atomic64(uint64_t value
, user_addr_t user_addr
)
495 return copyio(COPYOUTATOMIC64
, user_addr
, (char *)&value
, 8, NULL
, 0);
499 copyinstr(const user_addr_t user_addr
, char *kernel_addr
, vm_size_t nbytes
, vm_size_t
*lencopied
)
503 return copyio(COPYINSTR
, user_addr
, kernel_addr
, nbytes
, lencopied
, 0);
507 copyoutmsg(const char *kernel_addr
, user_addr_t user_addr
, mach_msg_size_t nbytes
)
509 CALL_COPYOUT_SHIM_MSG(kernel_addr
, user_addr
, (vm_size_t
)nbytes
)
510 return copyio(COPYOUT
, user_addr
, (char *)(uintptr_t)kernel_addr
, nbytes
, NULL
, 0);
514 copyout(const void *kernel_addr
, user_addr_t user_addr
, vm_size_t nbytes
)
516 CALL_COPYOUT_SHIM_NRML(kernel_addr
, user_addr
, nbytes
)
517 return copyio(COPYOUT
, user_addr
, (char *)(uintptr_t)kernel_addr
, nbytes
, NULL
, 0);
522 copypv(addr64_t src64
, addr64_t snk64
, unsigned int size
, int which
)
524 unsigned int lop
, csize
;
527 KERNEL_DEBUG(0xeff7004c | DBG_FUNC_START
, (unsigned)src64
,
528 (unsigned)snk64
, size
, which
, 0);
530 if ((which
& (cppvPsrc
| cppvPsnk
)) == 0) { /* Make sure that only one is virtual */
531 panic("copypv: no more than 1 parameter may be virtual\n"); /* Not allowed */
533 if ((which
& (cppvPsrc
| cppvPsnk
)) == (cppvPsrc
| cppvPsnk
)) {
534 bothphys
= 1; /* both are physical */
538 lop
= (unsigned int)(PAGE_SIZE
- (snk64
& (PAGE_SIZE
- 1))); /* Assume sink smallest */
540 if (lop
> (unsigned int)(PAGE_SIZE
- (src64
& (PAGE_SIZE
- 1)))) {
541 lop
= (unsigned int)(PAGE_SIZE
- (src64
& (PAGE_SIZE
- 1))); /* No, source is smaller */
545 * only need to compute the resid for the physical page
546 * address... we don't care about where we start/finish in
547 * the virtual since we just call the normal copyin/copyout
549 if (which
& cppvPsrc
) {
550 lop
= (unsigned int)(PAGE_SIZE
- (src64
& (PAGE_SIZE
- 1)));
552 lop
= (unsigned int)(PAGE_SIZE
- (snk64
& (PAGE_SIZE
- 1)));
555 csize
= size
; /* Assume we can copy it all */
557 csize
= lop
; /* Nope, we can't do it all */
561 * flush_dcache64 is currently a nop on the i386...
562 * it's used when copying to non-system memory such
563 * as video capture cards... on PPC there was a need
564 * to flush due to how we mapped this memory... not
565 * sure if it's needed on i386.
567 if (which
& cppvFsrc
) {
568 flush_dcache64(src64
, csize
, 1); /* If requested, flush source before move */
570 if (which
& cppvFsnk
) {
571 flush_dcache64(snk64
, csize
, 1); /* If requested, flush sink before move */
575 bcopy_phys(src64
, snk64
, csize
); /* Do a physical copy, virtually */
577 if (copyio_phys(src64
, snk64
, csize
, which
)) {
582 if (which
& cppvFsrc
) {
583 flush_dcache64(src64
, csize
, 1); /* If requested, flush source after move */
585 if (which
& cppvFsnk
) {
586 flush_dcache64(snk64
, csize
, 1); /* If requested, flush sink after move */
589 size
-= csize
; /* Calculate what is left */
590 snk64
+= csize
; /* Bump sink to next physical address */
591 src64
+= csize
; /* Bump source to next physical address */
593 KERNEL_DEBUG(0xeff7004c | DBG_FUNC_END
, (unsigned)src64
,
594 (unsigned)snk64
, size
, which
, 0);