change sockaddr generation to pass around correct types.
[trinity.git] / syscall.c
blobde9ab58691c2518f91f8b775ad057fee452381b7
1 /*
2 * Functions for actually doing the system calls.
3 */
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/ptrace.h>
12 #include <sys/syscall.h>
13 #include <sys/wait.h>
15 #include "arch.h"
16 #include "child.h"
17 #include "random.h"
18 #include "sanitise.h"
19 #include "shm.h"
20 #include "syscall.h"
21 #include "pids.h"
22 #include "log.h"
23 #include "params.h"
24 #include "maps.h"
25 #include "tables.h"
26 #include "utils.h"
28 #define __syscall_return(type, res) \
29 do { \
30 if ((unsigned long)(res) >= (unsigned long)(-125)) { \
31 errno = -(res); \
32 res = -1; \
33 } \
34 return (type) (res); \
35 } while (0)
37 #ifdef ARCH_IS_BIARCH
39 * This routine does 32 bit syscalls on 64 bit kernel.
40 * 32-on-32 will just use syscall() directly from do_syscall() because shm->do32bit is biarch only.
42 long syscall32(unsigned int call,
43 unsigned long a1, unsigned long a2, unsigned long a3,
44 unsigned long a4, unsigned long a5, unsigned long a6)
46 long __res = 0;
48 //FIXME: Move the implementations out to arch header files.
50 #if defined(__x86_64__)
51 __asm__ volatile (
52 "pushq %%rbp\n\t"
53 "pushq %%r10\n\t"
54 "pushq %%r11\n\t"
55 "movq %7, %%rbp\n\t"
56 "int $0x80\n\t"
57 "popq %%r11\n\t"
58 "popq %%r10\n\t"
59 "popq %%rbp\n\t"
60 : "=a" (__res)
61 : "0" (call),"b" ((long)(a1)),"c" ((long)(a2)),"d" ((long)(a3)), "S" ((long)(a4)),"D" ((long)(a5)), "g" ((long)(a6))
62 : "%rbp" /* mark EBP reg as dirty */
64 __syscall_return(long, __res);
66 #else
67 /* non-x86 implementations go here. */
68 #error Implement 32-on-64 syscall in syscall.c:syscall32() for this architecture.
70 #endif
71 return __res;
73 #else
74 #define syscall32(a,b,c,d,e,f,g) 0
75 #endif /* ARCH_IS_BIARCH */
77 static void check_uid(uid_t olduid)
79 uid_t myuid;
81 myuid = getuid();
82 if (myuid != olduid) {
84 /* unshare() can change us to /proc/sys/kernel/overflowuid */
85 if (myuid == 65534)
86 return;
88 output(0, "uid changed! Was: %d, now %d\n", olduid, myuid);
90 shm->exit_reason = EXIT_UID_CHANGED;
91 _exit(EXIT_FAILURE);
95 static unsigned long do_syscall(int childno, int *errno_saved)
97 int nr = shm->syscallno[childno];
98 unsigned long a1, a2, a3, a4, a5, a6;
99 unsigned long ret = 0;
101 a1 = shm->a1[childno];
102 a2 = shm->a2[childno];
103 a3 = shm->a3[childno];
104 a4 = shm->a4[childno];
105 a5 = shm->a5[childno];
106 a6 = shm->a6[childno];
108 shm->total_syscalls_done++;
109 shm->child_syscall_count[childno]++;
110 (void)gettimeofday(&shm->tv[childno], NULL);
112 if (syscalls[nr].entry->flags & NEED_ALARM)
113 (void)alarm(1);
115 errno = 0;
117 if (shm->do32bit[childno] == FALSE)
118 ret = syscall(nr, a1, a2, a3, a4, a5, a6);
119 else
120 ret = syscall32(nr, a1, a2, a3, a4, a5, a6);
122 *errno_saved = errno;
124 if (syscalls[nr].entry->flags & NEED_ALARM)
125 (void)alarm(0);
127 return ret;
131 * Generate arguments, print them out, then call the syscall.
133 long mkcall(int childno)
135 unsigned int call = shm->syscallno[childno];
136 unsigned long ret = 0;
137 int errno_saved;
138 uid_t olduid = getuid();
140 shm->regenerate++;
142 shm->a1[childno] = (unsigned long)rand64();
143 shm->a2[childno] = (unsigned long)rand64();
144 shm->a3[childno] = (unsigned long)rand64();
145 shm->a4[childno] = (unsigned long)rand64();
146 shm->a5[childno] = (unsigned long)rand64();
147 shm->a6[childno] = (unsigned long)rand64();
149 generic_sanitise(childno);
150 if (syscalls[call].entry->sanitise)
151 syscalls[call].entry->sanitise(childno);
153 output_syscall_prefix(childno, call);
155 /* If we're going to pause, might as well sync pre-syscall */
156 if (dopause == TRUE)
157 synclogs();
159 if (((unsigned long)shm->a1 == (unsigned long) shm) ||
160 ((unsigned long)shm->a2 == (unsigned long) shm) ||
161 ((unsigned long)shm->a3 == (unsigned long) shm) ||
162 ((unsigned long)shm->a4 == (unsigned long) shm) ||
163 ((unsigned long)shm->a5 == (unsigned long) shm) ||
164 ((unsigned long)shm->a6 == (unsigned long) shm)) {
165 BUG("Address of shm ended up in a register!\n");
168 /* Some architectures (IA64/MIPS) start their Linux syscalls
169 * At non-zero, and have other ABIs below.
171 call += SYSCALL_OFFSET;
173 ret = do_syscall(childno, &errno_saved);
174 shm->retval[childno] = ret;
176 if (IS_ERR(ret))
177 shm->failures++;
178 else
179 shm->successes++;
181 output_syscall_postfix(ret, errno_saved, IS_ERR(ret));
182 if (dopause == TRUE)
183 sleep(1);
185 /* If the syscall doesn't exist don't bother calling it next time. */
186 if ((ret == -1UL) && (errno_saved == ENOSYS)) {
188 /* Futex is awesome, it ENOSYS's depending on arguments. Sigh. */
189 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "futex"))
190 goto skip_enosys;
192 /* Unknown ioctls also ENOSYS. */
193 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "ioctl"))
194 goto skip_enosys;
196 /* sendfile() may ENOSYS depending on args. */
197 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "sendfile"))
198 goto skip_enosys;
200 output(1, "%s (%d) returned ENOSYS, marking as inactive.\n",
201 syscalls[call].entry->name, call);
203 if (biarch == FALSE) {
204 deactivate_syscall(call);
205 } else {
206 if (shm->do32bit[childno] == TRUE)
207 deactivate_syscall32(call);
208 else
209 deactivate_syscall64(call);
213 skip_enosys:
215 if (syscalls[call].entry->post)
216 syscalls[call].entry->post(childno);
218 /* store info for debugging. */
219 shm->previous_syscallno[childno] = shm->syscallno[childno];
220 shm->previous_a1[childno] = shm->a1[childno];
221 shm->previous_a2[childno] = shm->a2[childno];
222 shm->previous_a3[childno] = shm->a3[childno];
223 shm->previous_a4[childno] = shm->a4[childno];
224 shm->previous_a5[childno] = shm->a5[childno];
225 shm->previous_a6[childno] = shm->a6[childno];
227 check_uid(olduid);
229 return ret;