merge setgroups variants
[trinity.git] / syscall.c
blob1c35c13ee27c54bc9c662f52ae297b34d3f5eafd
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 "trinity.h"
27 #include "uid.h"
28 #include "utils.h"
30 #define __syscall_return(type, res) \
31 do { \
32 if ((unsigned long)(res) >= (unsigned long)(-125)) { \
33 errno = -(res); \
34 res = -1; \
35 } \
36 return (type) (res); \
37 } while (0)
39 #ifdef ARCH_IS_BIARCH
41 * This routine does 32 bit syscalls on 64 bit kernel.
42 * 32-on-32 will just use syscall() directly from do_syscall() because shm->do32bit is biarch only.
44 long syscall32(unsigned int call,
45 unsigned long a1, unsigned long a2, unsigned long a3,
46 unsigned long a4, unsigned long a5, unsigned long a6)
48 long __res = 0;
50 //FIXME: Move the implementations out to arch header files.
52 #if defined(__x86_64__)
53 __asm__ volatile (
54 "pushq %%rbp\n\t"
55 "pushq %%r10\n\t"
56 "pushq %%r11\n\t"
57 "movq %7, %%rbp\n\t"
58 "int $0x80\n\t"
59 "popq %%r11\n\t"
60 "popq %%r10\n\t"
61 "popq %%rbp\n\t"
62 : "=a" (__res)
63 : "0" (call),"b" ((long)(a1)),"c" ((long)(a2)),"d" ((long)(a3)), "S" ((long)(a4)),"D" ((long)(a5)), "g" ((long)(a6))
64 : "%rbp" /* mark EBP reg as dirty */
66 __syscall_return(long, __res);
68 #else
69 /* non-x86 implementations go here. */
70 #error Implement 32-on-64 syscall in syscall.c:syscall32() for this architecture.
72 #endif
73 return __res;
75 #else
76 #define syscall32(a,b,c,d,e,f,g) 0
77 #endif /* ARCH_IS_BIARCH */
79 static unsigned long do_syscall(int childno, int *errno_saved)
81 int nr = shm->syscallno[childno];
82 unsigned long a1, a2, a3, a4, a5, a6;
83 unsigned long ret = 0;
85 a1 = shm->a1[childno];
86 a2 = shm->a2[childno];
87 a3 = shm->a3[childno];
88 a4 = shm->a4[childno];
89 a5 = shm->a5[childno];
90 a6 = shm->a6[childno];
92 shm->total_syscalls_done++;
93 shm->child_syscall_count[childno]++;
94 (void)gettimeofday(&shm->tv[childno], NULL);
96 if (syscalls[nr].entry->flags & NEED_ALARM)
97 (void)alarm(1);
99 errno = 0;
101 if (shm->do32bit[childno] == FALSE)
102 ret = syscall(nr, a1, a2, a3, a4, a5, a6);
103 else
104 ret = syscall32(nr, a1, a2, a3, a4, a5, a6);
106 *errno_saved = errno;
108 if (syscalls[nr].entry->flags & NEED_ALARM)
109 (void)alarm(0);
111 return ret;
115 * Generate arguments, print them out, then call the syscall.
117 long mkcall(int childno)
119 struct syscallentry *entry;
120 unsigned int call = shm->syscallno[childno];
121 unsigned long ret = 0;
122 int errno_saved;
124 entry = syscalls[call].entry;
126 shm->regenerate++;
128 shm->a1[childno] = (unsigned long)rand64();
129 shm->a2[childno] = (unsigned long)rand64();
130 shm->a3[childno] = (unsigned long)rand64();
131 shm->a4[childno] = (unsigned long)rand64();
132 shm->a5[childno] = (unsigned long)rand64();
133 shm->a6[childno] = (unsigned long)rand64();
135 generic_sanitise(childno);
136 if (entry->sanitise)
137 entry->sanitise(childno);
139 output_syscall_prefix(childno, call);
141 /* If we're going to pause, might as well sync pre-syscall */
142 if (dopause == TRUE)
143 synclogs();
145 if (((unsigned long)shm->a1 == (unsigned long) shm) ||
146 ((unsigned long)shm->a2 == (unsigned long) shm) ||
147 ((unsigned long)shm->a3 == (unsigned long) shm) ||
148 ((unsigned long)shm->a4 == (unsigned long) shm) ||
149 ((unsigned long)shm->a5 == (unsigned long) shm) ||
150 ((unsigned long)shm->a6 == (unsigned long) shm)) {
151 BUG("Address of shm ended up in a register!\n");
154 /* Some architectures (IA64/MIPS) start their Linux syscalls
155 * At non-zero, and have other ABIs below.
157 call += SYSCALL_OFFSET;
159 ret = do_syscall(childno, &errno_saved);
160 shm->retval[childno] = ret;
162 if (IS_ERR(ret))
163 shm->failures++;
164 else
165 shm->successes++;
167 output_syscall_postfix(ret, errno_saved, IS_ERR(ret));
168 if (dopause == TRUE)
169 sleep(1);
171 /* If the syscall doesn't exist don't bother calling it next time. */
172 if ((ret == -1UL) && (errno_saved == ENOSYS)) {
174 /* Futex is awesome, it ENOSYS's depending on arguments. Sigh. */
175 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "futex"))
176 goto skip_enosys;
178 /* Unknown ioctls also ENOSYS. */
179 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "ioctl"))
180 goto skip_enosys;
182 /* sendfile() may ENOSYS depending on args. */
183 if (call == (unsigned int) search_syscall_table(syscalls, max_nr_syscalls, "sendfile"))
184 goto skip_enosys;
186 output(1, "%s (%d) returned ENOSYS, marking as inactive.\n",
187 entry->name, call);
189 if (biarch == FALSE) {
190 deactivate_syscall(call);
191 } else {
192 if (shm->do32bit[childno] == TRUE)
193 deactivate_syscall32(call);
194 else
195 deactivate_syscall64(call);
199 skip_enosys:
201 if (entry->post)
202 entry->post(childno);
204 /* store info for debugging. */
205 shm->previous_syscallno[childno] = shm->syscallno[childno];
206 shm->previous_a1[childno] = shm->a1[childno];
207 shm->previous_a2[childno] = shm->a2[childno];
208 shm->previous_a3[childno] = shm->a3[childno];
209 shm->previous_a4[childno] = shm->a4[childno];
210 shm->previous_a5[childno] = shm->a5[childno];
211 shm->previous_a6[childno] = shm->a6[childno];
213 check_uid();
215 return ret;
218 bool this_syscallname(const char *thisname, int childno)
220 unsigned int call = shm->syscallno[childno];
221 struct syscallentry *syscall_entry = syscalls[call].entry;
223 return strcmp(thisname, syscall_entry->name);