Giter Club home page Giter Club logo

seccomp-tools's Introduction

Build Status Code Climate Issue Count Test Coverage Inline docs Yard Docs MIT License

Seccomp Tools

Provide powerful tools for seccomp analysis.

This project targets to (but is not limited to) analyze seccomp sandbox in CTF pwn challenges. Some features might be CTF-specific, but also useful for analyzing seccomp of real cases.

Features

  • Dump - Automatically dumps seccomp BPF from execution file(s).
  • Disasm - Converts seccomp BPF to a human readable format.
    • With simple decompilation.
    • With syscall names and arguments whenever possible.
    • Colorful!
  • Asm - Makes writing seccomp rules similar to writing codes.
  • Emu - Emulates seccomp rules.
  • Supports multi-architecture.

Installation

Available on RubyGems.org!

$ gem install seccomp-tools

If you failed when compiling, try:

sudo apt install gcc ruby-dev

and install seccomp-tools again.

Command Line Interface

seccomp-tools

$ seccomp-tools --help
# Usage: seccomp-tools [--version] [--help] <command> [<options>]
#
# List of commands:
#
# 	asm	Seccomp bpf assembler.
# 	disasm	Disassemble seccomp bpf.
# 	dump	Automatically dump seccomp bpf from execution file(s).
# 	emu	Emulate seccomp rules.
#
# See 'seccomp-tools <command> --help' to read about a specific subcommand.

$ seccomp-tools dump --help
# dump - Automatically dump seccomp bpf from execution file(s).
# NOTE : This function is only available on Linux.
#
# Usage: seccomp-tools dump [exec] [options]
#     -c, --sh-exec <command>          Executes the given command (via sh).
#                                      Use this option if want to pass arguments or do pipe things to the execution file.
#                                      e.g. use `-c "./bin > /dev/null"` to dump seccomp without being mixed with stdout.
#     -f, --format FORMAT              Output format. FORMAT can only be one of <disasm|raw|inspect>.
#                                      Default: disasm
#     -l, --limit LIMIT                Limit the number of calling "prctl(PR_SET_SECCOMP)".
#                                      The target process will be killed whenever its calling times reaches LIMIT.
#                                      Default: 1
#     -o, --output FILE                Output result into FILE instead of stdout.
#                                      If multiple seccomp syscalls have been invoked (see --limit),
#                                      results will be written to FILE, FILE_1, FILE_2.. etc.
#                                      For example, "--output out.bpf" and the output files are out.bpf, out_1.bpf, ...
#     -p, --pid PID                    Dump installed seccomp filters of the existing process.
#                                      You must have CAP_SYS_ADMIN (e.g. be root) in order to use this option.

dump

Dumps the seccomp BPF from an execution file. This work is done by utilizing the ptrace syscall.

NOTICE: beware of the execution file will be executed.

$ file spec/binary/twctf-2016-diary
# spec/binary/twctf-2016-diary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=3648e29153ac0259a0b7c3e25537a5334f50107f, not stripped

$ seccomp-tools dump spec/binary/twctf-2016-diary
#  line  CODE  JT   JF      K
# =================================
#  0000: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0001: 0x15 0x00 0x01 0x00000002  if (A != open) goto 0003
#  0002: 0x06 0x00 0x00 0x00000000  return KILL
#  0003: 0x15 0x00 0x01 0x00000101  if (A != openat) goto 0005
#  0004: 0x06 0x00 0x00 0x00000000  return KILL
#  0005: 0x15 0x00 0x01 0x0000003b  if (A != execve) goto 0007
#  0006: 0x06 0x00 0x00 0x00000000  return KILL
#  0007: 0x15 0x00 0x01 0x00000038  if (A != clone) goto 0009
#  0008: 0x06 0x00 0x00 0x00000000  return KILL
#  0009: 0x15 0x00 0x01 0x00000039  if (A != fork) goto 0011
#  0010: 0x06 0x00 0x00 0x00000000  return KILL
#  0011: 0x15 0x00 0x01 0x0000003a  if (A != vfork) goto 0013
#  0012: 0x06 0x00 0x00 0x00000000  return KILL
#  0013: 0x15 0x00 0x01 0x00000055  if (A != creat) goto 0015
#  0014: 0x06 0x00 0x00 0x00000000  return KILL
#  0015: 0x15 0x00 0x01 0x00000142  if (A != execveat) goto 0017
#  0016: 0x06 0x00 0x00 0x00000000  return KILL
#  0017: 0x06 0x00 0x00 0x7fff0000  return ALLOW

$ seccomp-tools dump spec/binary/twctf-2016-diary -f inspect
# "\x20\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x02\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x01\x01\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x3B\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x38\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x39\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x3A\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x55\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x01\x42\x01\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\xFF\x7F"

$ seccomp-tools dump spec/binary/twctf-2016-diary -f raw | xxd
# 00000000: 2000 0000 0000 0000 1500 0001 0200 0000   ...............
# 00000010: 0600 0000 0000 0000 1500 0001 0101 0000  ................
# 00000020: 0600 0000 0000 0000 1500 0001 3b00 0000  ............;...
# 00000030: 0600 0000 0000 0000 1500 0001 3800 0000  ............8...
# 00000040: 0600 0000 0000 0000 1500 0001 3900 0000  ............9...
# 00000050: 0600 0000 0000 0000 1500 0001 3a00 0000  ............:...
# 00000060: 0600 0000 0000 0000 1500 0001 5500 0000  ............U...
# 00000070: 0600 0000 0000 0000 1500 0001 4201 0000  ............B...
# 00000080: 0600 0000 0000 0000 0600 0000 0000 ff7f  ................

disasm

Disassembles the seccomp from raw BPF.

$ xxd spec/data/twctf-2016-diary.bpf | head -n 3
# 00000000: 2000 0000 0000 0000 1500 0001 0200 0000   ...............
# 00000010: 0600 0000 0000 0000 1500 0001 0101 0000  ................
# 00000020: 0600 0000 0000 0000 1500 0001 3b00 0000  ............;...

$ seccomp-tools disasm spec/data/twctf-2016-diary.bpf
#  line  CODE  JT   JF      K
# =================================
#  0000: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0001: 0x15 0x00 0x01 0x00000002  if (A != open) goto 0003
#  0002: 0x06 0x00 0x00 0x00000000  return KILL
#  0003: 0x15 0x00 0x01 0x00000101  if (A != openat) goto 0005
#  0004: 0x06 0x00 0x00 0x00000000  return KILL
#  0005: 0x15 0x00 0x01 0x0000003b  if (A != execve) goto 0007
#  0006: 0x06 0x00 0x00 0x00000000  return KILL
#  0007: 0x15 0x00 0x01 0x00000038  if (A != clone) goto 0009
#  0008: 0x06 0x00 0x00 0x00000000  return KILL
#  0009: 0x15 0x00 0x01 0x00000039  if (A != fork) goto 0011
#  0010: 0x06 0x00 0x00 0x00000000  return KILL
#  0011: 0x15 0x00 0x01 0x0000003a  if (A != vfork) goto 0013
#  0012: 0x06 0x00 0x00 0x00000000  return KILL
#  0013: 0x15 0x00 0x01 0x00000055  if (A != creat) goto 0015
#  0014: 0x06 0x00 0x00 0x00000000  return KILL
#  0015: 0x15 0x00 0x01 0x00000142  if (A != execveat) goto 0017
#  0016: 0x06 0x00 0x00 0x00000000  return KILL
#  0017: 0x06 0x00 0x00 0x7fff0000  return ALLOW

asm

Assembles the seccomp rules into raw bytes. It's very useful when one wants to write custom seccomp rules.

Supports labels for jumping and uses syscall names directly. See examples below.

$ seccomp-tools asm
# asm - Seccomp bpf assembler.
#
# Usage: seccomp-tools asm IN_FILE [options]
#     -o, --output FILE                Output result into FILE instead of stdout.
#     -f, --format FORMAT              Output format. FORMAT can only be one of <inspect|raw|c_array|c_source|assembly>.
#                                      Default: inspect
#     -a, --arch ARCH                  Specify architecture.
#                                      Supported architectures are <aarch64|amd64|i386|s390x>.
#                                      Default: amd64

# Input file for asm
$ cat spec/data/libseccomp.asm
# # check if arch is X86_64
# A = arch
# A == ARCH_X86_64 ? next : dead
# A = sys_number
# A >= 0x40000000 ? dead : next
# A == write ? ok : next
# A == close ? ok : next
# A == dup ? ok : next
# A == exit ? ok : next
# return ERRNO(5)
# ok:
# return ALLOW
# dead:
# return KILL

$ seccomp-tools asm spec/data/libseccomp.asm
# " \x00\x00\x00\x04\x00\x00\x00\x15\x00\x00\b>\x00\x00\xC0 \x00\x00\x00\x00\x00\x00\x005\x00\x06\x00\x00\x00\x00@\x15\x00\x04\x00\x01\x00\x00\x00\x15\x00\x03\x00\x03\x00\x00\x00\x15\x00\x02\x00 \x00\x00\x00\x15\x00\x01\x00<\x00\x00\x00\x06\x00\x00\x00\x05\x00\x05\x00\x06\x00\x00\x00\x00\x00\xFF\x7F\x06\x00\x00\x00\x00\x00\x00\x00"

$ seccomp-tools asm spec/data/libseccomp.asm -f c_source
# #include <linux/seccomp.h>
# #include <stdio.h>
# #include <stdlib.h>
# #include <sys/prctl.h>
#
# static void install_seccomp() {
#   static unsigned char filter[] = {32,0,0,0,4,0,0,0,21,0,0,8,62,0,0,192,32,0,0,0,0,0,0,0,53,0,6,0,0,0,0,64,21,0,4,0,1,0,0,0,21,0,3,0,3,0,0,0,21,0,2,0,32,0,0,0,21,0,1,0,60,0,0,0,6,0,0,0,5,0,5,0,6,0,0,0,0,0,255,127,6,0,0,0,0,0,0,0};
#   struct prog {
#     unsigned short len;
#     unsigned char *filter;
#   } rule = {
#     .len = sizeof(filter) >> 3,
#     .filter = filter
#   };
#   if(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { perror("prctl(PR_SET_NO_NEW_PRIVS)"); exit(2); }
#   if(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &rule) < 0) { perror("prctl(PR_SET_SECCOMP)"); exit(2); }
# }

$ seccomp-tools asm spec/data/libseccomp.asm -f assembly
# install_seccomp:
#   push   rbp
#   mov    rbp, rsp
#   push   38
#   pop    rdi
#   push   0x1
#   pop    rsi
#   xor    eax, eax
#   mov    al, 0x9d
#   syscall
#   push   22
#   pop    rdi
#   lea    rdx, [rip + _filter]
#   push   rdx /* .filter */
#   push   _filter_end - _filter >> 3 /* .len */
#   mov    rdx, rsp
#   push   0x2
#   pop    rsi
#   xor    eax, eax
#   mov    al, 0x9d
#   syscall
#   leave
#   ret
# _filter:
# .ascii "\040\000\000\000\004\000\000\000\025\000\000\010\076\000\000\300\040\000\000\000\000\000\000\000\065\000\006\000\000\000\000\100\025\000\004\000\001\000\000\000\025\000\003\000\003\000\000\000\025\000\002\000\040\000\000\000\025\000\001\000\074\000\000\000\006\000\000\000\005\000\005\000\006\000\000\000\000\000\377\177\006\000\000\000\000\000\000\000"
# _filter_end:


# let's asm then disasm!
$ seccomp-tools asm spec/data/libseccomp.asm -f raw | seccomp-tools disasm -
#  line  CODE  JT   JF      K
# =================================
#  0000: 0x20 0x00 0x00 0x00000004  A = arch
#  0001: 0x15 0x00 0x08 0xc000003e  if (A != ARCH_X86_64) goto 0010
#  0002: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0003: 0x35 0x06 0x00 0x40000000  if (A >= 0x40000000) goto 0010
#  0004: 0x15 0x04 0x00 0x00000001  if (A == write) goto 0009
#  0005: 0x15 0x03 0x00 0x00000003  if (A == close) goto 0009
#  0006: 0x15 0x02 0x00 0x00000020  if (A == dup) goto 0009
#  0007: 0x15 0x01 0x00 0x0000003c  if (A == exit) goto 0009
#  0008: 0x06 0x00 0x00 0x00050005  return ERRNO(5)
#  0009: 0x06 0x00 0x00 0x7fff0000  return ALLOW
#  0010: 0x06 0x00 0x00 0x00000000  return KILL

Since v1.6.0 [not released yet], asm has switched to using a yacc-based syntax parser, hence supports more flexible and intuitive syntax!

$ cat spec/data/example.asm
# # An example of supported assembly syntax
# if (A == X)
#   goto next # 'next' is a reserved label, means the next statement ("A = args[0]" in this example)
# else
#   goto err_label # custom defined label
# A = args[0]
# if (
#   A # put a comment here is also valid
#     == 0x123
#   ) goto disallow
# if (! (A & 0x1337)) # support bang in if-conditions
#   goto 0 # equivalent to 'goto next'
# else goto 2 # goto $ + 2, 'mem[0] = A' in this example
# A = sys_number
# A = instruction_pointer >> 32
# mem[0] = A
# A = data[4] # equivalent to 'A = arch'
# err_label: return ERRNO(1337)
# disallow:
# return KILL

$ seccomp-tools asm spec/data/example.asm -f raw | seccomp-tools disasm -
#  line  CODE  JT   JF      K
# =================================
#  0000: 0x1d 0x00 0x07 0x00000000  if (A != X) goto 0008
#  0001: 0x20 0x00 0x00 0x00000010  A = args[0]
#  0002: 0x15 0x06 0x00 0x00000123  if (A == 0x123) goto 0009
#  0003: 0x45 0x02 0x00 0x00001337  if (A & 0x1337) goto 0006
#  0004: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0005: 0x20 0x00 0x00 0x0000000c  A = instruction_pointer >> 32
#  0006: 0x02 0x00 0x00 0x00000000  mem[0] = A
#  0007: 0x20 0x00 0x00 0x00000004  A = arch
#  0008: 0x06 0x00 0x00 0x00050539  return ERRNO(1337)
#  0009: 0x06 0x00 0x00 0x00000000  return KILL

The output of seccomp-tools disasm <file> --asm-able is a valid input of asm:

$ seccomp-tools disasm spec/data/x32.bpf --asm-able
# 0000: A = arch
# 0001: if (A != ARCH_X86_64) goto 0011
# 0002: A = sys_number
# 0003: if (A < 0x40000000) goto 0011
# 0004: if (A == x32_read) goto 0011
# 0005: if (A == x32_write) goto 0011
# 0006: if (A == x32_iopl) goto 0011
# 0007: if (A != x32_mmap) goto 0011
# 0008: A = args[0]
# 0009: if (A == 0x0) goto 0011
# 0010: return ERRNO(5)
# 0011: return ALLOW


# disasm then asm then disasm!
$ seccomp-tools disasm spec/data/x32.bpf --asm-able | seccomp-tools asm - -f raw | seccomp-tools disasm -
#  line  CODE  JT   JF      K
# =================================
#  0000: 0x20 0x00 0x00 0x00000004  A = arch
#  0001: 0x15 0x00 0x09 0xc000003e  if (A != ARCH_X86_64) goto 0011
#  0002: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0003: 0x35 0x00 0x07 0x40000000  if (A < 0x40000000) goto 0011
#  0004: 0x15 0x06 0x00 0x40000000  if (A == x32_read) goto 0011
#  0005: 0x15 0x05 0x00 0x40000001  if (A == x32_write) goto 0011
#  0006: 0x15 0x04 0x00 0x400000ac  if (A == x32_iopl) goto 0011
#  0007: 0x15 0x00 0x03 0x40000009  if (A != x32_mmap) goto 0011
#  0008: 0x20 0x00 0x00 0x00000010  A = addr # x32_mmap(addr, len, prot, flags, fd, pgoff)
#  0009: 0x15 0x01 0x00 0x00000000  if (A == 0x0) goto 0011
#  0010: 0x06 0x00 0x00 0x00050005  return ERRNO(5)
#  0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW

Emu

Emulates seccomp given sys_nr, arg0, arg1, etc.

$ seccomp-tools emu --help
# emu - Emulate seccomp rules.
#
# Usage: seccomp-tools emu [options] BPF_FILE [sys_nr [arg0 [arg1 ... arg5]]]
#     -a, --arch ARCH                  Specify architecture.
#                                      Supported architectures are <aarch64|amd64|i386|s390x>.
#                                      Default: amd64
#     -q, --[no-]quiet                 Run quietly, only show emulation result.

$ seccomp-tools emu spec/data/libseccomp.bpf write 0x3
#  line  CODE  JT   JF      K
# =================================
#  0000: 0x20 0x00 0x00 0x00000004  A = arch
#  0001: 0x15 0x00 0x08 0xc000003e  if (A != ARCH_X86_64) goto 0010
#  0002: 0x20 0x00 0x00 0x00000000  A = sys_number
#  0003: 0x35 0x06 0x00 0x40000000  if (A >= 0x40000000) goto 0010
#  0004: 0x15 0x04 0x00 0x00000001  if (A == write) goto 0009
#  0005: 0x15 0x03 0x00 0x00000003  if (A == close) goto 0009
#  0006: 0x15 0x02 0x00 0x00000020  if (A == dup) goto 0009
#  0007: 0x15 0x01 0x00 0x0000003c  if (A == exit) goto 0009
#  0008: 0x06 0x00 0x00 0x00050005  return ERRNO(5)
#  0009: 0x06 0x00 0x00 0x7fff0000  return ALLOW
#  0010: 0x06 0x00 0x00 0x00000000  return KILL
#
# return ALLOW at line 0009

Screenshots

Dump

dump

Emu

emu

emu

Supported Architectures

  • x86_64
  • x32
  • x86
  • arm64 (@saagarjha)
  • s390x (@iii-i)

Pull Requests of adding more architectures support are welcome!

Development

I recommend to use rbenv for your Ruby environment.

Setup

  • Install bundler
    • $ gem install bundler
  • Clone the source
    • $ git clone https://github.com/david942j/seccomp-tools && cd seccomp-tools
  • Install dependencies
    • $ bundle install

Run tests

$ bundle exec rake

I Need You

Any suggestions or feature requests are welcome! Feel free to file issues or send pull requests. And, if you like this work, I'll be happy to be starred 😬

seccomp-tools's People

Contributors

david942j avatar dependabot-preview[bot] avatar dependabot[bot] avatar iii-i avatar mephi42 avatar p4n74 avatar saagarjha avatar solarkennedy avatar thekidofarcrania avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

seccomp-tools's Issues

It run the target ELF file instead of showing the sec-info

Some basic infomation:
System:

  • Ubuntu 20.04.4 with ldd (Ubuntu GLIBC 2.31-0ubuntu9.9) 2.31
  • [email protected]
  • apt 2.0.9 (amd64)
  • gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
  • Both SeccompTools Version 1.0.0 and 1.5.0(The lateest) have been tested

Files in the workdir:

  • pwn(The target)

I want to get the sec-info by using following command line:

seccomp-tools dump ./pwn

As expects, it should demostrate some info like these:
image

However, it just run my ELF file instead of showing them:
image

The following command lines have been tested with no work:

sudo seccomp-tools dump ./pwn
seccomp-tools dump pwn

Is this a bug, or I didn't run it as a correct way?

Support dumping/disassembling to an input format accepted by `seccomp-tools asm`

Right now this is possible:

seccomp-tools asm filter.asm -f raw | seccomp-tools disasm -

But as far as I can tell, this is not:

seccomp-tools disasm filter.bin -f <format-name> | seccomp-tools asm -

Can we support disasm and dump outputting in a format accepted by asm? Or have asm accept the format output by dump and disasm.

seccomp-tools will hang on some samples

Hello, seccomp-tools hanged on some samples(attached below), based on the newest secomp-tools version.
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic

$ ruby --version
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux]

$ seccomp-tools --version
SeccompTools Version 1.6.1
vuln.zip

Faulty line number in compiler error message

During the process stage if an ArgumentError occurs (typically means the code has a syntax error), the code will catch this error and will call invalid and pass the correct line number (as it will use @input.size - 1

But if an ArgumentError error occurs in the compile stage (for errors that might require one pass first, i.e. if a bad jump occurs, or jump to invalid labels), the compile function will pass the wrong line number (it will pass the index of the instruction that it is parsing as the line number, which is not always equaled the current line number because of comments/labels can take up a whole line but is not added into the list of instructions).

The complication arises because I'm currently updating some of the coverage tests for backwards jumping and absolute label jumping... so I think I will first commit my changes, and then if you would like I will also try to fix this issue. (This will therefore mostly likely cause a build failure in specs b/c of this discrepancy)

For example, this code, which has a bad jump to a misspelled label:

# a comment
A = sys_number
A == open ? mispelled : next

return ALLOW

misspelled:
return ERRNO(1)

Produces this error instead:

Traceback (most recent call last):
	8: from /usr/local/bin/seccomp-tools:23:in `<main>'
	7: from /usr/local/bin/seccomp-tools:23:in `load'
	6: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/bin/seccomp-tools:5:in `<top (required)>'
	5: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/cli/cli.rb:54:in `work'
	4: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/cli/asm.rb:43:in `handle'
	3: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/asm.rb:31:in `asm'
	2: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:49:in `compile!'
	1: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:61:in `rescue in compile!'
/var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:268:in `invalid': Invalid instruction at line 2: "A = sys_number" (ArgumentError)
Error: Undefined label "mispelled"

The error should be Invalid instruction at line 3: A == open ? mispelled : next, but instead it erroneously says error on line 2.

Support stdin for asm

Can u add stdin support for seccomp-tools asm.

File only is not good for automation.

Dumping seccomp works wrong

Hi, I want to report a function of seccomp-tools which is dump. When I merge seccomp of x86 with seccomp of x64, seccomp-tools dump shows output incorrectly.

Here is the source

void install_seccomp_filter()
{
    scmp_filter_ctx ctx32, ctx64;
    ctx32 = seccomp_init(SCMP_ACT_KILL); // default action: kill
    ctx64 = seccomp_init(SCMP_ACT_KILL); // default action: kill
    seccomp_arch_remove(ctx32, SCMP_ARCH_NATIVE);
    seccomp_arch_remove(ctx64, SCMP_ARCH_NATIVE);
    seccomp_arch_add(ctx32, SCMP_ARCH_X86);
    seccomp_arch_add(ctx64, SCMP_ARCH_X86_64);
    
    // setup basic whitelist
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(lgetxattr), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(chmod), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(getpriority), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(setpriority), 0);
    
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(clock_nanosleep), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
    seccomp_rule_add(ctx64, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);

    seccomp_rule_add(ctx32, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
    seccomp_rule_add(ctx32, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), 0);
    seccomp_rule_add(ctx32, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
    seccomp_rule_add(ctx32, SCMP_ACT_ALLOW, SCMP_SYS(_llseek), 0);
    seccomp_rule_add(ctx32, SCMP_ACT_ALLOW, SCMP_SYS(getdents), 0);

    seccomp_merge(ctx64, ctx32);

    // build and load the filter
    seccomp_load(ctx64);  
}

As you can see that with x86, syscall mmap, mmap2, getdents are allowed but when dumping, it doesn't say that mmap or getends is allowed:

image

I got this error while deploying a challenge for sekai ctf but didn't want to submit immediately at that time, I want the ctf ended and I would submit later, which is this issue.

Should labels include uppercase letters?

(Sorry i might be raising quite a few issues now, but...)

I noticed the current regex for matching labels is /[a-z_][a-z0-9_]+/ (in LABEL_REGEX), which only allows for lower case letters. Though typically, (for many programming languages) they allow both upper case and lower case letters when specifying an identifier.

Is this intentional or not?

Invalid code generation with conditional far jumps

This is a bit of an edge case, and probably doesn't apply in most situations, but since it renders code generation incorrect, I figured I should still report it so a warning/error can be added.

When assembling long filters, seccomp-tools asm truncates jump offsets and considers only the lowest byte for conditional jumps. This leads to invalid code being generated.

In the following (very artificial, but the point still stands) example, the first instruction ends up jumping in the middle of the filter instead of jumping to the last instruction, its intended target. In this particular case, the bug silently changes the meaning of the filter, making it always return ALLOW instead of the intended behaviour.

A = args[0]
A == 0 ? kill : allow

A = 0
[...]
A = 0

allow:
return ALLOW
kill:
return KILL
Full filter code
A = args[0]
A == 0 ? kill : allow

A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0
A = 0

allow:
return ALLOW
kill:
return KILL

When disassembled, I get the following:

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000010  A = args[0]
 0001: 0x15 0x7d 0x7c 0x00000000  if (A == 0x0) goto 0127 else goto 0126
[...]
 0126: 0x00 0x00 0x00 0x00000000  A = 0
 0127: 0x00 0x00 0x00 0x00000000  A = 0
[...]
 0382: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0383: 0x06 0x00 0x00 0x00000000  return KILL

I don't see an easy solution in the assembler, but seccomp-tools asm should generate an error when trying to assemble a conditional jump with jt >= 256 or jf >= 256.

New Logo

Hello David942j.
You have a great app, unfortunately this app does not have a logo yet, may I donate a logo for your app?

Using seccomp-tools for binary hardening

I've been doing binary hardening recently. And I found that your tool is really helpful by generating bpf. I inject it into the binary and successfully ban some syscalls like execve.

check this code.

    inject_code = '''
    mov rax, {libc_start_main}
    mov r15, qword ptr [rax]
    add r15, {offset}
    
    mov rdi, 38
    mov rsi, 1
    mov rdx, 0
    mov rcx, 0
    mov r8, 0
    call r15
    
    mov rdi, 22
    mov rsi, 2
    mov rdx, {filter_addr}
    call r15
    
    ret''  #r15 = &prctl 

See if you got an idea to add binary injection in your project.

Parsing issues of syscall numbers

Okay so this is actually two issues, so I will place them on two tickets, but I feel that they might be related.

First let's say I use a syscall that exist in x86_64 (or amd64) but not in i386, such as readdir:

A = readdir

If I do not pass a flag -a i386, then this syscall should not exist, and I should expect this error:

Traceback (most recent call last):
	10: from /usr/local/bin/seccomp-tools:23:in `<main>'
	 9: from /usr/local/bin/seccomp-tools:23:in `load'
	 8: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/bin/seccomp-tools:5:in `<top (required)>'
	 7: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/cli/cli.rb:54:in `work'
	 6: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/cli/asm.rb:43:in `handle'
	 5: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/asm.rb:30:in `asm'
	 4: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/asm.rb:30:in `each'
	 3: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/asm.rb:30:in `block in asm'
	 2: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:27:in `process'
	 1: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:38:in `rescue in process'
/var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:268:in `invalid': Invalid instruction at line 1: "A = readdir" (ArgumentError)

or something like that, since this constant does not exist in the amd64 architecture, but instead I get a pretty cryptic error like the following:

Traceback (most recent call last):
	10: from /usr/local/bin/seccomp-tools:23:in `<main>'
	 9: from /usr/local/bin/seccomp-tools:23:in `load'
	 8: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/bin/seccomp-tools:5:in `<top (required)>'
	 7: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/cli/cli.rb:54:in `work'
	 6: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/cli/asm.rb:43:in `handle'
	 5: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/asm.rb:31:in `asm'
	 4: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:50:in `compile!'
	 3: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:50:in `with_index'
	 2: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:50:in `map'
	 1: from /var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:53:in `block in compile!'
/var/lib/gems/2.5.0/gems/seccomp-tools-1.2.0/lib/seccomp-tools/asm/compiler.rb:97:in `compile_assign': undefined method `first' for nil:NilClass (NoMethodError)

Building from source...

How to build seccomp-tools from source? Are there any steps to do or what not? (sorry I don't do much ruby dev so I don't really know right tools to use to build it)

Support pread/pwrite

Thank you for your awesome project! It is very helpful for my research.

When I executed seccomp-tools emu ${bpf_program} pread, some errors occurred.
The error message was shown in the following figure.
截圖 2021-03-06 上午12 21 15

Wrongly parsing constant identifiers

Related to #54.

When I tried exploring the bug in #54 further, and modified my code to this:

A = readdirx

Which should give me a compiler error when compiled, even on i386, I found that I get no error, and it decompiles to this:

 line  CODE  JT   JF      K
=================================
 0000: 0x00 0x00 0x00 0x00000059  A = 89

Which matches the sys_readdir constant even though I set it to readdirx. Something might be wrong in how the tokenizer or parser parses tokens, probably. I haven't looked much further into the code for it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.