Skip to content

Instantly share code, notes, and snippets.

@hhc0null
Last active February 26, 2020 21:52
Show Gist options
  • Save hhc0null/49cc73badc80082881c3 to your computer and use it in GitHub Desktop.
Save hhc0null/49cc73badc80082881c3 to your computer and use it in GitHub Desktop.
[メモ書き] libsecompのpseudo syscallについて

libsecompのpseudo syscallについて

 PlaidCTF 2014のjackshitを読む際に, libseccompのseccomp_rule_addでsyscallに負数を渡していることが気になったのでメモ書きとして残しておく.


1. Seccomp

 Secure Computing(Seccomp)は, プロセスのサンドボックス化のためのLinuxカーネルの機構である. read/write/exit/sigreturn以外を制限するMode 1はLinuxの2.6.12でマージされた機能である[1].
 Linux 3.5ではMode 2が追加され, 任意のシステムコールの制限が可能となり, 記述もBSD Packet Filter(BPF)を利用することとなった[2].

1.2 libseccomp

 libseccomp[3]は, Seccompを使う上で生じるアーキテクチャ毎の差異などの吸収を行うライブラリである. 現在, x86, ARM, MIPSがサポートされている[4].

1.2.1 利用例

 マニュアルにあるCでのサンプル[5]をFig. 1に示す.

Fig. 1 An example of seccomp code

#include <fcntl.h>
#include <seccomp.h>
#include <sys/stat.h>
#include <sys/types.h>

#define BUF_SIZE    256

int main(int argc, char *argv[])
{
    int rc = -1;
    scmp_filter_ctx ctx;
    struct scmp_arg_cmp arg_cmp[] = { SCMP_A0(SCMP_CMP_EQ, 2) };
    int fd;
    unsigned char buf[BUF_SIZE];

    ctx = seccomp_init(SCMP_ACT_KILL); // 全システムコールの制限をデフォルトとする. 
    if (ctx == NULL)
        goto out;

    /* ... */

    fd = open("file.txt", 0);

    /* ... */

    // closeを許可. 
    rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
    if (rc < 0)
        goto out;

    // readを第一引数がfd, 第二引数がbuf, 第三引数がBUF_SIZE以下の場合にのみ許可. 
    rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 3,
            SCMP_A0(SCMP_CMP_EQ, fd),
            SCMP_A1(SCMP_CMP_EQ, (scmp_datum_t)buf),
            SCMP_A2(SCMP_CMP_LE, BUF_SIZE));
    if (rc < 0)
        goto out;

    // writeを第一引数がfdの場合にのみ許可. 
    rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
            SCMP_CMP(0, SCMP_CMP_EQ, fd));
    if (rc < 0)
        goto out;

    // writeをarg_cmpに指定した条件(SCMP_A0(SCMP_CMP_EQ, 2): 第一引数が2)にのみ許可. 
    rc = seccomp_rule_add_array(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
            arg_cmp);
    if (rc < 0)
        goto out;

    rc = seccomp_load(ctx); // ctxをロード. 
    if (rc < 0)
        goto out;

    /* ... */

out:
    seccomp_release(ctx); // allowされなかったシステムコールを全て制限. 
    return -rc;
}

2. jackshitでの例

 PlaidCTF 2014のPwnable200 jackshit[6]での例を元に, Pseudo syscallについて説明する.

2.1 気になった箇所

 jackshitの逆アセンブルの結果とそのデコンパイル例をFig. 2, Fig. 3に示す.

Fig. 2 The curious disassembly of jackshit

 8048c56:	83 ec 0c             	sub    $0xc,%esp
 8048c59:	6a ff                	push   $0xffffffff
 8048c5b:	e8 e0 fb ff ff       	call   8048840 <exit@plt>
...
 8048ca2:	6a 00                	push   $0x0
 8048ca4:	6a 9b                	push   $0xffffff9b
 8048ca6:	68 00 00 ff 7f       	push   $0x7fff0000
 8048cab:	53                   	push   %ebx
 8048cac:	e8 2f fb ff ff       	call   80487e0 <seccomp_rule_add@plt>
 8048cb1:	83 c4 10             	add    $0x10,%esp
 8048cb4:	85 c0                	test   %eax,%eax
 8048cb6:	75 9e                	jne    8048c56 <close@plt+0x346>

Fig. 3 A sample of decompile of the part.

if(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, -101), 0) != 0) {
    exit(-1);
}

 Linuxでのシステムコール番号は一般的に0以上なので, -101ではエラーになると考えられる.

2.2 Pseudo syscall

 結果から述べると, この「seccomp_rule_addのsyscallに負数を設定していた」というものはlibseccompのseccomp.hに定義されているPseudo syscallによるものである.
 通常はシステムコール名とシステムコール番号とは/usr/includeのどこかのヘッダファイルにマクロとして定義されている. 筆者の環境では/usr/include/asm/unistd_32.hに在った. このヘッダファイルを利用することで, システムコール番号で直接的に指定すること無く対象とするシステムコールを指すことができる.
 しかし, すべての環境にそのヘッダファイルがあるとは限らないため, そのような場合にも対応できるようにlibseccomp/include/seccomp.hにPseudo syscallとしていくつかのシステムコール番号が補助的に記述されているのである[7]. socket関連(-100番台)やIPC関連(-200番台)のシステムコールをはじめ, その他一般的なシステムコール番号が用意されている.

3. まとめ

 以下の3点がわかった.

  • LinuxにはSeccompというサンドボックス化機構があり, Mode 2では全てのシステムコールについて制限/許可を行える.
  • Pseudo syscallは環境の差異を埋めるための仕組みである.
  • /usr/includeのどこにもunistd_32.hが無い環境が有り得る.

 今後はlibseccompを読み進め, Linux本体のSeccompの実装にも触れていきたい.


[1] [PATCH] seccomp: secure computing support
[2] The seccomp-bpf sandbox
[3] seccomp/libseccomp
[4] libseccomp/seccomp.h.in at d1019115acdc8460c9a1f8a878768001a3c32431 · seccomp/libseccomp
[5] Ubuntu Manpage: seccomp_rule_add, seccomp_rule_add_exact - Add a seccomp filter rule
[6] write-ups-2014/plaid-ctf-2014/jackshit at master · ctfs/write-ups-2014
[7] libseccomp/seccomp.h.in at master · seccomp/libseccomp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment