ネイティブコード以外の実行ファイルに対してsetuidが効かない件

ネットワークセキュリティHacks―プロが使うテクニック&ツール100選を読むまですっかり忘れていた。Cを使ういい機会なのでやってみる。

TCPの321番ポートを開くだけのプログラム。

まずはC.

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define ERROR(x) { perror(x); exit(1); } 

int main(int argc, char *argv[])
{
    int sock_s, sock_c;
    socklen_t len_c;
    struct sockaddr_in addr_s, addr_c;

    if ((sock_s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
        ERROR("socket");

    addr_s.sin_family = PF_INET;
    addr_s.sin_addr.s_addr = inet_addr("0.0.0.0");
    addr_s.sin_port = htons(321);
    if (bind(sock_s, (struct sockaddr*) &addr_s, sizeof(addr_s)) < 0)
        ERROR("bind");
    
    if (listen(sock_s, 5) < 0)
        ERROR("listen");

    if ((sock_c = accept(sock_s, (struct sockaddr*) &addr_c, &len_c)) < 0)
        ERROR("accept");

    exit(0);
}

で、これをコンパイルしてrootのものにしたうえでsetuid属性をつけてあげると一般ユーザーでも321番ポートを開ける。

komamitsu@potato:~/lab/c/tcpserv$ ls -l tcpserv
-rwsr-xr-x 1 root komamitsu 9313 2009-04-09 01:23 tcpserv
komamitsu@potato:~/lab/c/tcpserv$ ./tcpserv 

つぎはRuby.

#!/usr/bin/env ruby
require 'socket'

s = TCPServer.new('0.0.0.0', 321)
s.listen(5)
c = s.accept

み、短いな…
で同じようにsetuidして実行すると。

komamitsu@potato:~/lab/ruby$ ls -l tcpserv 
-rwsr-xr-x 1 root komamitsu 97 2009-04-09 01:27 tcpserv
komamitsu@potato:~/lab/ruby$ ./tcpserv 
./tcpserv:4:in `initialize': Permission denied - bind(2) (Errno::EACCES)
        from ./tcpserv:4:in `new'
        from ./tcpserv:4

setuidはスクリプト形式の実行ファイルには効かないらしい。

いきおいでOCamlも。もはや何が目的かどうでも良くなってきた。

open Unix

let _ =
  let sa = ADDR_INET (inet_addr_any, 321) in
  ignore (establish_server (fun ich och -> ()) sa)

お、こちらも短いぞ。
で、バイトコードとネイティブコードの実行ファイルをつくってrootのsetuidつけて実行。

komamitsu@potato:~/lab/ocaml/tcpserv$ ls -ltr tcpserv_*
-rwsr-xr-x 1 root komamitsu  55072 2009-04-09 01:33 tcpserv_byte
-rwsr-xr-x 1 root komamitsu 256736 2009-04-09 01:33 tcpserv_native
komamitsu@potato:~/lab/ocaml/tcpserv$ ./tcpserv_byte 
Fatal error: exception Unix.Unix_error(1, "bind", "")
komamitsu@potato:~/lab/ocaml/tcpserv$ ./tcpserv_native 

と、まあネイティブコード以外は駄目よ、と。