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