Line data Source code
1 : /*
2 : Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
3 : Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany
4 :
5 : This software was partially supported by the
6 : EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
7 :
8 : This software was partially supported by the
9 : ADA-FS project under the SPPEXA project funded by the DFG.
10 :
11 : This file is part of GekkoFS' POSIX interface.
12 :
13 : GekkoFS' POSIX interface is free software: you can redistribute it and/or
14 : modify it under the terms of the GNU Lesser General Public License as
15 : published by the Free Software Foundation, either version 3 of the License,
16 : or (at your option) any later version.
17 :
18 : GekkoFS' POSIX interface is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : GNU Lesser General Public License for more details.
22 :
23 : You should have received a copy of the GNU Lesser General Public License
24 : along with GekkoFS' POSIX interface. If not, see
25 : <https://www.gnu.org/licenses/>.
26 :
27 : SPDX-License-Identifier: LGPL-3.0-or-later
28 : */
29 :
30 : #include <client/intercept.hpp>
31 : #include <client/preload.hpp>
32 : #include <client/hooks.hpp>
33 : #include <client/logging.hpp>
34 :
35 : #include <optional>
36 : #include <fmt/format.h>
37 :
38 : #include <cerrno>
39 :
40 : extern "C" {
41 : #include <syscall.h>
42 : #include <sys/types.h>
43 : #include <sys/socket.h>
44 : #include <printf.h>
45 : }
46 :
47 : namespace {
48 :
49 : thread_local bool reentrance_guard_flag;
50 : thread_local gkfs::syscall::info saved_syscall_info;
51 :
52 : constexpr void
53 10945349 : save_current_syscall_info(gkfs::syscall::info info) {
54 10945349 : saved_syscall_info = info;
55 : }
56 :
57 : constexpr void
58 10942951 : reset_current_syscall_info() {
59 10942951 : saved_syscall_info = gkfs::syscall::no_info;
60 : }
61 :
62 : inline gkfs::syscall::info
63 21716768 : get_current_syscall_info() {
64 21716768 : return saved_syscall_info;
65 : }
66 :
67 :
68 : /*
69 : * hook_internal -- interception hook for internal syscalls
70 : *
71 : * This hook is basically used to keep track of file descriptors created
72 : * internally by the library itself. This is important because some
73 : * applications (e.g. ssh) may attempt to close all open file descriptors
74 : * which would leave the library internals in an inconsistent state.
75 : * We forward syscalls to the kernel but we keep track of any syscalls that may
76 : * create or destroy a file descriptor so that we can mark them as 'internal'.
77 : */
78 : inline int
79 3235619 : hook_internal(long syscall_number, long arg0, long arg1, long arg2, long arg3,
80 : long arg4, long arg5, long* result) {
81 :
82 : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
83 3235619 : const long args[gkfs::syscall::MAX_ARGS] = {arg0, arg1, arg2,
84 3235619 : arg3, arg4, arg5};
85 : #endif
86 :
87 3235619 : LOG(SYSCALL,
88 : gkfs::syscall::from_internal_code | gkfs::syscall::to_hook |
89 : gkfs::syscall::not_executed,
90 3235650 : syscall_number, args);
91 :
92 3235650 : switch(syscall_number) {
93 : #ifdef SYS_open
94 0 : case SYS_open:
95 0 : *result = syscall_no_intercept_wrapper(
96 : syscall_number, reinterpret_cast<char*>(arg0),
97 : static_cast<int>(arg1), static_cast<mode_t>(arg2));
98 :
99 0 : if(*result > 0) {
100 0 : *result = CTX->register_internal_fd(*result);
101 : }
102 :
103 : break;
104 : #endif
105 : #ifdef SYS_creat
106 0 : case SYS_creat:
107 0 : *result = syscall_no_intercept_wrapper(
108 : syscall_number, reinterpret_cast<const char*>(arg0),
109 : O_WRONLY | O_CREAT | O_TRUNC, static_cast<mode_t>(arg1));
110 0 : if(*result > 0) {
111 0 : *result = CTX->register_internal_fd(*result);
112 : }
113 :
114 : break;
115 : #endif
116 8680 : case SYS_openat:
117 8680 : *result = syscall_no_intercept_wrapper(
118 : syscall_number, static_cast<int>(arg0),
119 : reinterpret_cast<const char*>(arg1), static_cast<int>(arg2),
120 : static_cast<mode_t>(arg3));
121 8680 : if(*result > 0) {
122 8184 : *result = CTX->register_internal_fd(*result);
123 : }
124 : break;
125 : #ifdef SYS_epoll_create
126 992 : case SYS_epoll_create:
127 992 : *result = syscall_no_intercept_wrapper(syscall_number,
128 : static_cast<int>(arg0));
129 992 : if(*result > 0) {
130 992 : *result = CTX->register_internal_fd(*result);
131 : }
132 :
133 : break;
134 : #endif
135 248 : case SYS_epoll_create1:
136 248 : *result = syscall_no_intercept_wrapper(syscall_number,
137 : static_cast<int>(arg0));
138 248 : if(*result > 0) {
139 248 : *result = CTX->register_internal_fd(*result);
140 : }
141 :
142 : break;
143 :
144 0 : case SYS_dup:
145 0 : *result = syscall_no_intercept_wrapper(
146 : syscall_number, static_cast<unsigned int>(arg0));
147 0 : if(*result > 0) {
148 0 : *result = CTX->register_internal_fd(*result);
149 : }
150 : break;
151 : #ifdef SYS_dup2
152 0 : case SYS_dup2:
153 0 : *result = syscall_no_intercept_wrapper(
154 : syscall_number, static_cast<unsigned int>(arg0),
155 : static_cast<unsigned int>(arg1));
156 0 : if(*result > 0) {
157 0 : *result = CTX->register_internal_fd(*result);
158 : }
159 : break;
160 : #endif
161 0 : case SYS_dup3:
162 0 : *result = syscall_no_intercept_wrapper(
163 : syscall_number, static_cast<unsigned int>(arg0),
164 : static_cast<unsigned int>(arg1), static_cast<int>(arg2));
165 :
166 0 : if(*result > 0) {
167 0 : *result = CTX->register_internal_fd(*result);
168 : }
169 : break;
170 : #ifdef SYS_inotify_init
171 0 : case SYS_inotify_init:
172 0 : *result = syscall_no_intercept_wrapper(syscall_number);
173 :
174 0 : if(*result >= 0) {
175 0 : *result = CTX->register_internal_fd(*result);
176 : }
177 :
178 : break;
179 : #endif
180 0 : case SYS_inotify_init1:
181 0 : *result = syscall_no_intercept_wrapper(syscall_number,
182 : static_cast<int>(arg0));
183 :
184 0 : if(*result >= 0) {
185 0 : *result = CTX->register_internal_fd(*result);
186 : }
187 :
188 : break;
189 :
190 0 : case SYS_perf_event_open:
191 0 : *result = syscall_no_intercept_wrapper(
192 : syscall_number,
193 : reinterpret_cast<struct perf_event_attr*>(arg0),
194 : static_cast<pid_t>(arg1), static_cast<int>(arg2),
195 : static_cast<int>(arg3), static_cast<unsigned long>(arg4));
196 :
197 0 : if(*result >= 0) {
198 0 : *result = CTX->register_internal_fd(*result);
199 : }
200 : break;
201 : #ifdef SYS_signalfd
202 0 : case SYS_signalfd:
203 0 : *result = syscall_no_intercept_wrapper(
204 : syscall_number, static_cast<int>(arg0),
205 : reinterpret_cast<const sigset_t*>(arg1));
206 :
207 0 : if(*result >= 0) {
208 0 : *result = CTX->register_internal_fd(*result);
209 : }
210 : break;
211 : #endif
212 0 : case SYS_signalfd4:
213 0 : *result = syscall_no_intercept_wrapper(
214 : syscall_number, static_cast<int>(arg0),
215 : reinterpret_cast<const sigset_t*>(arg1),
216 : static_cast<int>(arg2));
217 :
218 0 : if(*result >= 0) {
219 0 : *result = CTX->register_internal_fd(*result);
220 : }
221 : break;
222 :
223 0 : case SYS_timerfd_create:
224 0 : *result = syscall_no_intercept_wrapper(syscall_number,
225 : static_cast<int>(arg0),
226 : static_cast<int>(arg1));
227 :
228 0 : if(*result >= 0) {
229 0 : *result = CTX->register_internal_fd(*result);
230 : }
231 : break;
232 :
233 :
234 1984 : case SYS_socket:
235 1984 : *result = syscall_no_intercept_wrapper(
236 : syscall_number, static_cast<int>(arg0),
237 : static_cast<int>(arg1), static_cast<int>(arg2));
238 :
239 1984 : if(*result >= 0) {
240 1984 : *result = CTX->register_internal_fd(*result);
241 : }
242 : break;
243 :
244 992 : case SYS_socketpair:
245 :
246 992 : *result = syscall_no_intercept_wrapper(
247 : syscall_number, static_cast<int>(arg0),
248 : static_cast<int>(arg1), static_cast<int>(arg2),
249 : reinterpret_cast<int*>(arg3));
250 :
251 992 : if(*result >= 0) {
252 992 : reinterpret_cast<int*>(arg3)[0] = CTX->register_internal_fd(
253 : reinterpret_cast<int*>(arg3)[0]);
254 1984 : reinterpret_cast<int*>(arg3)[1] = CTX->register_internal_fd(
255 992 : reinterpret_cast<int*>(arg3)[1]);
256 : }
257 :
258 : break;
259 : #ifdef SYS_pipe
260 0 : case SYS_pipe:
261 0 : *result = syscall_no_intercept_wrapper(
262 : syscall_number, reinterpret_cast<int*>(arg0));
263 :
264 0 : if(*result >= 0) {
265 0 : reinterpret_cast<int*>(arg0)[0] = CTX->register_internal_fd(
266 : reinterpret_cast<int*>(arg0)[0]);
267 0 : reinterpret_cast<int*>(arg0)[1] = CTX->register_internal_fd(
268 0 : reinterpret_cast<int*>(arg0)[1]);
269 : }
270 :
271 : break;
272 : #endif
273 0 : case SYS_pipe2:
274 :
275 0 : *result = syscall_no_intercept_wrapper(syscall_number,
276 : reinterpret_cast<int*>(arg0),
277 : static_cast<int>(arg1));
278 0 : if(*result >= 0) {
279 0 : reinterpret_cast<int*>(arg0)[0] = CTX->register_internal_fd(
280 : reinterpret_cast<int*>(arg0)[0]);
281 0 : reinterpret_cast<int*>(arg0)[1] = CTX->register_internal_fd(
282 0 : reinterpret_cast<int*>(arg0)[1]);
283 : }
284 :
285 : break;
286 : #ifdef SYS_eventfd
287 0 : case SYS_eventfd:
288 :
289 0 : *result = syscall_no_intercept_wrapper(syscall_number,
290 : static_cast<int>(arg0));
291 :
292 0 : if(*result >= 0) {
293 0 : *result = CTX->register_internal_fd(*result);
294 : }
295 : break;
296 : #endif
297 248 : case SYS_eventfd2:
298 :
299 248 : *result = syscall_no_intercept_wrapper(syscall_number,
300 : static_cast<int>(arg0),
301 : static_cast<int>(arg1));
302 :
303 248 : if(*result >= 0) {
304 248 : *result = CTX->register_internal_fd(*result);
305 : }
306 : break;
307 :
308 2976 : case SYS_recvmsg: {
309 2976 : *result = syscall_no_intercept_wrapper(
310 : syscall_number, static_cast<int>(arg0),
311 : reinterpret_cast<struct msghdr*>(arg1),
312 : static_cast<int>(arg2));
313 :
314 : // The recvmsg() syscall can receive file descriptors from another
315 : // process that the kernel automatically adds to the client's fds
316 : // as if dup2 had been called. Whenever that happens, we need to
317 : // make sure that we register these additional fds as internal, or
318 : // we could inadvertently overwrite them
319 2976 : if(*result >= 0) {
320 2976 : auto* hdr = reinterpret_cast<struct msghdr*>(arg1);
321 2976 : struct cmsghdr* cmsg = CMSG_FIRSTHDR(hdr);
322 :
323 2976 : for(; cmsg != NULL; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
324 0 : if(cmsg->cmsg_type == SCM_RIGHTS) {
325 :
326 0 : size_t nfd = cmsg->cmsg_len > CMSG_LEN(0)
327 0 : ? (cmsg->cmsg_len - CMSG_LEN(0)) /
328 : sizeof(int)
329 : : 0;
330 :
331 0 : int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
332 :
333 0 : for(size_t i = 0; i < nfd; ++i) {
334 0 : LOG(DEBUG, "recvmsg() provided extra fd {}",
335 0 : fds[i]);
336 :
337 : // ensure we update the fds in cmsg
338 : // if they have been relocated
339 0 : fds[i] = CTX->register_internal_fd(fds[i]);
340 : }
341 : }
342 : }
343 : }
344 :
345 : break;
346 : }
347 :
348 0 : case SYS_accept:
349 0 : *result = syscall_no_intercept_wrapper(
350 : syscall_number, static_cast<int>(arg0),
351 : reinterpret_cast<struct sockaddr*>(arg1),
352 : reinterpret_cast<int*>(arg2));
353 :
354 0 : if(*result >= 0) {
355 0 : *result = CTX->register_internal_fd(*result);
356 : }
357 : break;
358 :
359 0 : case SYS_accept4:
360 0 : *result = syscall_no_intercept_wrapper(
361 : syscall_number, static_cast<int>(arg0),
362 : reinterpret_cast<struct sockaddr*>(arg1),
363 : reinterpret_cast<int*>(arg2), static_cast<int>(arg3));
364 :
365 0 : if(*result >= 0) {
366 0 : *result = CTX->register_internal_fd(*result);
367 : }
368 : break;
369 :
370 :
371 3472 : case SYS_fcntl:
372 3472 : *result = syscall_no_intercept_wrapper(
373 : syscall_number, static_cast<int>(arg0),
374 : static_cast<int>(arg1), arg2);
375 :
376 3472 : if(*result >= 0) {
377 :
378 :
379 3472 : if((static_cast<int>(arg1) == F_DUPFD ||
380 : static_cast<int>(arg1) == F_DUPFD_CLOEXEC)) {
381 0 : *result = CTX->register_internal_fd(*result);
382 : }
383 : }
384 : break;
385 :
386 9424 : case SYS_close:
387 9424 : *result = syscall_no_intercept_wrapper(syscall_number,
388 : static_cast<int>(arg0));
389 9424 : if(*result >= 0) {
390 9424 : CTX->unregister_internal_fd(arg0);
391 : }
392 : break;
393 :
394 3206634 : default:
395 : // ignore any other syscalls, i.e.: pass them on to the kernel
396 : // (syscalls forwarded to the kernel that return are logged in
397 : // hook_forwarded_syscall())
398 3206634 : ::save_current_syscall_info(gkfs::syscall::from_internal_code |
399 : gkfs::syscall::to_kernel |
400 : gkfs::syscall::not_executed);
401 3206634 : return gkfs::syscall::forward_to_kernel;
402 : }
403 :
404 29016 : LOG(SYSCALL,
405 : gkfs::syscall::from_internal_code | gkfs::syscall::to_hook |
406 : gkfs::syscall::executed,
407 : syscall_number, args, *result);
408 :
409 : return gkfs::syscall::hooked;
410 : }
411 :
412 : /*
413 : * hook -- interception hook for application syscalls
414 : *
415 : * This hook is used to implement any application filesystem-related syscalls.
416 : */
417 : inline int
418 8114956 : hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4,
419 : long arg5, long* result) {
420 :
421 : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
422 8114956 : const long args[gkfs::syscall::MAX_ARGS] = {arg0, arg1, arg2,
423 8114956 : arg3, arg4, arg5};
424 : #endif
425 :
426 8114956 : LOG(SYSCALL,
427 : gkfs::syscall::from_external_code | gkfs::syscall::to_hook |
428 : gkfs::syscall::not_executed,
429 8118873 : syscall_number, args);
430 :
431 8118873 : switch(syscall_number) {
432 :
433 0 : case SYS_execve:
434 0 : *result = syscall_no_intercept_wrapper(
435 : syscall_number, reinterpret_cast<const char*>(arg0),
436 : reinterpret_cast<const char* const*>(arg1),
437 : reinterpret_cast<const char* const*>(arg2));
438 0 : break;
439 :
440 : #ifdef SYS_execveat
441 0 : case SYS_execveat:
442 0 : *result = syscall_no_intercept_wrapper(
443 : syscall_number, arg0, reinterpret_cast<const char*>(arg1),
444 : reinterpret_cast<const char* const*>(arg2),
445 : reinterpret_cast<const char* const*>(arg3), arg4);
446 0 : break;
447 : #endif
448 : #ifdef SYS_open
449 1 : case SYS_open:
450 1 : *result = gkfs::hook::hook_openat(
451 : AT_FDCWD, reinterpret_cast<char*>(arg0),
452 : static_cast<int>(arg1), static_cast<mode_t>(arg2));
453 1 : break;
454 : #endif
455 : #ifdef SYS_creat
456 1004 : case SYS_creat:
457 1004 : *result = gkfs::hook::hook_openat(
458 : AT_FDCWD, reinterpret_cast<const char*>(arg0),
459 : O_WRONLY | O_CREAT | O_TRUNC, static_cast<mode_t>(arg1));
460 1004 : break;
461 : #endif
462 8049 : case SYS_openat:
463 8049 : *result = gkfs::hook::hook_openat(
464 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
465 : static_cast<int>(arg2), static_cast<mode_t>(arg3));
466 8049 : break;
467 :
468 11857 : case SYS_close:
469 11857 : *result = gkfs::hook::hook_close(static_cast<int>(arg0));
470 11857 : break;
471 : #ifdef SYS_stat
472 46 : case SYS_stat:
473 92 : *result =
474 46 : gkfs::hook::hook_stat(reinterpret_cast<char*>(arg0),
475 : reinterpret_cast<struct stat*>(arg1));
476 46 : break;
477 : #endif
478 : #ifdef STATX_TYPE
479 4 : case SYS_statx:
480 4 : *result = gkfs::hook::hook_statx(
481 : static_cast<int>(arg0), reinterpret_cast<char*>(arg1),
482 : static_cast<int>(arg2), static_cast<unsigned int>(arg3),
483 : reinterpret_cast<struct statx*>(arg4));
484 4 : break;
485 : #endif
486 : #ifdef SYS_lstat
487 2 : case SYS_lstat:
488 2 : *result = gkfs::hook::hook_lstat(
489 : reinterpret_cast<char*>(arg0),
490 : reinterpret_cast<struct stat*>(arg1));
491 2 : break;
492 : #endif
493 267 : case SYS_fstat:
494 267 : *result = gkfs::hook::hook_fstat(
495 : static_cast<int>(arg0),
496 : reinterpret_cast<struct stat*>(arg1));
497 267 : break;
498 :
499 0 : case SYS_newfstatat:
500 0 : *result = gkfs::hook::hook_fstatat(
501 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
502 : reinterpret_cast<struct stat*>(arg2),
503 : static_cast<int>(arg3));
504 0 : break;
505 :
506 168373 : case SYS_read:
507 168373 : *result = gkfs::hook::hook_read(static_cast<unsigned int>(arg0),
508 : reinterpret_cast<void*>(arg1),
509 : static_cast<size_t>(arg2));
510 168373 : break;
511 :
512 2 : case SYS_pread64:
513 2 : *result = gkfs::hook::hook_pread(static_cast<unsigned int>(arg0),
514 : reinterpret_cast<char*>(arg1),
515 : static_cast<size_t>(arg2),
516 : static_cast<loff_t>(arg3));
517 2 : break;
518 :
519 1 : case SYS_readv:
520 1 : *result = gkfs::hook::hook_readv(
521 : static_cast<unsigned long>(arg0),
522 : reinterpret_cast<const struct iovec*>(arg1),
523 : static_cast<unsigned long>(arg2));
524 1 : break;
525 :
526 1 : case SYS_preadv:
527 1 : *result = gkfs::hook::hook_preadv(
528 : static_cast<unsigned long>(arg0),
529 : reinterpret_cast<const struct iovec*>(arg1),
530 : static_cast<unsigned long>(arg2),
531 : static_cast<unsigned long>(arg3),
532 : static_cast<unsigned long>(arg4));
533 1 : break;
534 :
535 3 : case SYS_pwrite64:
536 3 : *result = gkfs::hook::hook_pwrite(
537 : static_cast<unsigned int>(arg0),
538 : reinterpret_cast<const char*>(arg1),
539 : static_cast<size_t>(arg2), static_cast<loff_t>(arg3));
540 3 : break;
541 166680 : case SYS_write:
542 333360 : *result =
543 166680 : gkfs::hook::hook_write(static_cast<unsigned int>(arg0),
544 : reinterpret_cast<const char*>(arg1),
545 : static_cast<size_t>(arg2));
546 166680 : break;
547 :
548 2 : case SYS_writev:
549 2 : *result = gkfs::hook::hook_writev(
550 : static_cast<unsigned long>(arg0),
551 : reinterpret_cast<const struct iovec*>(arg1),
552 : static_cast<unsigned long>(arg2));
553 2 : break;
554 :
555 2 : case SYS_pwritev:
556 2 : *result = gkfs::hook::hook_pwritev(
557 : static_cast<unsigned long>(arg0),
558 : reinterpret_cast<const struct iovec*>(arg1),
559 : static_cast<unsigned long>(arg2),
560 : static_cast<unsigned long>(arg3),
561 : static_cast<unsigned long>(arg4));
562 2 : break;
563 : #ifdef SYS_unlink
564 6 : case SYS_unlink:
565 6 : *result = gkfs::hook::hook_unlinkat(
566 : AT_FDCWD, reinterpret_cast<const char*>(arg0), 0);
567 6 : break;
568 : #endif
569 1 : case SYS_unlinkat:
570 1 : *result = gkfs::hook::hook_unlinkat(
571 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
572 : static_cast<int>(arg2));
573 1 : break;
574 : #ifdef SYS_rmdir
575 8 : case SYS_rmdir:
576 8 : *result = gkfs::hook::hook_unlinkat(
577 : AT_FDCWD, reinterpret_cast<const char*>(arg0),
578 : AT_REMOVEDIR);
579 8 : break;
580 : #endif
581 : #ifdef SYS_symlink
582 1 : case SYS_symlink:
583 1 : *result = gkfs::hook::hook_symlinkat(
584 : reinterpret_cast<const char*>(arg0), AT_FDCWD,
585 : reinterpret_cast<const char*>(arg1));
586 1 : break;
587 : #endif
588 0 : case SYS_symlinkat:
589 0 : *result = gkfs::hook::hook_symlinkat(
590 : reinterpret_cast<const char*>(arg0), static_cast<int>(arg1),
591 : reinterpret_cast<const char*>(arg2));
592 0 : break;
593 : #ifdef SYS_access
594 5 : case SYS_access:
595 10 : *result =
596 5 : gkfs::hook::hook_access(reinterpret_cast<const char*>(arg0),
597 : static_cast<int>(arg1));
598 5 : break;
599 : #endif
600 4 : case SYS_faccessat:
601 4 : *result = gkfs::hook::hook_faccessat(
602 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
603 : static_cast<int>(arg2));
604 4 : break;
605 : #ifdef SYS_faccessat2
606 : case SYS_faccessat2:
607 : *result = gkfs::hook::hook_faccessat2(
608 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
609 : static_cast<int>(arg2), static_cast<int>(arg3));
610 : break;
611 : #endif
612 7917 : case SYS_lseek:
613 7917 : *result = gkfs::hook::hook_lseek(static_cast<unsigned int>(arg0),
614 : static_cast<off_t>(arg1),
615 : static_cast<unsigned int>(arg2));
616 7917 : break;
617 :
618 7 : case SYS_truncate:
619 7 : *result = gkfs::hook::hook_truncate(
620 : reinterpret_cast<const char*>(arg0),
621 : static_cast<long>(arg1));
622 7 : break;
623 :
624 2 : case SYS_ftruncate:
625 2 : *result = gkfs::hook::hook_ftruncate(
626 : static_cast<unsigned int>(arg0),
627 : static_cast<unsigned long>(arg1));
628 2 : break;
629 :
630 2 : case SYS_dup:
631 2 : *result = gkfs::hook::hook_dup(static_cast<unsigned int>(arg0));
632 2 : break;
633 : #ifdef SYS_dup2
634 2 : case SYS_dup2:
635 2 : *result = gkfs::hook::hook_dup2(static_cast<unsigned int>(arg0),
636 : static_cast<unsigned int>(arg1));
637 2 : break;
638 : #endif
639 2 : case SYS_dup3:
640 2 : *result = gkfs::hook::hook_dup3(static_cast<unsigned int>(arg0),
641 : static_cast<unsigned int>(arg1),
642 : static_cast<int>(arg2));
643 2 : break;
644 : #ifdef SYS_getdents
645 0 : case SYS_getdents:
646 0 : *result = gkfs::hook::hook_getdents(
647 : static_cast<unsigned int>(arg0),
648 : reinterpret_cast<struct linux_dirent*>(arg1),
649 : static_cast<unsigned int>(arg2));
650 0 : break;
651 : #endif
652 30 : case SYS_getdents64:
653 30 : *result = gkfs::hook::hook_getdents64(
654 : static_cast<unsigned int>(arg0),
655 : reinterpret_cast<struct linux_dirent64*>(arg1),
656 : static_cast<unsigned int>(arg2));
657 30 : break;
658 :
659 1 : case SYS_mkdirat:
660 1 : *result = gkfs::hook::hook_mkdirat(
661 : static_cast<unsigned int>(arg0),
662 : reinterpret_cast<const char*>(arg1),
663 : static_cast<mode_t>(arg2));
664 1 : break;
665 : #ifdef SYS_mkdir
666 18 : case SYS_mkdir:
667 18 : *result = gkfs::hook::hook_mkdirat(
668 : AT_FDCWD, reinterpret_cast<const char*>(arg0),
669 : static_cast<mode_t>(arg1));
670 18 : break;
671 : #endif
672 : #ifdef SYS_chmod
673 1 : case SYS_chmod:
674 1 : *result = gkfs::hook::hook_fchmodat(AT_FDCWD,
675 : reinterpret_cast<char*>(arg0),
676 : static_cast<mode_t>(arg1));
677 1 : break;
678 : #endif
679 2 : case SYS_fchmod:
680 2 : *result = gkfs::hook::hook_fchmod(static_cast<unsigned int>(arg0),
681 : static_cast<mode_t>(arg1));
682 2 : break;
683 :
684 2 : case SYS_fchmodat:
685 2 : *result = gkfs::hook::hook_fchmodat(static_cast<unsigned int>(arg0),
686 : reinterpret_cast<char*>(arg1),
687 : static_cast<mode_t>(arg2));
688 2 : break;
689 :
690 0 : case SYS_flock:
691 0 : *result = gkfs::hook::hook_flock(static_cast<unsigned int>(arg0),
692 : static_cast<unsigned int>(arg1));
693 0 : break;
694 9 : case SYS_chdir:
695 18 : *result =
696 9 : gkfs::hook::hook_chdir(reinterpret_cast<const char*>(arg0));
697 9 : break;
698 :
699 3 : case SYS_fchdir:
700 3 : *result = gkfs::hook::hook_fchdir(static_cast<unsigned int>(arg0));
701 3 : break;
702 :
703 5 : case SYS_getcwd:
704 5 : *result = gkfs::hook::hook_getcwd(reinterpret_cast<char*>(arg0),
705 : static_cast<unsigned long>(arg1));
706 5 : break;
707 : #ifdef SYS_readlink
708 0 : case SYS_readlink:
709 0 : *result = gkfs::hook::hook_readlinkat(
710 : AT_FDCWD, reinterpret_cast<const char*>(arg0),
711 : reinterpret_cast<char*>(arg1), static_cast<int>(arg2));
712 0 : break;
713 : #endif
714 1 : case SYS_readlinkat:
715 1 : *result = gkfs::hook::hook_readlinkat(
716 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
717 : reinterpret_cast<char*>(arg2), static_cast<int>(arg3));
718 1 : break;
719 :
720 15816 : case SYS_fcntl:
721 15816 : *result = gkfs::hook::hook_fcntl(static_cast<unsigned int>(arg0),
722 : static_cast<unsigned int>(arg1),
723 : static_cast<unsigned long>(arg2));
724 15816 : break;
725 : #ifdef SYS_rename
726 12 : case SYS_rename:
727 12 : *result = gkfs::hook::hook_renameat(
728 : AT_FDCWD, reinterpret_cast<const char*>(arg0), AT_FDCWD,
729 : reinterpret_cast<const char*>(arg1), 0);
730 12 : break;
731 : #endif
732 2 : case SYS_renameat:
733 2 : *result = gkfs::hook::hook_renameat(
734 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
735 : static_cast<int>(arg2), reinterpret_cast<const char*>(arg3),
736 : 0);
737 2 : break;
738 :
739 0 : case SYS_renameat2:
740 0 : *result = gkfs::hook::hook_renameat(
741 : static_cast<int>(arg0), reinterpret_cast<const char*>(arg1),
742 : static_cast<int>(arg2), reinterpret_cast<const char*>(arg3),
743 : static_cast<unsigned int>(arg4));
744 0 : break;
745 :
746 2 : case SYS_fstatfs:
747 2 : *result = gkfs::hook::hook_fstatfs(
748 : static_cast<unsigned int>(arg0),
749 : reinterpret_cast<struct statfs*>(arg1));
750 2 : break;
751 :
752 1 : case SYS_statfs:
753 1 : *result = gkfs::hook::hook_statfs(
754 : reinterpret_cast<const char*>(arg0),
755 : reinterpret_cast<struct statfs*>(arg1));
756 1 : break;
757 :
758 1 : case SYS_fdatasync:
759 1 : case SYS_fsync:
760 1 : *result = gkfs::hook::hook_fsync(static_cast<unsigned int>(arg0));
761 1 : break;
762 :
763 1 : case SYS_getxattr:
764 1 : *result = gkfs::hook::hook_getxattr(
765 : reinterpret_cast<const char*>(arg0),
766 : reinterpret_cast<const char*>(arg1),
767 : reinterpret_cast<void*>(arg2), static_cast<size_t>(arg4));
768 1 : break;
769 :
770 7738715 : default:
771 : // ignore any other syscalls, i.e.: pass them on to the kernel
772 : // (syscalls forwarded to the kernel that return are logged in
773 : // hook_forwarded_syscall())
774 7738715 : ::save_current_syscall_info(gkfs::syscall::from_external_code |
775 : gkfs::syscall::to_kernel |
776 : gkfs::syscall::not_executed);
777 7738715 : return gkfs::syscall::forward_to_kernel;
778 : }
779 :
780 380158 : LOG(SYSCALL,
781 : gkfs::syscall::from_external_code | gkfs::syscall::to_hook |
782 : gkfs::syscall::executed,
783 : syscall_number, args, *result);
784 :
785 : return gkfs::syscall::hooked;
786 : }
787 :
788 : #ifdef SYS_socketcall
789 : /* Wraps socketcall in powerpc9, we only change syscalls that need special
790 : * treatment */
791 : long
792 : socketcall_wrapper(long syscall_number, long& arg0, long& arg1, long& arg2,
793 : long& arg3, long& arg4, long& arg5) {
794 :
795 : switch(static_cast<int>(arg0)) {
796 : case 1:
797 : syscall_number = SYS_socket;
798 : break;
799 : case 5:
800 : syscall_number = SYS_accept;
801 : break;
802 :
803 : case 17:
804 : syscall_number = SYS_recvmsg;
805 : break;
806 : case 18:
807 : syscall_number = SYS_accept4;
808 : break;
809 : case 19:
810 : syscall_number = SYS_recvmmsg;
811 : break;
812 :
813 : default:
814 : break;
815 : }
816 : if(syscall_number != SYS_socketcall) {
817 : long int* parameters = (long int*) arg1;
818 : arg0 = static_cast<long>(*parameters);
819 : parameters++;
820 : arg1 = static_cast<long>(*parameters);
821 : parameters++;
822 : arg2 = static_cast<long>(*parameters);
823 : parameters++;
824 : arg3 = static_cast<long>(*parameters);
825 : parameters++;
826 : arg4 = static_cast<long>(*parameters);
827 : parameters++;
828 : arg5 = static_cast<long>(*parameters);
829 : }
830 :
831 : return syscall_number;
832 : }
833 : #endif
834 :
835 :
836 : void
837 10943257 : hook_forwarded_syscall(long syscall_number, long arg0, long arg1, long arg2,
838 : long arg3, long arg4, long arg5, long result) {
839 :
840 10943257 : if(::get_current_syscall_info() == gkfs::syscall::no_info) {
841 0 : return;
842 : }
843 :
844 : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
845 10943257 : const long args[gkfs::syscall::MAX_ARGS] = {arg0, arg1, arg2,
846 10943257 : arg3, arg4, arg5};
847 : #endif
848 :
849 10943257 : LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
850 10942951 : syscall_number, args, result);
851 :
852 10942951 : ::reset_current_syscall_info();
853 : }
854 :
855 : void
856 992 : hook_clone_at_child(unsigned long flags, void* child_stack, int* ptid,
857 : int* ctid, long newtls) {
858 :
859 : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
860 992 : const long args[gkfs::syscall::MAX_ARGS] = {
861 992 : static_cast<long>(flags), reinterpret_cast<long>(child_stack),
862 : reinterpret_cast<long>(ptid), reinterpret_cast<long>(ctid),
863 992 : static_cast<long>(newtls), 0};
864 : #endif
865 :
866 992 : reentrance_guard_flag = true;
867 :
868 992 : LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
869 992 : SYS_clone, args, 0);
870 :
871 992 : reentrance_guard_flag = false;
872 992 : }
873 :
874 : void
875 992 : hook_clone_at_parent(unsigned long flags, void* child_stack, int* ptid,
876 : int* ctid, long newtls, long returned_pid) {
877 :
878 : #if defined(GKFS_ENABLE_LOGGING) && defined(GKFS_DEBUG_BUILD)
879 992 : const long args[gkfs::syscall::MAX_ARGS] = {
880 992 : static_cast<long>(flags), reinterpret_cast<long>(child_stack),
881 : reinterpret_cast<long>(ptid), reinterpret_cast<long>(ctid),
882 992 : static_cast<long>(newtls), 0};
883 : #endif
884 :
885 992 : reentrance_guard_flag = true;
886 :
887 992 : LOG(SYSCALL, ::get_current_syscall_info() | gkfs::syscall::executed,
888 992 : SYS_clone, args, returned_pid);
889 :
890 992 : reentrance_guard_flag = false;
891 992 : }
892 :
893 : } // namespace
894 :
895 : namespace gkfs::preload {
896 :
897 : int
898 3111374 : internal_hook_guard_wrapper(long syscall_number, long arg0, long arg1,
899 : long arg2, long arg3, long arg4, long arg5,
900 : long* syscall_return_value) {
901 3111374 : assert(CTX->interception_enabled());
902 :
903 : #ifdef SYS_socketcall
904 : if(syscall_number == SYS_socketcall)
905 : syscall_number = socketcall_wrapper(syscall_number, arg0, arg1, arg2,
906 : arg3, arg4, arg5);
907 : #endif
908 :
909 3111274 : if(reentrance_guard_flag) {
910 0 : ::save_current_syscall_info(gkfs::syscall::from_internal_code |
911 : gkfs::syscall::to_kernel |
912 : gkfs::syscall::not_executed);
913 0 : return gkfs::syscall::forward_to_kernel;
914 : }
915 :
916 3111274 : int was_hooked = 0;
917 :
918 3111274 : reentrance_guard_flag = true;
919 3111274 : was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
920 : arg5, syscall_return_value);
921 3111219 : reentrance_guard_flag = false;
922 :
923 3111219 : return was_hooked;
924 : }
925 :
926 :
927 : /*
928 : * hook_guard_wrapper -- a wrapper which can notice reentrance.
929 : *
930 : * The reentrance_guard_flag flag allows the library to distinguish the hooking
931 : * of its own syscalls. E.g. while handling an open() syscall,
932 : * libgkfs_intercept might call fopen(), which in turn uses an open()
933 : * syscall internally. This internally used open() syscall is once again
934 : * forwarded to libgkfs_intercept, but using this flag we can notice this
935 : * case of reentering itself.
936 : *
937 : * XXX This approach still contains a very significant bug, as libgkfs_intercept
938 : * being called inside a signal handler might easily forward a mock fd to the
939 : * kernel.
940 : */
941 : int
942 8240619 : hook_guard_wrapper(long syscall_number, long arg0, long arg1, long arg2,
943 : long arg3, long arg4, long arg5,
944 : long* syscall_return_value) {
945 :
946 8240619 : assert(CTX->interception_enabled());
947 :
948 : #ifdef SYS_socketcall
949 : if(syscall_number == SYS_socketcall)
950 : syscall_number = socketcall_wrapper(syscall_number, arg0, arg1, arg2,
951 : arg3, arg4, arg5);
952 : #endif
953 :
954 8239863 : int was_hooked = 0;
955 :
956 8239863 : if(reentrance_guard_flag) {
957 :
958 124381 : was_hooked = hook_internal(syscall_number, arg0, arg1, arg2, arg3, arg4,
959 : arg5, syscall_return_value);
960 124381 : return was_hooked;
961 : }
962 :
963 8115482 : reentrance_guard_flag = true;
964 :
965 8115482 : was_hooked = ::hook(syscall_number, arg0, arg1, arg2, arg3, arg4, arg5,
966 : syscall_return_value);
967 :
968 8115625 : reentrance_guard_flag = false;
969 :
970 8115625 : return was_hooked;
971 : }
972 :
973 : void
974 248 : start_self_interception() {
975 :
976 248 : LOG(DEBUG, "Enabling syscall interception for self");
977 :
978 248 : intercept_hook_point = internal_hook_guard_wrapper;
979 248 : intercept_hook_point_post_kernel = hook_forwarded_syscall;
980 248 : intercept_hook_point_clone_child = hook_clone_at_child;
981 248 : intercept_hook_point_clone_parent = hook_clone_at_parent;
982 248 : }
983 :
984 : void
985 248 : start_interception() {
986 :
987 248 : assert(CTX->interception_enabled());
988 :
989 248 : LOG(DEBUG, "Enabling syscall interception for client process");
990 :
991 : // Set up the callback function pointer
992 248 : intercept_hook_point = hook_guard_wrapper;
993 248 : intercept_hook_point_post_kernel = hook_forwarded_syscall;
994 248 : intercept_hook_point_clone_child = hook_clone_at_child;
995 248 : intercept_hook_point_clone_parent = hook_clone_at_parent;
996 248 : }
997 :
998 : void
999 248 : stop_interception() {
1000 248 : assert(CTX->interception_enabled());
1001 :
1002 248 : LOG(DEBUG, "Disabling syscall interception for client process");
1003 :
1004 : // Reset callback function pointer
1005 248 : intercept_hook_point = nullptr;
1006 248 : intercept_hook_point_post_kernel = nullptr;
1007 248 : intercept_hook_point_clone_child = nullptr;
1008 248 : intercept_hook_point_clone_parent = nullptr;
1009 248 : }
1010 :
1011 : } // namespace gkfs::preload
|