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;
102 a1
= shm
->a1
[childno
];
103 a2
= shm
->a2
[childno
];
104 a3
= shm
->a3
[childno
];
105 a4
= shm
->a4
[childno
];
106 a5
= shm
->a5
[childno
];
107 a6
= shm
->a6
[childno
];
109 pidslot
= find_pid_slot(getpid());
110 if (pidslot
!= PIDSLOT_NOT_FOUND
) {
111 shm
->total_syscalls_done
++;
112 shm
->child_syscall_count
[pidslot
]++;
113 (void)gettimeofday(&shm
->tv
[pidslot
], NULL
);
116 if (syscalls
[nr
].entry
->flags
& NEED_ALARM
)
121 if (shm
->do32bit
[childno
] == FALSE
)
122 ret
= syscall(nr
, a1
, a2
, a3
, a4
, a5
, a6
);
124 ret
= syscall32(nr
, a1
, a2
, a3
, a4
, a5
, a6
);
126 *errno_saved
= errno
;
128 if (syscalls
[nr
].entry
->flags
& NEED_ALARM
)
135 * Generate arguments, print them out, then call the syscall.
137 long mkcall(int childno
)
139 unsigned int call
= shm
->syscallno
[childno
];
140 unsigned long ret
= 0;
142 uid_t olduid
= getuid();
146 shm
->a1
[childno
] = (unsigned long)rand64();
147 shm
->a2
[childno
] = (unsigned long)rand64();
148 shm
->a3
[childno
] = (unsigned long)rand64();
149 shm
->a4
[childno
] = (unsigned long)rand64();
150 shm
->a5
[childno
] = (unsigned long)rand64();
151 shm
->a6
[childno
] = (unsigned long)rand64();
153 generic_sanitise(childno
);
154 if (syscalls
[call
].entry
->sanitise
)
155 syscalls
[call
].entry
->sanitise(childno
);
157 output_syscall_prefix(childno
, call
);
159 /* If we're going to pause, might as well sync pre-syscall */
163 if (((unsigned long)shm
->a1
== (unsigned long) shm
) ||
164 ((unsigned long)shm
->a2
== (unsigned long) shm
) ||
165 ((unsigned long)shm
->a3
== (unsigned long) shm
) ||
166 ((unsigned long)shm
->a4
== (unsigned long) shm
) ||
167 ((unsigned long)shm
->a5
== (unsigned long) shm
) ||
168 ((unsigned long)shm
->a6
== (unsigned long) shm
)) {
169 BUG("Address of shm ended up in a register!\n");
172 /* Some architectures (IA64/MIPS) start their Linux syscalls
173 * At non-zero, and have other ABIs below.
175 call
+= SYSCALL_OFFSET
;
177 ret
= do_syscall(childno
, &errno_saved
);
178 shm
->retval
[childno
] = ret
;
185 output_syscall_postfix(ret
, errno_saved
, IS_ERR(ret
));
189 /* If the syscall doesn't exist don't bother calling it next time. */
190 if ((ret
== -1UL) && (errno_saved
== ENOSYS
)) {
192 /* Futex is awesome, it ENOSYS's depending on arguments. Sigh. */
193 if (call
== (unsigned int) search_syscall_table(syscalls
, max_nr_syscalls
, "futex"))
196 /* Unknown ioctls also ENOSYS. */
197 if (call
== (unsigned int) search_syscall_table(syscalls
, max_nr_syscalls
, "ioctl"))
200 /* sendfile() may ENOSYS depending on args. */
201 if (call
== (unsigned int) search_syscall_table(syscalls
, max_nr_syscalls
, "sendfile"))
204 output(1, "%s (%d) returned ENOSYS, marking as inactive.\n",
205 syscalls
[call
].entry
->name
, call
);
207 if (biarch
== FALSE
) {
208 deactivate_syscall(call
);
210 if (shm
->do32bit
[childno
] == TRUE
)
211 deactivate_syscall32(call
);
213 deactivate_syscall64(call
);
219 if (syscalls
[call
].entry
->post
)
220 syscalls
[call
].entry
->post(childno
);
222 /* store info for debugging. */
223 shm
->previous_syscallno
[childno
] = shm
->syscallno
[childno
];
224 shm
->previous_a1
[childno
] = shm
->a1
[childno
];
225 shm
->previous_a2
[childno
] = shm
->a2
[childno
];
226 shm
->previous_a3
[childno
] = shm
->a3
[childno
];
227 shm
->previous_a4
[childno
] = shm
->a4
[childno
];
228 shm
->previous_a5
[childno
] = shm
->a5
[childno
];
229 shm
->previous_a6
[childno
] = shm
->a6
[childno
];