TenForward

技術ブログ。はてなダイアリーから移転しました

ICMP sockets

連載の第42回

ファイルケーパビリティは安全のためにコピーすると設定が外れます。

なんてことを書いてますが、同僚から「Arch Linux でやるとなぜか ping が実行できてしまう」という情報が。確かに Arch でやると実行できてしまいます。

$ lsb_release -d
Description:    Arch Linux
$ cp /usr/bin/ping .
$ getcap ./ping 
$ ./ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.025 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms

strace とかで見てみるとどうも SOCK_RAW でなく SOCK_DGRAM を使ってる模様。どうやらこれらしい。hayajo さんからも同じ情報を頂いて自信を持って、これを手がかりにググってみると、

icmp(7) にも記載が。えー、2.6.39 から?

$ man icmp
    :(snip)
       ping_group_range (two integers; default: see below; since Linux 2.6.39)
              Range of the group IDs (minimum and maximum  group  IDs,  inclu‐
              sive) that are allowed to create ICMP Echo sockets.  The default
              is "1 0", which means no group is allowed to  create  ICMP  Echo
              sockets.

いやー、Linux 奥が深いですね。こんなの知りませんでした。Arch を確認してみると確かに設定されています。

$ sysctl -a 2>/dev/null | grep ping_group_range 
net.ipv4.ping_group_range = 0    2147483647

Plamo だと

$ /sbin/sysctl -a 2>/dev/null | grep ping
net.ipv4.ping_group_range = 1    0

Arch の値はやりすぎ感あるのでとりあえず 0〜65534 とすると、

$ sudo sysctl -w net.ipv4.ping_group_range="0 65534"
net.ipv4.ping_group_range = 0 65534
$ /sbin/sysctl -n net.ipv4.ping_group_range
0  65534

設定できたので、

$ cp /bin/ping .
$ /sbin/getcap ./ping 
$ ./ping -c1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) バイトのデータ
64 バイト応答 送信元 127.0.0.1: icmp_seq=1 ttl=64 時間=0.013ミリ秒

--- 127.0.0.1 ping 統計 ---
送信パケット数 1, 受信パケット数 1, パケット損失 0%, 時間 0ミリ秒
rtt 最小/平均/最大/mdev = 0.013/0.013/0.013/0.000ミリ秒

実行できました。

ちなみに「安全のためにコピーしたら外れる」とか書きましたが、cp コマンドでも CAP_SETFCAP ケーパビリティがあれば --preserve=xattr とかやればファイルケーパビリティ保存したままコピーされますね。

(補足・2019-11-29) Twitter で systemd がそのように設定していると教えていただきました。ありがとうございます。

        * This release enables unprivileged programs (i.e. requiring neither
          setuid nor file capabilities) to send ICMP Echo (i.e. ping) requests
          by turning on the "net.ipv4.ping_group_range" sysctl of the Linux
          kernel for the whole UNIX group range, i.e. all processes. This
          change should be reasonably safe, as the kernel support for it was
          specifically implemented to allow safe access to ICMP Echo for
          processes lacking any privileges. If this is not desirable, it can be
          disabled again by setting the parameter to "1 0".