TenForward

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

ping コマンドの file capability(1)

(いまさらのお話とは思いますが自分用のメモに)

LinuxCapability、何度も理解しようとして完全に理解できないままなんですが、ちょっとした理由で File capability を調べてます。最近は ambient capability なんてのもあって理解が遠のいてます。:-p

file capability といえば、まず登場するのはこのコマンドではないでしょうか?(違う?) Ubuntu 18.04.3 では次のように setuid されています。file capability は特に設定されていません。

$ ls -l /bin/ping
-rwsr-xr-x 1 root root 64424 Jun 28 20:05 /bin/ping
$ getcap /bin/ping
$ 

これは想定通りだったんですが、先日リリースしたばかりの CentOS 8 で見てみると、

$ ls -l /bin/ping
-rwxr-xr-x. 1 root root 69160 May 11 23:22 /bin/ping
$ getcap /bin/ping 
/bin/ping = cap_net_admin,cap_net_raw+p

setuid されておらず file capability が設定されていて、「おお、イマドキのセキュアな設定っぽい」と思いました(CentOS 7 からそうだったようなので今更感満載です)。でも +p と設定されています。あれ? +ep でじゃないとマズくない? +e がないと実行できなくない? 例のあのややこしい条件式からいっても。

$ man 7 capabilities
  : (snip)
           P'(ambient)     = (file is privileged) ? 0 : P(ambient)

           P'(permitted)   = (P(inheritable) & F(inheritable)) |
                             (F(permitted) & P(bounding)) | P'(ambient)

           P'(effective)   = F(effective) ? P'(permitted) : P'(ambient)

           P'(inheritable) = P(inheritable)    [i.e., unchanged]

           P'(bounding)    = P(bounding)       [i.e., unchanged]

それはそのとおりなのですが、CentOS で採用されている ping が含まれている iputils のコードを確認するとその理由がわかります(たぶん)。

#ifdef HAVE_LIBCAP
int modify_capability(cap_value_t cap, cap_flag_value_t on)
{
    cap_t cap_p = cap_get_proc();
    cap_flag_value_t cap_ok;
    int rc = -1;

    if (!cap_p) {
        error(0, errno, "cap_get_proc");
        goto out;
    }

    cap_ok = CAP_CLEAR;
    cap_get_flag(cap_p, cap, CAP_PERMITTED, &cap_ok);
    if (cap_ok == CAP_CLEAR) {
        rc = on ? -1 : 0;
        goto out;
    }

    cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &cap, on);

    if (cap_set_proc(cap_p) < 0) {
        error(0, errno, "cap_set_proc");
        goto out;
    }

    cap_free(cap_p);
    cap_p = NULL;

    rc = 0;
out:
    if (cap_p)
        cap_free(cap_p);
    return rc;
}

https://github.com/iputils/iputils/blob/4b0a0ab7898b093ef55c4a8cacea9a21c37a451f/ping_common.c#L189

CAP_PERMITTED を確認して、付与されていれば CAP_EFFECTIVE を設定してます(と思う)。

これで +ep でなく +p な理由がわかりました。ping コマンド自体で +p が付いていれば(というか付いている結果として permitted が設定されていれば、かな?)必要な capability を設定してシステムコールを呼ぶプログラムになっているからでした。

とはいえこれでは +e が不要な理由はわかりましたが、付けておいてマズい理由はわかりません。ま、セキュリティ観点から不要な権限は付けておく理由はない、というだけでも理由になりますが。

(続く)

tenforward.hatenablog.com