1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright 2013, winocm. <winocm@icloud.com> 30 * All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without modification, 33 * are permitted provided that the following conditions are met: 34 * 35 * Redistributions of source code must retain the above copyright notice, this 36 * list of conditions and the following disclaimer. 37 * 38 * Redistributions in binary form must reproduce the above copyright notice, this 39 * list of conditions and the following disclaimer in the documentation and/or 40 * other materials provided with the distribution. 41 * 42 * If you are going to use this software in any form that does not involve 43 * releasing the source to this project or improving it, let me know beforehand. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 47 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 48 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 49 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 51 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 52 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 54 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56/* 57 * BSD system calls for ARM. 58 */ 59 60#include <mach/mach_types.h> 61#include <mach/exception.h> 62 63#include <kern/task.h> 64#include <kern/thread.h> 65#include <kern/assert.h> 66#include <kern/clock.h> 67#include <kern/locks.h> 68#include <kern/sched_prim.h> 69#include <kern/debug.h> 70 71#include <sys/systm.h> 72#include <sys/param.h> 73#include <sys/proc_internal.h> 74#include <sys/user.h> 75#include <sys/sysproto.h> 76#include <sys/sysent.h> 77#include <sys/ucontext.h> 78#include <sys/wait.h> 79#include <mach/thread_act.h> /* for thread_abort_safely */ 80#include <mach/thread_status.h> 81 82#include <arm/machine_routines.h> 83 84#include <sys/kdebug.h> 85#include <sys/sdt.h> 86 87#include <security/audit/audit.h> 88 89#include <mach/branch_predicates.h> 90 91/* dynamically generated at build time based on syscalls.master */ 92extern const char *syscallnames[]; 93 94/* 95 * Function: unix_syscall 96 * 97 * Inputs: regs - pointer to arm save area 98 * 99 * Outputs: none 100 */ 101void unix_syscall(arm_saved_state_t * state) 102{ 103 thread_t thread; 104 void *vt; 105 unsigned int code; 106 struct sysent *callp; 107 int error = 0; 108 vm_offset_t params; 109 struct proc *p; 110 struct uthread *uthread; 111 boolean_t args_in_uthread; 112 boolean_t is_vfork; 113 114 assert(state != NULL); 115 thread = current_thread(); 116 uthread = get_bsdthread_info(thread); 117 118 /* 119 * Get the approriate proc; may be different from task's for vfork() 120 */ 121 is_vfork = uthread->uu_flag & UT_VFORK; 122 if (__improbable(is_vfork != 0)) 123 p = current_proc(); 124 else 125 p = (struct proc *) get_bsdtask_info(current_task()); 126 127 /* 128 * Verify that we are not being called from a task without a proc 129 */ 130 if (__improbable(p == NULL)) { 131 state->r[0] = EPERM; 132 task_terminate_internal(current_task()); 133 thread_exception_return(); 134 /* 135 * NOTREACHED 136 */ 137 } 138 139 /* 140 * Current syscall number is in r12 on ARM 141 */ 142 boolean_t shift_args = FALSE; 143 144 state->cpsr &= ~(1 << 29); /* C-bit IIRC, turn this into a Define */ 145 code = state->r[12]; 146 147 /* 148 * Delayed binding of thread credential to process credential, if we 149 * are not running with an explicitly set thread credential. 150 */ 151 kauth_cred_uthread_update(uthread, p); 152 153 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code]; 154 if (__improbable(callp == sysent)) { 155 /* 156 * indirect system call... system call number 157 * passed as 'arg0' 158 */ 159 code = state->r[0]; 160 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code]; 161 shift_args = TRUE; 162 } 163 164 if (callp->sy_narg) { 165 int arg_count = callp->sy_narg; 166 if (!shift_args) { 167 int i; 168 for (i = 0; i < 12; i++) { 169 uthread->uu_arg[i] = state->r[i]; 170 if (i == (arg_count)) 171 break; 172 } 173 } else { 174 int i; 175 for (i = 0; i < 11; i++) { 176 uthread->uu_arg[i] = state->r[i + 1]; 177 if (i == (arg_count)) 178 break; 179 } 180 } 181 } 182 183 /* 184 * Set return values 185 */ 186 uthread->uu_flag |= UT_NOTCANCELPT; 187 uthread->uu_rval[0] = 0; 188 uthread->uu_rval[1] = 0; 189 190 AUDIT_SYSCALL_ENTER(code, p, uthread); 191 error = (*(callp->sy_call)) (p, (void *) uthread->uu_arg, &(uthread->uu_rval[0])); 192 AUDIT_SYSCALL_EXIT(code, p, uthread, error); 193 194#if 0 195 kprintf("SYSCALL: %s (%d, routine %p), args %p, return %x (%x, %x) pc 0x%08x\n", syscallnames[code >= NUM_SYSENT ? 63 : code], code, callp->sy_call, (void *) uthread->uu_arg, error, uthread->uu_rval[0], uthread->uu_rval[1], state->pc); 196#endif 197 198#if CONFIG_MACF 199 mac_thread_userret(code, error, thread); 200#endif 201 202 if (error) 203 state->cpsr |= (1 << 29); /* C-bit IIRC, turn this into a Define */ 204 205 if (error == ERESTART) { 206 panic("unix_syscall: restarting syscall\n"); 207 } else if(error != EJUSTRETURN) { 208 if(error) { 209 state->r[0] = error; 210 } else { /* Not error. */ 211 switch(callp->sy_return_type) { 212 case _SYSCALL_RET_INT_T: 213 state->r[0] = (int)uthread->uu_rval[0]; 214 state->r[1] = (int)uthread->uu_rval[1]; 215 break; 216 case _SYSCALL_RET_UINT_T: 217 state->r[0] = (u_int)uthread->uu_rval[0]; 218 state->r[1] = (u_int)uthread->uu_rval[1]; 219 break; 220 case _SYSCALL_RET_OFF_T: 221 case _SYSCALL_RET_UINT64_T: 222 state->r[0] = uthread->uu_rval[0]; 223 state->r[1] = uthread->uu_rval[1]; 224 break; 225 case _SYSCALL_RET_ADDR_T: 226 case _SYSCALL_RET_SIZE_T: 227 case _SYSCALL_RET_SSIZE_T: { 228 user_addr_t *retp = (user_addr_t *)&uthread->uu_rval[0]; 229 state->r[0] = *retp; 230 state->r[1] = 0; 231 } 232 break; 233 case _SYSCALL_RET_NONE: 234 break; 235 default: 236 panic("unix_syscall: unknown return type"); 237 break; 238 } 239 } 240 } 241 242 uthread->uu_flag &= ~UT_NOTCANCELPT; 243 244 /* 245 * panic if funnel is held 246 */ 247 syscall_exit_funnelcheck(); 248 249 if (uthread->uu_lowpri_window) { 250 /* 251 * task is marked as a low priority I/O type 252 * and the I/O we issued while in this system call 253 * collided with normal I/O operations... we'll 254 * delay in order to mitigate the impact of this 255 * task on the normal operation of the system 256 */ 257 throttle_lowpri_io(TRUE); 258 } 259 260 thread_exception_return(); 261} 262 263void unix_syscall_return(int error) 264{ 265 thread_t thread_act; 266 struct uthread *uthread; 267 struct proc *proc; 268 arm_saved_state_t *state; 269 unsigned int code = 0; 270 struct sysent *callp; 271 272 thread_act = current_thread(); 273 proc = current_proc(); 274 uthread = get_bsdthread_info(thread_act); 275 276 state = find_user_regs(thread_act); 277 278 if (state->r[12] != 0) 279 code = state->r[12]; 280 281 callp = (code >= NUM_SYSENT) ? &sysent[63] : &sysent[code]; 282 283 AUDIT_SYSCALL_EXIT(code, proc, uthread, error); 284 285 if (error == ERESTART) { 286 panic("unix_syscall: restarting syscall\n"); 287 } else if(error != EJUSTRETURN) { 288 if(error) { 289 state->r[0] = error; 290 } else { /* Not error. */ 291 switch(callp->sy_return_type) { 292 case _SYSCALL_RET_INT_T: 293 state->r[0] = uthread->uu_rval[0]; 294 state->r[1] = uthread->uu_rval[1]; 295 break; 296 case _SYSCALL_RET_UINT_T: 297 state->r[0] = (u_int)uthread->uu_rval[0]; 298 state->r[1] = (u_int)uthread->uu_rval[1]; 299 break; 300 case _SYSCALL_RET_OFF_T: 301 case _SYSCALL_RET_UINT64_T: 302 state->r[0] = uthread->uu_rval[0]; 303 state->r[1] = uthread->uu_rval[1]; 304 break; 305 case _SYSCALL_RET_ADDR_T: 306 case _SYSCALL_RET_SIZE_T: 307 case _SYSCALL_RET_SSIZE_T: { 308 user_addr_t *retp = (user_addr_t *)&uthread->uu_rval[0]; 309 state->r[0] = *retp; 310 state->r[1] = 0; 311 } 312 break; 313 case _SYSCALL_RET_NONE: 314 break; 315 default: 316 panic("unix_syscall: unknown return type"); 317 break; 318 } 319 state->cpsr &= ~(1 << 29); /* C-bit IIRC, turn this into a Define */ 320 } 321 } 322 323 uthread->uu_flag &= ~UT_NOTCANCELPT; 324 325#if FUNNEL_DEBUG 326 /* 327 * if we're holding the funnel panic 328 */ 329 syscall_exit_funnelcheck(); 330#endif /* FUNNEL_DEBUG */ 331 332 if (uthread->uu_lowpri_window) { 333 /* 334 * task is marked as a low priority I/O type 335 * and the I/O we issued while in this system call 336 * collided with normal I/O operations... we'll 337 * delay in order to mitigate the impact of this 338 * task on the normal operation of the system 339 */ 340 throttle_lowpri_io(TRUE); 341 } 342 if (kdebug_enable && (code != 180)) { 343 if (callp->sy_return_type == _SYSCALL_RET_SSIZE_T) 344 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, error, uthread->uu_rval[1], 0, 0, 0); 345 else 346 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_EXCP_SC, code) | DBG_FUNC_END, error, uthread->uu_rval[0], uthread->uu_rval[1], 0, 0); 347 } 348 349 thread_exception_return(); 350 /* 351 * NOTREACHED 352 */ 353} 354