Package: strace
Version: 4.15-2
Severity: normal

Dear Maintainer,

On armhf, when the known system call triggers a SECCOMP rule that raises SIGSYS
strace starts interpreting system calls entries as exits, and exits as entries.
After another SIGSYS correct behavour is restored.

For example:

$ strace -o /dev/fd/1 ./a.out 3 2>/dev/null       
...
read(72,  <unfinished ...>
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f57e5d0, 
si_syscall=__NR_read, si_arch=AUDIT_ARCH_ARM} ---
<... read resumed> "3\0KDE_MULTIHEAD=false\0GS_LIB=/h", 0) = 31
read(72, "3\0", 0)                      = 2
write(1, "H", 1)                        = 101
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f57e5d0, 
si_syscall=__NR_read, si_arch=AUDIT_ARCH_ARM} ---
sigreturn({mask=[]})                    = 101
write(2, "e", 1)                        = 1
read(108,  <unfinished ...>
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f57e5d0, 
si_syscall=__NR_read, si_arch=AUDIT_ARCH_ARM} ---
<... read resumed> "ello World\n\0\0\0\0d\376\377\177\1\0\0\0\0\0\0\0\0\0\0\0", 
1) = 31
read(108, "el", 1)                      = 2
write(1, "l", 1)                        = 108
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f57e5d0, 
si_syscall=__NR_read, si_arch=AUDIT_ARCH_ARM} ---
sigreturn({mask=[]})                    = 108


With an invalid system call number it works properly:

$ strace -o /dev/fd/1 ./a.out 1000 2>/dev/null
...
syscall_1000(0x48, 0xbede5373, 0, 0, 0x7f61778c, 0x3e8 <unfinished ...>
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f6175d0, 
si_syscall=1000, si_arch=AUDIT_ARCH_ARM} ---
<... syscall_1000 resumed> )            = 0x1f
write(2, "H", 1)                        = 1
syscall_1000(0x65, 0x7f61778c, 0x1, 0, 0x7f61778d, 0x3e8 <unfinished ...>
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f6175d0, 
si_syscall=1000, si_arch=AUDIT_ARCH_ARM} ---
<... syscall_1000 resumed> )            = 0x1f
write(2, "e", 1)                        = 1
syscall_1000(0x6c, 0x7f61778d, 0x1, 0, 0x7f61778e, 0x3e8 <unfinished ...>
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f6175d0, 
si_syscall=1000, si_arch=AUDIT_ARCH_ARM} ---
<... syscall_1000 resumed> )            = 0x1f
write(2, "l", 1)                        = 1
syscall_1000(0x6c, 0x7f61778e, 0x1, 0, 0x7f61778f, 0x3e8 <unfinished ...>
--- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f6175d0, 
si_syscall=1000, si_arch=AUDIT_ARCH_ARM} ---

Attached test case requires -marm or -O2 gcc options to compile.

-- System Information:
Debian Release: 9.0
  APT prefers testing
  APT policy: (990, 'testing'), (500, 'unstable')
Architecture: armhf (armv7l)

Kernel: Linux 4.9.9-teb2+ (SMP w/4 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages strace depends on:
ii  libc6  2.24-9

strace recommends no packages.

strace suggests no packages.

-- no debconf information
#define _GNU_SOURCE
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <signal.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <unistd.h>

void ignore(int s) {
}

extern char syscall_instruction[];

int main(int argc, char **argv) {
    
    struct sock_filter filter[] = {

    // Load PC
    BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, 
instruction_pointer)),

    // Trap test instruction
    BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uintptr_t)syscall_instruction, 0, 1),

    // Raise signal.
    BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP),

    // Continue as Linux system call.
    BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    };

    struct sock_fprog fprog = {
    .len = sizeof(filter) / sizeof(filter[0]),
    .filter = filter
    };

  prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
  prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (uintptr_t)&fprog, 0, 0);
  
  signal(SIGSYS, ignore);
  
  int syscall = 4;
  if (argc > 1) syscall = atoi(argv[1]);
  
  const char *c = "Hello World\n";

  while (*c) {
#ifdef __arm__
    register int r0 asm("r0") = *c;
    register int r7 asm("r7") = syscall;
    asm volatile ("svc 0\n\tsyscall_instruction:" : "+r"(r0), "+r"(r7) :: 
"memory");
#else
    int s = syscall;
    asm volatile ("int $0x80\n\tsyscall_instruction:" : "+a"(s):  "b"(*c) : 
"memory");
#endif
    write(2, c, 1);
    ++c;
  }
}

Reply via email to