1 /* 2 * Apply a compiled cBPF seccomp filter to a freshly-execve'd workload by 3 * injecting prctl(PR_SET_NO_NEW_PRIVS) and seccomp(SET_MODE_FILTER) into the 4 * tracee via ptrace. The tracee does PTRACE_TRACEME before its final execve; 5 * the parent catches the post-execve stop (before the workload's first 6 * userspace instruction), pokes the filter into the tracee's stack, drives the 7 * two syscalls by single-stepping a temporary trap instruction at the program 8 * counter, restores the saved registers and code, then detaches. This arms the 9 * filter for statically and dynamically linked workloads alike, closing the 10 * gap left by an LD_PRELOAD-based installer (which static binaries ignore). 11 * 12 * Copyright (C) 2026 Daniel Golle <daniel@makrotopia.org> 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU Lesser General Public License version 2.1 16 * as published by the Free Software Foundation 17 * 18 * This program 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 General Public License for more details. 22 */ 23 #define _GNU_SOURCE 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <signal.h> 27 #include <stdint.h> 28 #include <stdio.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <sys/ptrace.h> 32 #include <sys/uio.h> 33 #include <sys/user.h> 34 #include <sys/wait.h> 35 #include <linux/filter.h> 36 #include <linux/seccomp.h> 37 #include <sys/prctl.h> 38 #include <sys/syscall.h> 39 #include <limits.h> 40 41 #include "log.h" 42 #include "seccomp-inject.h" 43 #include "elf.h" 44 45 #ifndef PR_SET_NO_NEW_PRIVS 46 #define PR_SET_NO_NEW_PRIVS 38 47 #endif 48 #ifndef SECCOMP_SET_MODE_FILTER 49 #define SECCOMP_SET_MODE_FILTER 1 50 #endif 51 #ifndef AT_NULL 52 #define AT_NULL 0 53 #endif 54 #ifndef AT_ENTRY 55 #define AT_ENTRY 9 56 #endif 57 #ifndef AT_BASE 58 #define AT_BASE 7 59 #endif 60 #ifndef NT_PRSTATUS 61 #define NT_PRSTATUS 1 62 #endif 63 #ifndef NT_ARM_SYSTEM_CALL 64 #define NT_ARM_SYSTEM_CALL 0x404 65 #endif 66 #ifndef PTRACE_SET_SYSCALL 67 #define PTRACE_SET_SYSCALL 23 68 #endif 69 70 #if defined(__x86_64__) 71 typedef struct user_regs_struct inj_regs; 72 #define INJ_SYSCALL_ASM "syscall" 73 #define INJ_BP_ASM "int3" 74 static unsigned long inj_pc(const inj_regs *r) 75 { 76 return r->rip; 77 } 78 79 static void inj_set_pc(inj_regs *r, unsigned long pc) 80 { 81 r->rip = pc; 82 } 83 84 static unsigned long inj_sp(const inj_regs *r) 85 { 86 return r->rsp; 87 } 88 89 static long inj_ret(const inj_regs *r) 90 { 91 return r->rax; 92 } 93 94 static void inj_clear_restart(inj_regs *r) 95 { 96 r->orig_rax = (unsigned long)-1; 97 } 98 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 99 long a3, long a4, long a5) 100 { 101 r->rax = nr; 102 r->orig_rax = nr; 103 r->rdi = a0; 104 r->rsi = a1; 105 r->rdx = a2; 106 r->r10 = a3; 107 r->r8 = a4; 108 r->r9 = a5; 109 } 110 111 static void inj_get_call(const inj_regs *r, long *nr, long *args) 112 { 113 *nr = r->orig_rax; 114 args[0] = r->rdi; 115 args[1] = r->rsi; 116 args[2] = r->rdx; 117 args[3] = r->r10; 118 args[4] = r->r8; 119 args[5] = r->r9; 120 } 121 122 #elif defined(__i386__) 123 typedef struct user_regs_struct inj_regs; 124 #define INJ_SYSCALL_ASM "int $0x80" 125 #define INJ_BP_ASM "int3" 126 static unsigned long inj_pc(const inj_regs *r) 127 { 128 return r->eip; 129 } 130 131 static void inj_set_pc(inj_regs *r, unsigned long pc) 132 { 133 r->eip = pc; 134 } 135 136 static unsigned long inj_sp(const inj_regs *r) 137 { 138 return r->esp; 139 } 140 141 static long inj_ret(const inj_regs *r) 142 { 143 return r->eax; 144 } 145 146 static void inj_clear_restart(inj_regs *r) 147 { 148 r->orig_eax = (unsigned long)-1; 149 } 150 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 151 long a3, long a4, long a5) 152 { 153 r->eax = nr; 154 r->orig_eax = nr; 155 r->ebx = a0; 156 r->ecx = a1; 157 r->edx = a2; 158 r->esi = a3; 159 r->edi = a4; 160 r->ebp = a5; 161 } 162 163 static void inj_get_call(const inj_regs *r, long *nr, long *args) 164 { 165 *nr = r->orig_eax; 166 args[0] = r->ebx; 167 args[1] = r->ecx; 168 args[2] = r->edx; 169 args[3] = r->esi; 170 args[4] = r->edi; 171 args[5] = r->ebp; 172 } 173 174 #elif defined(__aarch64__) 175 typedef struct { unsigned long long regs[31], sp, pc, pstate; } inj_regs; 176 #define INJ_SYSCALL_ASM "svc #0" 177 #define INJ_BP_ASM "brk #0" 178 static unsigned long inj_pc(const inj_regs *r) 179 { 180 return r->pc; 181 } 182 183 static void inj_set_pc(inj_regs *r, unsigned long pc) 184 { 185 r->pc = pc; 186 } 187 188 static unsigned long inj_sp(const inj_regs *r) 189 { 190 return r->sp; 191 } 192 193 static long inj_ret(const inj_regs *r) 194 { 195 return r->regs[0]; 196 } 197 198 static void inj_clear_restart(inj_regs *r) 199 { 200 (void)r; 201 } 202 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 203 long a3, long a4, long a5) 204 { 205 r->regs[8] = nr; 206 r->regs[0] = a0; 207 r->regs[1] = a1; 208 r->regs[2] = a2; 209 r->regs[3] = a3; 210 r->regs[4] = a4; 211 r->regs[5] = a5; 212 } 213 214 static void inj_get_call(const inj_regs *r, long *nr, long *args) 215 { 216 *nr = r->regs[8]; 217 args[0] = r->regs[0]; 218 args[1] = r->regs[1]; 219 args[2] = r->regs[2]; 220 args[3] = r->regs[3]; 221 args[4] = r->regs[4]; 222 args[5] = r->regs[5]; 223 } 224 225 #elif defined(__arm__) 226 typedef struct { unsigned long uregs[18]; } inj_regs; 227 #define INJ_SYSCALL_ASM "svc #0" 228 static unsigned long inj_pc(const inj_regs *r) 229 { 230 return r->uregs[15]; 231 } 232 233 static void inj_set_pc(inj_regs *r, unsigned long pc) 234 { 235 r->uregs[15] = pc; 236 } 237 238 static unsigned long inj_sp(const inj_regs *r) 239 { 240 return r->uregs[13]; 241 } 242 243 static long inj_ret(const inj_regs *r) 244 { 245 return r->uregs[0]; 246 } 247 248 static void inj_clear_restart(inj_regs *r) __attribute__((unused)); 249 static void inj_clear_restart(inj_regs *r) 250 { 251 (void)r; 252 } 253 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 254 long a3, long a4, long a5) 255 { 256 r->uregs[7] = nr; 257 r->uregs[0] = a0; 258 r->uregs[1] = a1; 259 r->uregs[2] = a2; 260 r->uregs[3] = a3; 261 r->uregs[4] = a4; 262 r->uregs[5] = a5; 263 } 264 265 static void inj_get_call(const inj_regs *r, long *nr, long *args) 266 { 267 *nr = r->uregs[7]; 268 args[0] = r->uregs[0]; 269 args[1] = r->uregs[1]; 270 args[2] = r->uregs[2]; 271 args[3] = r->uregs[3]; 272 args[4] = r->uregs[4]; 273 args[5] = r->uregs[5]; 274 } 275 276 static int inj_thumb(const inj_regs *r) 277 { 278 return (r->uregs[16] >> 5) & 1; 279 } 280 281 #elif defined(__riscv) && __riscv_xlen == 64 282 typedef struct { 283 unsigned long pc, ra, sp, gp, tp, t0, t1, t2, s0, s1; 284 unsigned long a0, a1, a2, a3, a4, a5, a6, a7; 285 unsigned long s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; 286 unsigned long t3, t4, t5, t6; 287 } inj_regs; 288 #define INJ_SYSCALL_ASM "ecall" 289 #define INJ_BP_ASM "ebreak" 290 #define INJ_NO_SINGLESTEP 1 291 static unsigned long inj_pc(const inj_regs *r) 292 { 293 return r->pc; 294 } 295 296 static void inj_set_pc(inj_regs *r, unsigned long pc) 297 { 298 r->pc = pc; 299 } 300 301 static unsigned long inj_sp(const inj_regs *r) 302 { 303 return r->sp; 304 } 305 306 static long inj_ret(const inj_regs *r) 307 { 308 return r->a0; 309 } 310 311 static void inj_clear_restart(inj_regs *r) 312 { 313 (void)r; 314 } 315 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 316 long a3, long a4, long a5) 317 { 318 r->a7 = nr; 319 r->a0 = a0; 320 r->a1 = a1; 321 r->a2 = a2; 322 r->a3 = a3; 323 r->a4 = a4; 324 r->a5 = a5; 325 } 326 327 static void inj_get_call(const inj_regs *r, long *nr, long *args) 328 { 329 *nr = r->a7; 330 args[0] = r->a0; 331 args[1] = r->a1; 332 args[2] = r->a2; 333 args[3] = r->a3; 334 args[4] = r->a4; 335 args[5] = r->a5; 336 } 337 338 #elif defined(__loongarch__) && __loongarch_grlen == 64 339 typedef struct { unsigned long regs[32], orig_a0, csr_era, csr_badv, reserved[10]; } inj_regs; 340 #define INJ_SYSCALL_ASM "syscall 0" 341 #define INJ_BP_ASM "break 0" 342 #define INJ_NO_SINGLESTEP 1 343 static unsigned long inj_pc(const inj_regs *r) 344 { 345 return r->csr_era; 346 } 347 348 static void inj_set_pc(inj_regs *r, unsigned long pc) 349 { 350 r->csr_era = pc; 351 } 352 353 static unsigned long inj_sp(const inj_regs *r) 354 { 355 return r->regs[3]; 356 } 357 358 static long inj_ret(const inj_regs *r) 359 { 360 return r->regs[4]; 361 } 362 363 static void inj_clear_restart(inj_regs *r) 364 { 365 (void)r; 366 } 367 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 368 long a3, long a4, long a5) 369 { 370 r->regs[11] = nr; 371 r->regs[4] = a0; 372 r->regs[5] = a1; 373 r->regs[6] = a2; 374 r->regs[7] = a3; 375 r->regs[8] = a4; 376 r->regs[9] = a5; 377 } 378 379 static void inj_get_call(const inj_regs *r, long *nr, long *args) 380 { 381 *nr = r->regs[11]; 382 args[0] = r->regs[4]; 383 args[1] = r->regs[5]; 384 args[2] = r->regs[6]; 385 args[3] = r->regs[7]; 386 args[4] = r->regs[8]; 387 args[5] = r->regs[9]; 388 } 389 390 #elif defined(__mips__) 391 #ifndef ELF_NGREG 392 #define ELF_NGREG 45 393 #endif 394 #if _MIPS_SIM == _ABIO32 395 #define MIPS_EF_V0 8 396 #define MIPS_EF_A0 10 397 #define MIPS_EF_SP 35 398 #define MIPS_EF_A3 13 399 #define MIPS_EF_EPC 40 400 #else 401 #define MIPS_EF_V0 2 402 #define MIPS_EF_A0 4 403 #define MIPS_EF_SP 29 404 #define MIPS_EF_A3 7 405 #define MIPS_EF_EPC 34 406 #endif 407 typedef struct { unsigned long gregs[ELF_NGREG]; } inj_regs; 408 #define INJ_SYSCALL_ASM "syscall" 409 #define INJ_BP_ASM "break" 410 #define INJ_NO_SINGLESTEP 1 411 static unsigned long inj_pc(const inj_regs *r) 412 { 413 return r->gregs[MIPS_EF_EPC]; 414 } 415 416 static void inj_set_pc(inj_regs *r, unsigned long pc) 417 { 418 r->gregs[MIPS_EF_EPC] = pc; 419 } 420 421 static unsigned long inj_sp(const inj_regs *r) 422 { 423 return r->gregs[MIPS_EF_SP]; 424 } 425 426 #if _MIPS_SIM == _ABIO32 427 static void inj_set_sp(inj_regs *r, unsigned long sp) 428 { 429 r->gregs[MIPS_EF_SP] = sp; 430 } 431 #endif 432 433 static long inj_ret(const inj_regs *r) 434 { 435 if (r->gregs[MIPS_EF_A3]) 436 return -(long)r->gregs[MIPS_EF_V0]; 437 438 return r->gregs[MIPS_EF_V0]; 439 } 440 441 static void inj_clear_restart(inj_regs *r) 442 { 443 (void)r; 444 } 445 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 446 long a3, long a4, long a5) 447 { 448 r->gregs[MIPS_EF_V0] = nr; 449 r->gregs[MIPS_EF_A0] = a0; 450 r->gregs[MIPS_EF_A0 + 1] = a1; 451 r->gregs[MIPS_EF_A0 + 2] = a2; 452 r->gregs[MIPS_EF_A0 + 3] = a3; 453 #if _MIPS_SIM != _ABIO32 454 r->gregs[MIPS_EF_A0 + 4] = a4; 455 r->gregs[MIPS_EF_A0 + 5] = a5; 456 r->gregs[MIPS_EF_A0 + 6] = 0; 457 r->gregs[MIPS_EF_A0 + 7] = 0; 458 #else 459 (void)a4; 460 (void)a5; 461 #endif 462 } 463 464 static void inj_get_call(const inj_regs *r, long *nr, long *args) 465 { 466 *nr = r->gregs[MIPS_EF_V0]; 467 args[0] = r->gregs[MIPS_EF_A0]; 468 args[1] = r->gregs[MIPS_EF_A0 + 1]; 469 args[2] = r->gregs[MIPS_EF_A0 + 2]; 470 args[3] = r->gregs[MIPS_EF_A0 + 3]; 471 #if _MIPS_SIM != _ABIO32 472 args[4] = r->gregs[MIPS_EF_A0 + 4]; 473 args[5] = r->gregs[MIPS_EF_A0 + 5]; 474 #else 475 args[4] = 0; 476 args[5] = 0; 477 #endif 478 } 479 480 #elif defined(__powerpc64__) 481 typedef struct { 482 unsigned long gpr[32]; 483 unsigned long nip, msr, orig_gpr3, ctr, link, xer, ccr, softe; 484 unsigned long trap, dar, dsisr, result; 485 } inj_regs; 486 #define INJ_SYSCALL_ASM "sc" 487 #define INJ_BP_ASM "trap" 488 static unsigned long inj_pc(const inj_regs *r) 489 { 490 return r->nip; 491 } 492 493 static void inj_set_pc(inj_regs *r, unsigned long pc) 494 { 495 r->nip = pc; 496 } 497 498 static unsigned long inj_sp(const inj_regs *r) 499 { 500 return r->gpr[1]; 501 } 502 503 static long inj_ret(const inj_regs *r) 504 { 505 if (r->ccr & 0x10000000UL) 506 return -(long)r->gpr[3]; 507 return r->gpr[3]; 508 } 509 510 static void inj_clear_restart(inj_regs *r) 511 { 512 (void)r; 513 } 514 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 515 long a3, long a4, long a5) 516 { 517 r->gpr[0] = nr; 518 r->gpr[3] = a0; 519 r->gpr[4] = a1; 520 r->gpr[5] = a2; 521 r->gpr[6] = a3; 522 r->gpr[7] = a4; 523 r->gpr[8] = a5; 524 } 525 526 static void inj_get_call(const inj_regs *r, long *nr, long *args) 527 { 528 *nr = r->gpr[0]; 529 args[0] = r->gpr[3]; 530 args[1] = r->gpr[4]; 531 args[2] = r->gpr[5]; 532 args[3] = r->gpr[6]; 533 args[4] = r->gpr[7]; 534 args[5] = r->gpr[8]; 535 } 536 537 #elif defined(__powerpc__) 538 typedef struct { 539 unsigned long gpr[32]; 540 unsigned long nip, msr, orig_gpr3, ctr, link, xer, ccr, mq; 541 unsigned long trap, dar, dsisr, result; 542 } inj_regs; 543 #define INJ_SYSCALL_ASM "sc" 544 #define INJ_BP_ASM "trap" 545 static unsigned long inj_pc(const inj_regs *r) 546 { 547 return r->nip; 548 } 549 550 static void inj_set_pc(inj_regs *r, unsigned long pc) 551 { 552 r->nip = pc; 553 } 554 555 static unsigned long inj_sp(const inj_regs *r) 556 { 557 return r->gpr[1]; 558 } 559 560 static long inj_ret(const inj_regs *r) 561 { 562 if (r->ccr & 0x10000000UL) 563 return -(long)r->gpr[3]; 564 return r->gpr[3]; 565 } 566 567 static void inj_clear_restart(inj_regs *r) 568 { 569 (void)r; 570 } 571 static void inj_set_call(inj_regs *r, long nr, long a0, long a1, long a2, 572 long a3, long a4, long a5) 573 { 574 r->gpr[0] = nr; 575 r->gpr[3] = a0; 576 r->gpr[4] = a1; 577 r->gpr[5] = a2; 578 r->gpr[6] = a3; 579 r->gpr[7] = a4; 580 r->gpr[8] = a5; 581 } 582 583 static void inj_get_call(const inj_regs *r, long *nr, long *args) 584 { 585 *nr = r->gpr[0]; 586 args[0] = r->gpr[3]; 587 args[1] = r->gpr[4]; 588 args[2] = r->gpr[5]; 589 args[3] = r->gpr[6]; 590 args[4] = r->gpr[7]; 591 args[5] = r->gpr[8]; 592 } 593 594 #else 595 #error "unsupported architecture for seccomp ptrace injection" 596 #endif 597 598 #if defined(__arm__) 599 __asm__ ( 600 ".pushsection .text\n" 601 ".arm\n" 602 ".globl inj_syscall_insn_arm\ninj_syscall_insn_arm:\n\t" INJ_SYSCALL_ASM "\n" 603 ".globl inj_syscall_insn_arm_end\ninj_syscall_insn_arm_end:\n" 604 ".globl inj_bp_insn_arm\ninj_bp_insn_arm:\n\t.inst 0xe7f001f0\n" 605 ".globl inj_bp_insn_arm_end\ninj_bp_insn_arm_end:\n" 606 ".thumb\n" 607 ".globl inj_syscall_insn_thumb\ninj_syscall_insn_thumb:\n\t" INJ_SYSCALL_ASM "\n" 608 ".globl inj_syscall_insn_thumb_end\ninj_syscall_insn_thumb_end:\n" 609 ".globl inj_bp_insn_thumb\ninj_bp_insn_thumb:\n\t.inst.n 0xde01\n" 610 ".globl inj_bp_insn_thumb_end\ninj_bp_insn_thumb_end:\n" 611 ".popsection\n" 612 ); 613 extern const unsigned char inj_syscall_insn_arm[], inj_syscall_insn_arm_end[]; 614 extern const unsigned char inj_syscall_insn_thumb[], inj_syscall_insn_thumb_end[]; 615 extern const unsigned char inj_bp_insn_arm[], inj_bp_insn_arm_end[]; 616 extern const unsigned char inj_bp_insn_thumb[], inj_bp_insn_thumb_end[]; 617 618 #define INJ_INSN_MAX 16 619 #else 620 __asm__ ( 621 ".pushsection .text\n" 622 ".globl inj_syscall_insn\ninj_syscall_insn:\n\t" INJ_SYSCALL_ASM "\n" 623 ".globl inj_syscall_insn_end\ninj_syscall_insn_end:\n" 624 ".globl inj_bp_insn\ninj_bp_insn:\n\t" INJ_BP_ASM "\n" 625 ".globl inj_bp_insn_end\ninj_bp_insn_end:\n" 626 ".popsection\n" 627 ); 628 extern const unsigned char inj_syscall_insn[], inj_syscall_insn_end[]; 629 extern const unsigned char inj_bp_insn[], inj_bp_insn_end[]; 630 631 #define inj_syscall_len() ((size_t)(inj_syscall_insn_end - inj_syscall_insn)) 632 #define inj_bp_len() ((size_t)(inj_bp_insn_end - inj_bp_insn)) 633 #define INJ_INSN_MAX 16 634 #endif 635 636 static int inj_getregs(pid_t pid, inj_regs *regs) 637 { 638 struct iovec iov; 639 640 iov.iov_base = regs; 641 iov.iov_len = sizeof(*regs); 642 643 return ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, &iov); 644 } 645 646 static int inj_setregs(pid_t pid, inj_regs *regs) 647 { 648 struct iovec iov; 649 650 iov.iov_base = regs; 651 iov.iov_len = sizeof(*regs); 652 653 return ptrace(PTRACE_SETREGSET, pid, (void *)NT_PRSTATUS, &iov); 654 } 655 656 int seccomp_read_syscall(pid_t pid, long *nr, long *args) 657 { 658 inj_regs regs; 659 660 if (inj_getregs(pid, ®s)) 661 return -1; 662 663 inj_get_call(®s, nr, args); 664 665 return 0; 666 } 667 668 static int inj_poke(pid_t pid, unsigned long addr, const void *src, size_t len) 669 { 670 unsigned long word; 671 size_t off, chunk; 672 673 for (off = 0; off < len; off += sizeof(long)) { 674 chunk = (len - off < sizeof(long)) ? (len - off) : sizeof(long); 675 errno = 0; 676 word = ptrace(PTRACE_PEEKTEXT, pid, (void *)(addr + off), 0); 677 if (word == (unsigned long)-1 && errno) 678 return -1; 679 memcpy(&word, (const char *)src + off, chunk); 680 if (ptrace(PTRACE_POKETEXT, pid, (void *)(addr + off), (void *)word)) 681 return -1; 682 } 683 684 return 0; 685 } 686 687 static int inj_peek(pid_t pid, unsigned long addr, void *dst, size_t len) 688 { 689 unsigned long word; 690 size_t off, chunk; 691 692 for (off = 0; off < len; off += sizeof(long)) { 693 chunk = (len - off < sizeof(long)) ? (len - off) : sizeof(long); 694 errno = 0; 695 word = ptrace(PTRACE_PEEKTEXT, pid, (void *)(addr + off), 0); 696 if (word == (unsigned long)-1 && errno) 697 return -1; 698 memcpy((char *)dst + off, &word, chunk); 699 } 700 701 return 0; 702 } 703 704 #if !defined(__arm__) 705 #ifdef INJ_NO_SINGLESTEP 706 static int inj_step(pid_t pid, unsigned long pc, int *status) 707 { 708 unsigned long bpaddr = pc + inj_syscall_len(); 709 unsigned char saved[INJ_INSN_MAX]; 710 size_t bplen = inj_bp_len(); 711 int rc = -1; 712 713 if (inj_peek(pid, bpaddr, saved, bplen)) 714 return -1; 715 if (inj_poke(pid, bpaddr, inj_bp_insn, bplen)) 716 return -1; 717 718 if (ptrace(PTRACE_CONT, pid, 0, 0)) 719 goto out; 720 if (waitpid(pid, status, 0) < 0) 721 goto out; 722 rc = 0; 723 724 out: 725 inj_poke(pid, bpaddr, saved, bplen); 726 return rc; 727 } 728 #else 729 static int inj_step(pid_t pid, unsigned long pc, int *status) 730 { 731 (void)pc; 732 733 if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) 734 return -1; 735 if (waitpid(pid, status, 0) < 0) 736 return -1; 737 738 return 0; 739 } 740 #endif 741 742 static int inj_call(pid_t pid, const inj_regs *base, unsigned long pc, 743 long nr, long a0, long a1, long a2, 744 long a3, long a4, long a5, long *ret) 745 { 746 inj_regs regs; 747 int status; 748 #if defined(__mips__) && _MIPS_SIM == _ABIO32 749 unsigned long scratch; 750 unsigned long stkargs[4]; 751 #endif 752 753 for (;;) { 754 regs = *base; 755 inj_set_pc(®s, pc); 756 inj_set_call(®s, nr, a0, a1, a2, a3, a4, a5); 757 #if defined(__mips__) && _MIPS_SIM == _ABIO32 758 scratch = (inj_sp(base) - 256) & ~0xfUL; 759 stkargs[0] = a4; 760 stkargs[1] = a5; 761 stkargs[2] = 0; 762 stkargs[3] = 0; 763 inj_set_sp(®s, scratch); 764 if (inj_poke(pid, scratch + 16, stkargs, sizeof(stkargs))) 765 return -1; 766 #endif 767 if (inj_setregs(pid, ®s)) 768 return -1; 769 770 if (inj_step(pid, pc, &status)) 771 return -1; 772 if (WIFEXITED(status) || WIFSIGNALED(status)) 773 return -1; 774 if (inj_getregs(pid, ®s)) 775 return -1; 776 if (inj_pc(®s) != pc) 777 break; 778 } 779 780 *ret = inj_ret(®s); 781 782 return 0; 783 } 784 #endif 785 786 static int read_auxv(pid_t pid, unsigned long type, unsigned long *val) 787 { 788 char path[64]; 789 unsigned long pair[2]; 790 int fd; 791 ssize_t n; 792 int ret = -1; 793 794 snprintf(path, sizeof(path), "/proc/%d/auxv", (int)pid); 795 fd = open(path, O_RDONLY | O_CLOEXEC); 796 if (fd < 0) 797 return -1; 798 799 while ((n = read(fd, pair, sizeof(pair))) == (ssize_t)sizeof(pair)) { 800 if (pair[0] == type) { 801 *val = pair[1]; 802 ret = 0; 803 break; 804 } 805 if (pair[0] == AT_NULL) 806 break; 807 } 808 809 close(fd); 810 return ret; 811 } 812 813 #if defined(__arm__) 814 815 static int arm_thumb_at(unsigned long entry) 816 { 817 return (int)(entry & 1UL); 818 } 819 820 static const unsigned char *arm_bp_insn(int thumb, size_t *len) 821 { 822 if (thumb) { 823 *len = (size_t)(inj_bp_insn_thumb_end - inj_bp_insn_thumb); 824 return inj_bp_insn_thumb; 825 } 826 *len = (size_t)(inj_bp_insn_arm_end - inj_bp_insn_arm); 827 return inj_bp_insn_arm; 828 } 829 830 static const unsigned char *arm_syscall_insn(int thumb, size_t *len) 831 { 832 if (thumb) { 833 *len = (size_t)(inj_syscall_insn_thumb_end - inj_syscall_insn_thumb); 834 return inj_syscall_insn_thumb; 835 } 836 *len = (size_t)(inj_syscall_insn_arm_end - inj_syscall_insn_arm); 837 return inj_syscall_insn_arm; 838 } 839 840 static int inj_call_arm(pid_t pid, const inj_regs *base, unsigned long pc, 841 int thumb, long nr, long a0, long a1, long a2, 842 long a3, long a4, long a5, long *ret) 843 { 844 const unsigned char *sci, *bpi; 845 size_t scilen, bpilen; 846 unsigned char saved[INJ_INSN_MAX]; 847 inj_regs regs; 848 int status; 849 850 sci = arm_syscall_insn(thumb, &scilen); 851 bpi = arm_bp_insn(thumb, &bpilen); 852 853 if (inj_peek(pid, pc, saved, scilen + bpilen)) 854 return -1; 855 if (inj_poke(pid, pc, sci, scilen)) 856 return -1; 857 if (inj_poke(pid, pc + scilen, bpi, bpilen)) 858 goto restore; 859 860 regs = *base; 861 inj_set_pc(®s, pc); 862 inj_set_call(®s, nr, a0, a1, a2, a3, a4, a5); 863 if (inj_setregs(pid, ®s)) 864 goto restore; 865 866 if (ptrace(PTRACE_CONT, pid, 0, 0)) 867 goto restore; 868 if (waitpid(pid, &status, 0) < 0) 869 goto restore; 870 if (!WIFSTOPPED(status)) 871 goto restore; 872 873 if (inj_getregs(pid, ®s)) 874 goto restore; 875 876 inj_poke(pid, pc, saved, scilen + bpilen); 877 *ret = inj_ret(®s); 878 879 return 0; 880 881 restore: 882 inj_poke(pid, pc, saved, scilen + bpilen); 883 return -1; 884 } 885 886 static int seccomp_run_to_entry_arm(pid_t pid) 887 { 888 const unsigned char *bp; 889 size_t bplen; 890 unsigned char saved[INJ_INSN_MAX]; 891 unsigned long entry, addr; 892 inj_regs regs; 893 int status, sig = 0, thumb; 894 895 if (read_auxv(pid, AT_ENTRY, &entry)) { 896 ERROR("seccomp-inject: cannot read AT_ENTRY: %m\n"); 897 return -1; 898 } 899 900 thumb = arm_thumb_at(entry); 901 addr = entry & ~1UL; 902 bp = arm_bp_insn(thumb, &bplen); 903 904 if (inj_peek(pid, addr, saved, bplen)) { 905 ERROR("seccomp-inject: read entry: %m\n"); 906 return -1; 907 } 908 if (inj_poke(pid, addr, bp, bplen)) { 909 ERROR("seccomp-inject: poke entry breakpoint: %m\n"); 910 return -1; 911 } 912 913 for (;;) { 914 if (ptrace(PTRACE_CONT, pid, 0, (void *)(long)sig)) { 915 ERROR("seccomp-inject: PTRACE_CONT to entry: %m\n"); 916 goto restore; 917 } 918 if (waitpid(pid, &status, 0) < 0) { 919 ERROR("seccomp-inject: waitpid to entry: %m\n"); 920 goto restore; 921 } 922 if (!WIFSTOPPED(status)) { 923 ERROR("seccomp-inject: workload exited before entry\n"); 924 return -1; 925 } 926 if (WSTOPSIG(status) == SIGTRAP) 927 break; 928 sig = WSTOPSIG(status); 929 } 930 931 if (inj_getregs(pid, ®s)) { 932 ERROR("seccomp-inject: GETREGSET at entry: %m\n"); 933 goto restore; 934 } 935 inj_set_pc(®s, addr); 936 if (inj_setregs(pid, ®s)) { 937 ERROR("seccomp-inject: SETREGSET at entry: %m\n"); 938 goto restore; 939 } 940 inj_poke(pid, addr, saved, bplen); 941 942 return 0; 943 944 restore: 945 inj_poke(pid, addr, saved, bplen); 946 return -1; 947 } 948 949 static int seccomp_inject_arm(pid_t pid, struct sock_fprog *prog) 950 { 951 inj_regs saved; 952 struct sock_fprog rprog; 953 unsigned long sp, pc, filter_addr, prog_addr; 954 size_t filterlen; 955 long ret; 956 int thumb; 957 958 if (inj_getregs(pid, &saved)) { 959 ERROR("seccomp-inject: GETREGSET: %m\n"); 960 return -1; 961 } 962 963 thumb = inj_thumb(&saved); 964 965 pc = inj_pc(&saved); 966 sp = inj_sp(&saved); 967 filterlen = (size_t)prog->len * sizeof(struct sock_filter); 968 969 filter_addr = (sp - 4096 - filterlen - sizeof(rprog)) & ~0xfUL; 970 prog_addr = (filter_addr + filterlen + 0xf) & ~0xfUL; 971 972 if (inj_poke(pid, filter_addr, prog->filter, filterlen)) { 973 ERROR("seccomp-inject: poke filter: %m\n"); 974 return -1; 975 } 976 977 rprog.len = prog->len; 978 rprog.filter = (struct sock_filter *)(uintptr_t)filter_addr; 979 if (inj_poke(pid, prog_addr, &rprog, sizeof(rprog))) { 980 ERROR("seccomp-inject: poke fprog: %m\n"); 981 return -1; 982 } 983 984 if (inj_call_arm(pid, &saved, pc, thumb, SYS_prctl, 985 PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0, &ret)) { 986 ERROR("seccomp-inject: drive prctl: %m\n"); 987 goto restore; 988 } 989 if (ret) { 990 ERROR("seccomp-inject: PR_SET_NO_NEW_PRIVS returned %ld\n", ret); 991 goto restore; 992 } 993 994 if (inj_call_arm(pid, &saved, pc, thumb, SYS_seccomp, 995 SECCOMP_SET_MODE_FILTER, 0, (long)prog_addr, 0, 0, 0, &ret)) { 996 ERROR("seccomp-inject: drive seccomp: %m\n"); 997 goto restore; 998 } 999 if (ret) { 1000 ERROR("seccomp-inject: seccomp(SET_MODE_FILTER) returned %ld\n", ret); 1001 goto restore; 1002 } 1003 1004 if (inj_setregs(pid, &saved)) { 1005 ERROR("seccomp-inject: restore SETREGSET: %m\n"); 1006 return -1; 1007 } 1008 1009 return 0; 1010 1011 restore: 1012 inj_setregs(pid, &saved); 1013 return -1; 1014 } 1015 #endif 1016 1017 #if !defined(__arm__) 1018 static int run_to_addr(pid_t pid, unsigned long addr) 1019 { 1020 const unsigned char *bp = inj_bp_insn; 1021 size_t bplen = inj_bp_len(); 1022 unsigned char saved[INJ_INSN_MAX]; 1023 inj_regs regs; 1024 int status, sig = 0; 1025 1026 if (inj_peek(pid, addr, saved, bplen)) { 1027 ERROR("seccomp-inject: read bp target: %m\n"); 1028 return -1; 1029 } 1030 if (inj_poke(pid, addr, bp, bplen)) { 1031 ERROR("seccomp-inject: poke breakpoint: %m\n"); 1032 return -1; 1033 } 1034 1035 for (;;) { 1036 if (ptrace(PTRACE_CONT, pid, 0, (void *)(long)sig)) { 1037 ERROR("seccomp-inject: PTRACE_CONT to bp: %m\n"); 1038 goto restore; 1039 } 1040 if (waitpid(pid, &status, 0) < 0) { 1041 ERROR("seccomp-inject: waitpid to bp: %m\n"); 1042 goto restore; 1043 } 1044 if (!WIFSTOPPED(status)) { 1045 ERROR("seccomp-inject: workload exited before reaching target\n"); 1046 return -1; 1047 } 1048 if (WSTOPSIG(status) == SIGTRAP) 1049 break; 1050 sig = WSTOPSIG(status); 1051 } 1052 1053 if (inj_getregs(pid, ®s)) { 1054 ERROR("seccomp-inject: GETREGSET at bp: %m\n"); 1055 goto restore; 1056 } 1057 inj_set_pc(®s, addr); 1058 if (inj_setregs(pid, ®s)) { 1059 ERROR("seccomp-inject: SETREGSET at bp: %m\n"); 1060 goto restore; 1061 } 1062 inj_poke(pid, addr, saved, bplen); 1063 1064 return 0; 1065 1066 restore: 1067 inj_poke(pid, addr, saved, bplen); 1068 return -1; 1069 } 1070 #endif 1071 1072 int seccomp_run_to_entry(pid_t pid) 1073 { 1074 #if defined(__arm__) 1075 return seccomp_run_to_entry_arm(pid); 1076 #else 1077 unsigned long entry; 1078 1079 if (read_auxv(pid, AT_ENTRY, &entry)) { 1080 ERROR("seccomp-inject: cannot read AT_ENTRY: %m\n"); 1081 return -1; 1082 } 1083 1084 return run_to_addr(pid, entry); 1085 #endif 1086 } 1087 1088 #if !defined(__arm__) && !defined(__i386__) 1089 static unsigned long find_libc_init(pid_t pid, int *main_argidx) 1090 { 1091 char path[64], line[600], rooted[PATH_MAX + 64], p[PATH_MAX]; 1092 char seen[48][256]; 1093 unsigned long bases[48]; 1094 unsigned long lo, hi, val; 1095 int nseen = 0, i; 1096 FILE *f; 1097 1098 *main_argidx = 0; 1099 snprintf(path, sizeof(path), "/proc/%d/maps", (int)pid); 1100 f = fopen(path, "r"); 1101 if (!f) 1102 return 0; 1103 1104 while (fgets(line, sizeof(line), f)) { 1105 if (sscanf(line, "%lx-%lx %*s %*s %*s %*s %4095s", &lo, &hi, p) < 3) 1106 continue; 1107 if (p[0] != '/') 1108 continue; 1109 for (i = 0; i < nseen; i++) 1110 if (!strcmp(seen[i], p)) 1111 break; 1112 if (i < nseen || nseen >= 48) 1113 continue; 1114 strncpy(seen[nseen], p, sizeof(seen[0]) - 1); 1115 seen[nseen][sizeof(seen[0]) - 1] = '\0'; 1116 bases[nseen] = lo; 1117 nseen++; 1118 } 1119 fclose(f); 1120 1121 for (i = 0; i < nseen; i++) { 1122 snprintf(rooted, sizeof(rooted), "/proc/%d/root%s", (int)pid, seen[i]); 1123 val = elf_dynsym_value(rooted, "__libc_start_main"); 1124 if (val) { 1125 *main_argidx = 0; 1126 return bases[i] + val; 1127 } 1128 } 1129 for (i = 0; i < nseen; i++) { 1130 snprintf(rooted, sizeof(rooted), "/proc/%d/root%s", (int)pid, seen[i]); 1131 val = elf_dynsym_value(rooted, "__libc_init"); 1132 if (val) { 1133 *main_argidx = 2; 1134 return bases[i] + val; 1135 } 1136 } 1137 return 0; 1138 } 1139 #endif 1140 1141 int seccomp_marker_addrs(pid_t pid, unsigned long *at_entry, unsigned long *lsm, int *main_argidx) 1142 { 1143 *at_entry = 0; 1144 *lsm = 0; 1145 *main_argidx = 0; 1146 1147 if (read_auxv(pid, AT_ENTRY, at_entry)) 1148 return -1; 1149 1150 #if !defined(__arm__) && !defined(__i386__) 1151 *lsm = find_libc_init(pid, main_argidx); 1152 #endif 1153 1154 return 0; 1155 } 1156 1157 int seccomp_run_to_main(pid_t pid) 1158 { 1159 #if defined(__arm__) 1160 return seccomp_run_to_entry(pid); 1161 #else 1162 unsigned long at_entry, lsm, mainaddr; 1163 long nr, args[6]; 1164 int main_argidx; 1165 1166 if (seccomp_marker_addrs(pid, &at_entry, &lsm, &main_argidx)) 1167 return -1; 1168 if (!lsm) 1169 return seccomp_run_to_entry(pid); 1170 1171 if (run_to_addr(pid, lsm)) 1172 return -1; 1173 if (seccomp_read_syscall(pid, &nr, args)) 1174 return -1; 1175 1176 mainaddr = (unsigned long)args[main_argidx]; 1177 if (!mainaddr) 1178 return -1; 1179 1180 return run_to_addr(pid, mainaddr); 1181 #endif 1182 } 1183 1184 int seccomp_run_to_main_from_entry(pid_t pid) 1185 { 1186 #if defined(__arm__) 1187 return 1; 1188 #else 1189 unsigned long at_entry, lsm, mainaddr; 1190 long nr, args[6]; 1191 int main_argidx; 1192 1193 if (seccomp_marker_addrs(pid, &at_entry, &lsm, &main_argidx)) 1194 return -1; 1195 if (!lsm) 1196 return 1; 1197 1198 if (run_to_addr(pid, lsm)) 1199 return -1; 1200 if (seccomp_read_syscall(pid, &nr, args)) 1201 return -1; 1202 1203 mainaddr = (unsigned long)args[main_argidx]; 1204 if (!mainaddr) 1205 return -1; 1206 1207 if (run_to_addr(pid, mainaddr)) 1208 return -1; 1209 1210 return 0; 1211 #endif 1212 } 1213 1214 int seccomp_bp_arm(pid_t pid, unsigned long addr, struct seccomp_bp *bp) 1215 { 1216 #if defined(__arm__) 1217 const unsigned char *ins; 1218 size_t len; 1219 int thumb; 1220 1221 thumb = arm_thumb_at(addr); 1222 bp->addr = addr & ~1UL; 1223 ins = arm_bp_insn(thumb, &len); 1224 #else 1225 const unsigned char *ins = inj_bp_insn; 1226 size_t len = inj_bp_len(); 1227 1228 bp->addr = addr; 1229 #endif 1230 1231 if (len > sizeof(bp->saved)) 1232 return -1; 1233 if (inj_peek(pid, bp->addr, bp->saved, len)) 1234 return -1; 1235 if (inj_poke(pid, bp->addr, ins, len)) 1236 return -1; 1237 1238 bp->len = (unsigned char)len; 1239 bp->armed = 1; 1240 1241 return 0; 1242 } 1243 1244 int seccomp_bp_match(pid_t pid, struct seccomp_bp **bps, int n) 1245 { 1246 inj_regs regs; 1247 unsigned long pc; 1248 int i; 1249 1250 if (inj_getregs(pid, ®s)) 1251 return -1; 1252 1253 pc = inj_pc(®s); 1254 #if defined(__arm__) 1255 pc &= ~1UL; 1256 #endif 1257 1258 for (i = 0; i < n; i++) { 1259 if (!bps[i] || !bps[i]->armed) 1260 continue; 1261 if (pc != bps[i]->addr && pc != bps[i]->addr + bps[i]->len) 1262 continue; 1263 1264 inj_poke(pid, bps[i]->addr, bps[i]->saved, bps[i]->len); 1265 inj_set_pc(®s, bps[i]->addr); 1266 if (inj_setregs(pid, ®s)) 1267 return -1; 1268 bps[i]->armed = 0; 1269 1270 return i; 1271 } 1272 1273 return -1; 1274 } 1275 1276 int seccomp_force_errno(pid_t pid, int err) 1277 { 1278 #if defined(__aarch64__) 1279 inj_regs regs; 1280 int scno = -1; 1281 struct iovec iov; 1282 1283 iov.iov_base = &scno; 1284 iov.iov_len = sizeof(scno); 1285 if (ptrace(PTRACE_SETREGSET, pid, (void *)NT_ARM_SYSTEM_CALL, &iov)) 1286 return -1; 1287 if (inj_getregs(pid, ®s)) 1288 return -1; 1289 regs.regs[0] = (unsigned long long)(long long)-err; 1290 if (inj_setregs(pid, ®s)) 1291 return -1; 1292 1293 return 0; 1294 #elif defined(__arm__) 1295 inj_regs regs; 1296 1297 if (ptrace(PTRACE_SET_SYSCALL, pid, 0, (void *)-1L)) 1298 return -1; 1299 if (inj_getregs(pid, ®s)) 1300 return -1; 1301 regs.uregs[0] = (unsigned long)(long)-err; 1302 if (inj_setregs(pid, ®s)) 1303 return -1; 1304 1305 return 0; 1306 #elif defined(__mips__) 1307 inj_regs regs; 1308 1309 if (inj_getregs(pid, ®s)) 1310 return -1; 1311 regs.gregs[MIPS_EF_V0] = (unsigned long)(long)-1; 1312 if (inj_setregs(pid, ®s)) 1313 return -1; 1314 1315 return 1; 1316 #elif defined(__x86_64__) || defined(__i386__) || \ 1317 (defined(__riscv) && __riscv_xlen == 64) || \ 1318 (defined(__loongarch__) && __loongarch_grlen == 64) || \ 1319 defined(__powerpc64__) || defined(__powerpc__) 1320 inj_regs regs; 1321 1322 if (inj_getregs(pid, ®s)) 1323 return -1; 1324 1325 #if defined(__x86_64__) 1326 regs.orig_rax = (unsigned long)-1; 1327 regs.rax = (unsigned long)(long)-err; 1328 #elif defined(__i386__) 1329 regs.orig_eax = (unsigned long)-1; 1330 regs.eax = (unsigned long)(long)-err; 1331 #elif defined(__riscv) && __riscv_xlen == 64 1332 regs.a7 = (unsigned long)-1; 1333 regs.a0 = (unsigned long)(long)-err; 1334 #elif defined(__loongarch__) && __loongarch_grlen == 64 1335 regs.regs[11] = (unsigned long)-1; 1336 regs.regs[4] = (unsigned long)(long)-err; 1337 #else 1338 regs.gpr[0] = (unsigned long)-1; 1339 regs.gpr[3] = (unsigned long)err; 1340 regs.ccr |= 0x10000000UL; 1341 #endif 1342 1343 if (inj_setregs(pid, ®s)) 1344 return -1; 1345 1346 return 0; 1347 #else 1348 (void)pid; 1349 (void)err; 1350 return -1; 1351 #endif 1352 } 1353 1354 int seccomp_force_errno_exit(pid_t pid, int err) 1355 { 1356 #if defined(__mips__) 1357 inj_regs regs; 1358 1359 if (inj_getregs(pid, ®s)) 1360 return -1; 1361 1362 regs.gregs[MIPS_EF_V0] = (unsigned long)(long)err; 1363 regs.gregs[MIPS_EF_A3] = 1; 1364 1365 if (inj_setregs(pid, ®s)) 1366 return -1; 1367 1368 return 0; 1369 #else 1370 (void)pid; 1371 (void)err; 1372 return -1; 1373 #endif 1374 } 1375 1376 int seccomp_inject(pid_t pid, struct sock_fprog *prog) 1377 { 1378 #if defined(__arm__) 1379 return seccomp_inject_arm(pid, prog); 1380 #else 1381 inj_regs saved; 1382 struct sock_fprog rprog; 1383 unsigned char savedinsn[INJ_INSN_MAX]; 1384 unsigned long sp, pc, filter_addr, prog_addr; 1385 size_t filterlen; 1386 long ret; 1387 1388 if (inj_getregs(pid, &saved)) { 1389 ERROR("seccomp-inject: GETREGSET: %m\n"); 1390 return -1; 1391 } 1392 1393 pc = inj_pc(&saved); 1394 sp = inj_sp(&saved); 1395 filterlen = (size_t)prog->len * sizeof(struct sock_filter); 1396 1397 filter_addr = (sp - 4096 - filterlen - sizeof(rprog)) & ~0xfUL; 1398 prog_addr = (filter_addr + filterlen + 0xf) & ~0xfUL; 1399 1400 if (inj_peek(pid, pc, savedinsn, inj_syscall_len())) { 1401 ERROR("seccomp-inject: read pc: %m\n"); 1402 return -1; 1403 } 1404 if (inj_poke(pid, pc, inj_syscall_insn, inj_syscall_len())) { 1405 ERROR("seccomp-inject: poke trap: %m\n"); 1406 return -1; 1407 } 1408 if (inj_poke(pid, filter_addr, prog->filter, filterlen)) { 1409 ERROR("seccomp-inject: poke filter: %m\n"); 1410 goto restore; 1411 } 1412 1413 rprog.len = prog->len; 1414 rprog.filter = (struct sock_filter *)(uintptr_t)filter_addr; 1415 if (inj_poke(pid, prog_addr, &rprog, sizeof(rprog))) { 1416 ERROR("seccomp-inject: poke fprog: %m\n"); 1417 goto restore; 1418 } 1419 1420 if (inj_call(pid, &saved, pc, SYS_prctl, 1421 PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0, &ret)) { 1422 ERROR("seccomp-inject: drive prctl: %m\n"); 1423 goto restore; 1424 } 1425 if (ret) { 1426 ERROR("seccomp-inject: PR_SET_NO_NEW_PRIVS returned %ld\n", ret); 1427 goto restore; 1428 } 1429 1430 if (inj_call(pid, &saved, pc, SYS_seccomp, 1431 SECCOMP_SET_MODE_FILTER, 0, (long)prog_addr, 0, 0, 0, &ret)) { 1432 ERROR("seccomp-inject: drive seccomp: %m\n"); 1433 goto restore; 1434 } 1435 if (ret) { 1436 ERROR("seccomp-inject: seccomp(SET_MODE_FILTER) returned %ld\n", ret); 1437 goto restore; 1438 } 1439 1440 inj_poke(pid, pc, savedinsn, inj_syscall_len()); 1441 inj_clear_restart(&saved); 1442 if (inj_setregs(pid, &saved)) { 1443 ERROR("seccomp-inject: restore SETREGSET: %m\n"); 1444 return -1; 1445 } 1446 1447 return 0; 1448 1449 restore: 1450 inj_poke(pid, pc, savedinsn, inj_syscall_len()); 1451 inj_clear_restart(&saved); 1452 inj_setregs(pid, &saved); 1453 1454 return -1; 1455 #endif 1456 } 1457
This page was automatically generated by LXR 0.3.1. • OpenWrt