2 * Functions for actually doing the system calls.
10 #include <sys/types.h>
11 #include <sys/ptrace.h>
12 #include <sys/syscall.h>
28 #define __syscall_return(type, res) \
30 if ((unsigned long)(res) >= (unsigned long)(-125)) { \
34 return (type) (res); \
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
)
48 //FIXME: Move the implementations out to arch header files.
50 #if defined(__x86_64__)
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
);
67 /* non-x86 implementations go here. */
68 #error Implement 32-on-64 syscall in syscall.c:syscall32() for this architecture.
74 #define syscall32(a,b,c,d,e,f,g) 0
75 #endif /* ARCH_IS_BIARCH */
77 static void check_uid(uid_t olduid
)
82 if (myuid
!= olduid
) {
84 /* unshare() can change us to /proc/sys/kernel/overflowuid */
88 output(0, "uid changed! Was: %d, now %d\n", olduid
, myuid
);
90 shm
->exit_reason
= EXIT_UID_CHANGED
;
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
)
117 if (shm
->do32bit
[childno
] == FALSE
)
118 ret
= syscall(nr
, a1
, a2
, a3
, a4
, a5
, a6
);
120 ret
= syscall32(nr
, a1
, a2
, a3
, a4
, a5
, a6
);
122 *errno_saved
= errno
;
124 if (syscalls
[nr
].entry
->flags
& NEED_ALARM
)
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;
138 uid_t olduid
= getuid();
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 */
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
;
181 output_syscall_postfix(ret
, errno_saved
, IS_ERR(ret
));
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"))
192 /* Unknown ioctls also ENOSYS. */
193 if (call
== (unsigned int) search_syscall_table(syscalls
, max_nr_syscalls
, "ioctl"))
196 /* sendfile() may ENOSYS depending on args. */
197 if (call
== (unsigned int) search_syscall_table(syscalls
, max_nr_syscalls
, "sendfile"))
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
);
206 if (shm
->do32bit
[childno
] == TRUE
)
207 deactivate_syscall32(call
);
209 deactivate_syscall64(call
);
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
];