
grsecurity
有効なカーネルを使用していますCONFIG_GRKERNSEC_SOCKET_SERVER
。
[*] Socket restrictions
[ ] Deny any sockets to group (NEW)
[ ] Deny client sockets to group (NEW)
[*] Deny server sockets to group
これにより、ユーザーが「サーバー」ソケットを作成する(Apacheを起動するなど)、クライアントソケット(Firefoxなど)を開くことができます。
実際、すべてのWebクライアントはうまく動作します(Firefox、telnet、ssh、nc、w3m、...)。 Chromeブラウザ(Chromium)のみ機能しません。
コマンドラインからChromeを起動すると、次のエラーが発生します。
ERROR:address_tracker_linux.cc(138)] Could not bind NETLINK socket: Permission denied
libudev: udev_monitor_enable_receiving: bind failed: Permission denied
FATAL:udev_linux.cc(31)] Check failed: 0 == ret (0 vs. -1)
Aborted
ログには以下が表示されます。
grsec: denied bind() by /usr/lib/chromium/chromium[NetworkChangeNo:3920]
grsec: denied bind() by /usr/lib/chromium/chromium[WorkerPool/3922:3922]
grsec: denied bind() by /usr/lib/chromium/chromium[Chrome_IOThread:3934]
grsec: denied bind() by /usr/lib/chromium/chromium[NetworkChangeNo:3966]
grsec: denied bind() by /usr/lib/chromium/chromium[WorkerPool/3968:3968]
grsec: denied bind() by /usr/lib/chromium/chromium[Chrome_IOThread:3980]
他のクライアント(Firefox)はすべて正常に動作しているため、Chromeが起動しない理由を説明できる人はいますか?
Debian Wheezy(64ビット)でChrome(Chromium)37を使用しています。
答え1
サーバーソケットを拒否するとAF_NETLINK
ソケットも拒否されるため、Chromiumは起動されず、何らかの理由でChromiumはサーバーと通信する必要があります。これudev
にはAF_NETLINK
ソケットが必要です。確かで権威のあるソースはありませんが、基本的なソースコードを使用して最初の原則から説明しようとします。
私は最初のエラーメッセージを調べ始めました。エラーメッセージを生成するChromiumのコードは次のとおりです。https://src.chromium.org/svn/trunk/src/net/base/address_tracker_linux.cc行138:
// Request notifications.
struct sockaddr_nl addr = {};
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
// TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY |
RTMGRP_LINK;
int rv = bind(netlink_fd_,
reinterpret_cast<struct sockaddr*>(&addr),
sizeof(addr));
if (rv < 0) {
PLOG(ERROR) << "Could not bind NETLINK socket";
AbortAndForceOnline();
return;
}
実際の grsec 関連の失敗は、bind()
インターフェイスの IPv4 または IPv6 アドレスが変更されるたびに、リンク状態が変更されたときに通知を受け取る netlink ソケットを設定しようとする呼び出しで発生します。
この呼び出しはカーネルのシステム呼び出しによって処理されます。net/socket.c
:
SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{
struct socket *sock;
struct sockaddr_storage address;
int err, fput_needed;
これはシステムコールといくつかのローカル変数を宣言します。システムコール宣言がbind()
Chromiumコードの呼び出しと一致することがわかりますint fd, struct sockaddr __user * umyaddr, int addrlen
。
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock) {
ファイル記述子でソケットを見つけます。アウトレットを見つけたら..
err = move_addr_to_kernel(umyaddr, addrlen, &address);
if (err >= 0) {
これにより、ユーザー空間によって提供されるデータがカーネル空間にコピーされます。エラーがなければ...
err = security_socket_bind(sock,
(struct sockaddr *)&address,
addrlen);
if (!err)
これにより、ロードされたすべてのLSM(SELinuxなど)に呼び出しが許可されていることを確認する機会が提供されます。もしそうなら...
err = sock->ops->bind(sock,
(struct sockaddr *)
&address, addrlen);
バインディングは他の場所で行われ、標準のカーネルコード分析が完了しました。
grsecはnet/socket.c
特に複数の場所にパッチが適用され、LSMセキュリティチェックの前にセルフチェックを追加します(参照)。https://grsecurity.net/test/grsecurity-3.0-3.18.6-201502062100.patch;探すSYSCALL_DEFINE3(bind
):
if (gr_handle_sock_server((struct sockaddr *)&address)) {
err = -EACCES;
goto error;
}
err = gr_search_bind(sock, (struct sockaddr_in *)&address);
if (err)
goto error;
最初の確認は以下に関連していますgr_handle_sock_server()
。
gr_handle_sock_server(const struct sockaddr *sck)
{
#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER
if (grsec_enable_socket_server &&
in_group_p(grsec_socket_server_gid) &&
sck && (sck->sa_family != AF_UNIX) &&
(sck->sa_family != AF_LOCAL)) {
gr_log_noargs(GR_DONT_AUDIT, GR_BIND_MSG);
return -EACCES;
}
#endif
return 0;
}
これは「グループに対するサーバーソケット拒否」チェックを実装します。コメントで確認されているように、システムではgrsec_enable_socket_server
1なので、グループ1001で実行すると成功しif
(sck->sa_family == AF_NETLINK
この場合)、アクセスは拒否されます。
Chromiumコードに戻ると、エラーメッセージが記録され、AbortAndForceOnline()
ブラウザがオンラインだと思うように設定されます。したがって、これは起動失敗を説明しません。
さらに進む前に失敗を再現してみました。この目的のために、最初の関数へのバインディングをauthbind
防ぐように調整しました。AF_NETLINK
libauthbind.c
bind()
case
switch
case AF_NETLINK:
puts("Denying AF_NETLINK");
return -EACCES;
生成されたライブラリで実行するとエラーが再現されます。
% LD_PRELOAD=/usr/lib/authbind/libauthbind.so.1 chromium
Denying AF_NETLINK
[15858:15876:0214/160730:ERROR:address_tracker_linux.cc(154)] Could not bind NETLINK socket: Success
Denying AF_NETLINK
libudev: udev_monitor_enable_receiving: bind failed: No such file or directory
[15858:15890:0214/160730:FATAL:udev_linux.cc(29)] Check failed: 0 == ret (0 vs. -2)
zsh: abort LD_PRELOAD=/usr/lib/authbind/libauthbind.so.1 chromium
(「成功」と「該当するファイルディレクトリなし」という奇妙なエラーメッセージは、私が設定していないためですerrno
。)
したがって、停止は実際に関連していますbind()
。udev_linux.cc
次の29行目を確認してください。
int ret = udev_monitor_enable_receiving(monitor_.get());
CHECK_EQ(0, ret);
ret
udev_monitor_enable_receiving()
netlinkソケットをバインドできず、CHECK_EQ
ここでアサーションが失敗するため、これは負です。https://src.chromium.org/svn/trunk/src/base/logging.h実装のため)。これは中断信号を生成し、Chromiumは使用されているシェルに従って一種の「中断」メッセージで終了します。