Linux: 0, 1, 2 のファイルディスクリプタを閉じて setuid したバイナリ実行の挙動を調べる

以下の記事を読んで setuid したバイナリを実行する挙動で新たに知ったことがあった

lwn.net

以下に引用する

Some OSes (e.g., OpenBSD) protect against this by opening /dev/null on any unused FDs in the 0-2 range when execing a setuid program. As far as I can tell, Linux does not (but maybe I'm missing something...). This behavior is permitted in POSIX.1-2001, but not before.


いくつかの OS (たとえば OpenBSD) は、setuid プログラムを実行するときに、0-2 の範囲の未使用の FD で /dev/null をオープンして、この問題を防いでいます。私の知る限り、Linuxはそうではありません(しかし、もしかしたら私は何かを見逃しているかもしれません...)。この動作はPOSIX.1-2001では許可されているが、それ以前は許可されていない。

DeepL 翻訳

OpenBSD の execve(2) の man にも 下記の説明が付いている

     In the case of a new setuid or setgid executable being exe-
     cuted, if file descriptors 0, 1, or 2 (representing stdin, stdout, and
     stderr) are currently unallocated, these descriptors will be opened to
     point to some system file like /dev/null. The intent is to ensure these
     descriptors are not unallocated, since many libraries make assumptions
     about the use of these 3 file descriptors.

なるほどなー 。実際にどうなんだろうと Linux で試した。

実験環境

Ubuntu Jammy で実験をします

hiboma@vps:~$ uname -a
Linux vps 5.15.0-60-generic #66-Ubuntu SMP Fri Jan 20 14:29:49 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

hiboma@vps:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04 LTS
Release:    22.04
Codename:   jammy

実験用のコード

C のコードで sleep するだけの setuid バイナリを用意します。

#include <unistd.h>

int main() {
    sleep(100);
}

以下の手順で setuid なバイナリとします。

$ gcc setuid-sleep.c -o setuid-sleep
$ sudo chown root.root setuid-sleep 
$ sudo chmod 4755 setuid-sleep 

$ ls -hal setuid-sleep
-rwsr-xr-x 1 root root 16K Jun  7 10:24 setuid-sleep

0, 1, 2 のファイルディスクリプタを閉じてから 1 setuid なバイナリを実行する bashシェルスクリプトも用意します

#!/bin/bash                                                                                                                                                                                                      
                                                                                                                                                                                                                 
exec 0<&-                                                                                                                                                                                                        
exec 1<&-                                                                                                                                                                                                        
exec 2<&-                                                                                                                                                                                                        
                                                                                                                                                                                                                 
exec ./setuid-sleep                                                                                                                                                                                              

実験

シェルスクリプトを実行します。これで 0, 1, 2 のデスクリプタを閉じて setuid したバイナリを exec できます。

$ ./test.sh

setuid したバイナリを実行しているプロセスの lsof をとって見ます。

$ sudo lsof -p $(pgrep setuid-sleep)
COMMAND       PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
setuid-sl 1120951 root  cwd    DIR  252,2     4096 134434 /home/hiboma
setuid-sl 1120951 root  rtd    DIR  252,2     4096      2 /
setuid-sl 1120951 root  txt    REG  252,2    15968 135566 /home/hiboma/setuid-sleep
setuid-sl 1120951 root  mem    REG  252,2  2216304   4337 /usr/lib/x86_64-linux-gnu/libc.so.6
setuid-sl 1120951 root  mem    REG  252,2   240936    194 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
setuid-sl 1120951 root    0w   CHR    1,7      0t0      8 /dev/full 👈
setuid-sl 1120951 root    1r   CHR    1,3      0t0      5 /dev/null 👈
setuid-sl 1120951 root    2r   CHR    1,3      0t0      5 /dev/null 👈

/dev/full, /dev/null を開いていますね!

/dev/full, /dev/null を open するのはどこ?

strace をとって調べて見たところ、ld-linux-x86-64.so.2 っぽい。

openat(AT_FDCWD, "/dev/full", O_WRONLY|O_NOFOLLOW) = 0
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x9748) [0x26b38]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x903e) [0x2642e]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x24a5) [0x1f895]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x41c8) [0x215b8]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x2ec8) [0x202b8]

... 略


openat(AT_FDCWD, "/dev/null", O_RDONLY|O_NOFOLLOW) = 1
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x9748) [0x26b38]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x907e) [0x2646e]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x24a5) [0x1f895]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x41c8) [0x215b8]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x2ec8) [0x202b8]

... 略


openat(AT_FDCWD, "/dev/null", O_RDONLY|O_NOFOLLOW) = 2
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x9748) [0x26b38]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x90c2) [0x264b2]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x24a5) [0x1f895]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x41c8) [0x215b8]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x2ec8) [0x202b8]

ソースは?

  • どういう実装になっているのかも気になって glibc のソースを辿ってみたのでしたが、分からず
  • _dl_catch_error 周りも複雑でわからん。 slack-gpt の回答は以下の通りだった

_dl_catch_errorは、GNU Cライブラリ (glibc) の内部で使用される関数です。この関数は、動的リンカーによる共有ライブラリのロードやシンボルの解決中に発生するエラーをキャッチ(捉え)する役割を果たします。


具体的には、_dl_catch_errorは以下のような機能を提供します: 1. エラーハンドラの設定: エラーが発生した際に呼び出される関数を設定できます。これにより、バリエーションに富むエラーハンドリングを行うことができます。

  1. エラーの発生処理: _dl_catch_error は、エラーが発生した際にエラーメッセージを生成し、設定されたエラーハンドラに渡します。これにより、詳細なエラー情報が収集され、適切なエラー処理が行われます。

  2. エラーハンドラのリセット: エラーが捉えられた後には、元の状態に戻します。_dl_catch_errorはビルトインのエラー処理機能を提供することで、動的リンカーによる共有ライブラリのロードやシンボルの解決を安全かつ信頼性の高いものにする役割を果たします

実験の補足

ファイルディスクリプタを閉じずに setuid バイナリを実行すると、0, 1, 2 のファイルディスクリプタ/dev/pts を指していました

~$ sudo lsof -p $(pgrep setuid-sleep)
COMMAND       PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
setuid-sl 1125289 root  cwd    DIR  252,2     4096 134434 /home/hiboma
setuid-sl 1125289 root  rtd    DIR  252,2     4096      2 /
setuid-sl 1125289 root  txt    REG  252,2    15968 135566 /home/hiboma/setuid-sleep
setuid-sl 1125289 root  mem    REG  252,2  2216304   4337 /usr/lib/x86_64-linux-gnu/libc.so.6
setuid-sl 1125289 root  mem    REG  252,2   240936    194 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
setuid-sl 1125289 root    0u   CHR  136,1      0t0      4 /dev/pts/1
setuid-sl 1125289 root    1u   CHR  136,1      0t0      4 /dev/pts/1
setuid-sl 1125289 root    2u   CHR  136,1      0t0      4 /dev/pts/1

感想

  • 細かいプロセスの挙動ではまだまだ知らないことがある
  • /dev/full, /dev/null を open する実装がどこにあるのか気になる

関連エントリ

hiboma.hatenadiary.jp

hiboma.hatenadiary.jp


  1. シェルスクリプトでファイルディスクリプタを閉じる、って全然書いたことがなくて やり方を知らなかった

strace の -k オプションでスタックトレースを出す - 2023 Ubuntu Jammy 版

以前こんなエントリを書いていた

hiboma.hatenadiary.jp

strace で -k を指定すると システムコール呼び出しのスタックトレースを採取できるのを知った。v4.9 から使える experimental 扱いのオプション

という内容のエントリでした。


 

しかしながら

CentOS7.4 の strace-4.12-4.el7 ではサポートされていない機能だ。ざんねーん ちなみに Ubuntu Xenial もだめだー。とほほー

当時、私が業務で扱っていた Linux ディストリビューションではサポートされていなかったのでした。


で、この内容を改めて思い出して、 Ubuntu Jammy で strace -k を試してみたら 動く!

hiboma@vps:~$ strace -k -P /etc/passwd -y id
openat(AT_FDCWD</home/hiboma>, "/etc/passwd", O_RDONLY|O_CLOEXEC) = 3</etc/passwd>
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__open64_nocancel+0x4c) [0x119bcc]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_open+0xd5) [0x8c1e5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_fopen+0x292) [0x8c492]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(fopen+0x7e) [0x7f72e]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__nss_files_fopen+0x12) [0x154e32]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_nss_files_getpwuid_r+0x3e) [0x15ab4e]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid_r+0x11f) [0xe9e0f]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid+0xa3) [0xe9683]
 > /usr/bin/id() [0x621e]
 > /usr/bin/id() [0x2fc5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_init_first+0x90) [0x29d90]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x29e40]
 > /usr/bin/id() [0x32e5]
newfstatat(3</etc/passwd>, "", {st_mode=S_IFREG|0644, st_size=1889, ...}, AT_EMPTY_PATH) = 0
 > /usr/lib/x86_64-linux-gnu/libc.so.6(fstatat+0xe) [0x113eee]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_doallocate+0x63) [0x7ebf3]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_doallocbuf+0x50) [0x8dd60]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_seekoff+0x135) [0x8aa95]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(fseeko+0x63) [0x88d53]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__nss_files_fopen+0x2c) [0x154e4c]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_nss_files_getpwuid_r+0x3e) [0x15ab4e]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid_r+0x11f) [0xe9e0f]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid+0xa3) [0xe9683]
 > /usr/bin/id() [0x621e]
 > /usr/bin/id() [0x2fc5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_init_first+0x90) [0x29d90]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x29e40]
 > /usr/bin/id() [0x32e5]
lseek(3</etc/passwd>, 0, SEEK_SET)      = 0
 > /usr/lib/x86_64-linux-gnu/libc.so.6(llseek+0xb) [0x114acb]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_seekoff+0x22d) [0x8ab8d]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(fseeko+0x63) [0x88d53]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__nss_files_fopen+0x2c) [0x154e4c]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_nss_files_getpwuid_r+0x3e) [0x15ab4e]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid_r+0x11f) [0xe9e0f]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid+0xa3) [0xe9683]
 > /usr/bin/id() [0x621e]
 > /usr/bin/id() [0x2fc5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_init_first+0x90) [0x29d90]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x29e40]
 > /usr/bin/id() [0x32e5]
read(3</etc/passwd>, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1889
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__read_nocancel+0x8) [0x119cd8]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_underflow+0x186) [0x8ccb6]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_default_uflow+0x36) [0x8de16]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_getline_info+0xac) [0x8049c]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(fgets_unlocked+0x45) [0x8a3b5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__nss_readline+0x4b) [0x154ecb]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_nss_files_getpwuid_r+0x82) [0x15ab92]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid_r+0x11f) [0xe9e0f]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid+0xa3) [0xe9683]
 > /usr/bin/id() [0x621e]
 > /usr/bin/id() [0x2fc5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_init_first+0x90) [0x29d90]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x29e40]
 > /usr/bin/id() [0x32e5]
close(3</etc/passwd>)                   = 0
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__close_nocancel+0xb) [0x119a1b]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_file_close_it+0x70) [0x8bf80]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_IO_fclose+0x11f) [0x7ee0f]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(_nss_files_getpwuid_r+0xd5) [0x15abe5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid_r+0x11f) [0xe9e0f]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(getpwuid+0xa3) [0xe9683]
 > /usr/bin/id() [0x621e]
 > /usr/bin/id() [0x2fc5]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_init_first+0x90) [0x29d90]
 > /usr/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x29e40]
 > /usr/bin/id() [0x32e5]
uid=1000(hiboma) gid=1000(hiboma) groups=1000(hiboma),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev)
+++ exited with 0 +++

やったー! すぐにつかえる!

動作環境

hiboma@vps:~$ uname -a
Linux vps 5.15.0-60-generic #66-Ubuntu SMP Fri Jan 20 14:29:49 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
hiboma@vps:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04 LTS
Release:    22.04
Codename:   jammy
hiboma@vps:~$ 

感想

  • 見慣れないオプションがたくさんあるから もうちょい調べてみたい
  • 最近は strace 使ってあれこれ調べるって機会、減ったなぁ

Linux: /dev/full と カーネルのソースリーディング #3分で

注) /dev/null じゃなくて /dev/full に関するエントリです。

/dev/full は何ですか?

write(2) すると必ず ENOSPC を返すキャラクタデバイスです。

$ echo hello > /dev/full 
-bash: echo: write error: No space left on device

「そういえば、こんなキャラクタデバイスあったな〜」と思って、Linux カーネルのソースを読み直しました

ChatGPT に聞いてソースを調べる

grepGNU Global でシュっと見つからないので、slack-gptカーネルのソースがどこかと聞いたら一発で正解を出してくれた

こちらが slack-gpt が教えてくれた URL です

github.com

/dev/full のソース

/dev/full の write を処理するコードは write_full でした。

static const struct file_operations full_fops = {
    .llseek     = full_lseek,
    .read_iter  = read_iter_zero,
    .write      = write_full, 🤏

};

必ず -ENOSPC をかえす実装になっています。おもしろいですね

static ssize_t write_full(struct file *file, const char __user *buf,
              size_t count, loff_t *ppos)
{
    return -ENOSPC; 🤏
}

なお、/dev/full デバイスの定義は下記の通り。デバイスの初期化コードは長くなりそうなので スキップ

static const struct memdev {
    const char *name;
    umode_t mode;
    const struct file_operations *fops;
    fmode_t fmode;
} devlist[] = {
#ifdef CONFIG_DEVMEM
     [DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
#endif
     [3] = { "null", 0666, &null_fops, FMODE_NOWAIT },
#ifdef CONFIG_DEVPORT
     [4] = { "port", 0, &port_fops, 0 },
#endif
     [5] = { "zero", 0666, &zero_fops, FMODE_NOWAIT },
     [7] = { "full", 0666, &full_fops, 0 }, 🤏
     [8] = { "random", 0666, &random_fops, FMODE_NOWAIT },
     [9] = { "urandom", 0666, &urandom_fops, FMODE_NOWAIT },
#ifdef CONFIG_PRINTK
    [11] = { "kmsg", 0644, &kmsg_fops, 0 },
#endif
};

感想

  • シンプルな実装で面白い。自分でも作れそう
  • 「ソース読むか ... でもどこだろう ...? 」と迷子になったが、ChatGPT のガイドでたどり着けた。

参考

💡 slack-gpt は同僚の P山さんが開発している ChatGPT Slack ボットです

github.com

twitter.com

setuid したバイナリの strace を取ると /etc/suid-debug を access(2) でみている - LD_DEBUG の制御に使うファイルだった

Linux で setuid したバイナリで検証作業している時に知った /edtc/suid-debug について調べた内容です。

なぜ こんなことを調べているのですか?

まず、setuid-sleep という setuid したバイナリがあリます。これは sleep するだけの setuid 検証用のバイナリです。

$ ls -hal setuid-sleep                                                                                                                                                                               
-rwsr-xr-x 1 root hiboma 16K Jun  6 10:50 setuid-sleep                                                                                                                                                           

$ stat setuid-sleep
  File: setuid-sleep
  Size: 15960           Blocks: 32         IO Block: 4096   regular file
Device: fc02h/64514d    Inode: 135566      Links: 1
Access: (4755/-rwsr-xr-x)  Uid: (    0/    root)   Gid: ( 1000/  hiboma)
Access: 2023-06-06 10:56:50.342504983 +0900
Modify: 2023-06-06 10:50:08.884304931 +0900
Change: 2023-06-06 10:56:46.206522908 +0900
 Birth: 2023-06-06 10:50:08.872304965 +0900

# 環境は Ubuntu Jammy です
$ uname -a
Linux vps 5.15.0-60-generic #66-Ubuntu SMP Fri Jan 20 14:29:49 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

strace をとると access(2) で /etc/suid-debug の有無を確認しているのを発見しました。

$ strace -f ./setuid-sleep
execve("./setuid-sleep", ["./setuid-sleep"], 0x7ffc7af04528 /* 23 vars */) = 0
🔥 access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)
brk(NULL)                               = 0x55653bde3000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd013de010) = -1 EINVAL (Invalid argument)
fcntl(0, F_GETFD)                       = 0
fcntl(1, F_GETFD)                       = 0
fcntl(2, F_GETFD)                       = 0
🔥 access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)

おっと /etc/suid-debug ファイルはなんだろう? 🤔 ... となって調べた次第です。

調べてみた

Google で調べて man にたどりつきました。

ld-linux.so(8) — manpages — Debian testing — Debian Manpages

Since glibc 2.3.4, LD_DEBUG is ignored in secure-execution mode, unless the file /etc/suid-debug exists (the content of the file is irrelevant).

  • setuid していると LD_DEBUG が無視される ( secure-execution mode )
  • /etc/suid-debug があれば、LD_DEBUG が有効なままになる

ということらしいです。

LD_DEBUG とは?

LD_DEBUG については下記の説明を引用します

LD_DEBUG

(glibc 2.1 以降) 動的リンカーの詳細なデバッグ情報を出力する。 all に設定した場合、全ての動的リンカーが持つデバッグ情報を表示する。 help に設定した場合、この環境変数で指定されるカテゴリーのヘルプ情報を表示する。 glibc 2.3.4 以降、 set-user-ID/set-group-ID されたバイナリでは LD_DEBUG は無視される。

実験: /etc/suid-debug の有無で LD_DEBUG のふるまいを観察する

/etc/suid-debug がないと何もでないですね

$ LD_DEBUG=symbols ./setuid-sleep 

次に、 /etc/suid-debug を touch(3) で作成して、再度実行します。するとデバッグのログがたくさん出てきた!

$ sudo touch  /etc/suid-debug 
$ LD_DEBUG=symbols ./setuid-sleep
    963912:     symbol=__vdso_clock_gettime;  lookup in file=linux-vdso.so.1 [0]
    963912:     symbol=__vdso_gettimeofday;  lookup in file=linux-vdso.so.1 [0]
    963912:     symbol=__vdso_time;  lookup in file=linux-vdso.so.1 [0]
    963912:     symbol=__vdso_getcpu;  lookup in file=linux-vdso.so.1 [0]
    963912:     symbol=__vdso_clock_getres;  lookup in file=linux-vdso.so.1 [0]
    963912:     symbol=_res;  lookup in file=./setuid-sleep [0]
    963912:     symbol=_res;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
    963912:     symbol=svc_max_pollfd;  lookup in file=./setuid-sleep [0]
    963912:     symbol=svc_max_pollfd;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
    963912:     symbol=obstack_alloc_failed_handler;  lookup in file=./setuid-sleep [0]
    963912:     symbol=obstack_alloc_failed_handler;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
    963912:     symbol=__ctype_toupper;  lookup in file=./setuid-sleep [0]
    963912:     symbol=__ctype_toupper;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
    963912:     symbol=loc1;  lookup in file=./setuid-sleep [0]
    963912:     symbol=loc1;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
    963912:     symbol=_dl_argv;  lookup in file=./setuid-sleep [0]
    963912:     symbol=_dl_argv;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
    963912:     symbol=_dl_argv;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]

... 略

感想

  • strace してると「あれ なんだこれ? 」って発見がある
    • もともと調べたいことではなくて、脇道にそれてしまう 🌝

参考

LD_DEBUG で指定できるオプションは下記の通りです。

LD_DEBUG (since glibc 2.1)

Output verbose debugging information about operation of the dynamic linker. The content of this variable is one of more of the following categories, separated by colons, commas, or (if the value is quoted) spaces:

help
    Specifying help in the value of this variable does not run the specified program, and displays a help message about which categories can be specified in this environment variable.

all
    Print all debugging information (except statistics and unused; see below).

bindings
  Display information about which definition each symbol is bound to.

files
    Display progress for input file.

libs
    Display library search paths.

reloc
    Display relocation processing.

scopes
    Display scope information.

statistics
    Display relocation statistics.

symbols
    Display search paths for each symbol look-up.

unused
    Determine unused DSOs.

versions
    Display version dependencies.

Since glibc 2.3.4, LD_DEBUG is ignored in secure-execution mode, unless the file /etc/suid-debug exists (the content of the file is irrelevant).
`

deb パッケージ がどんな configure オプションでビルドされたかを調べる

hiboma.hatenadiary.jp

このエントリの続きです。 deb パッケージの configure オプションはどうやって確かめるんだったかな? と調べた次第

環境

Ubuntu jammy の docker で作業した

1. deb の source パッケージを取得、ファイルシステムで展開する

いろいろ調べたところ apt source で source パッケージをダウンロードできると知りました。

apt source を使うには /etc/apt/sources.list で deb-src の URL を記述する必要があります。ftp.riken.jp のミラーをお借りします。

deb-src http://ftp.riken.jp/Linux/ubuntu/ jammy-updates main restricted universe multiverse
deb-src http://ftp.riken.jp/Linux/ubuntu/ jammy-security main restricted universe multiverse
deb-src http://ftp.riken.jp/Linux/ubuntu/ jammy-backports main restricted universe multiverse
deb-src http://ftp.riken.jp/Linux/ubuntu/ jammy partner

curl で試してみます

root@7073a24a73ad:/workspace# apt source curl
Reading package lists... Done
NOTICE: 'curl' packaging is maintained in the 'Git' version control system at:
https://salsa.debian.org/debian/curl.git
Please use:
git clone https://salsa.debian.org/debian/curl.git
to retrieve the latest (possibly unreleased) updates to the package.
Need to get 4257 kB of source archives.
Get:1 http://ftp.riken.jp/Linux/ubuntu jammy-updates/main curl 7.81.0-1ubuntu1.10 (dsc) [3143 B]
Get:2 http://ftp.riken.jp/Linux/ubuntu jammy-updates/main curl 7.81.0-1ubuntu1.10 (tar) [4188 kB]
Get:3 http://ftp.riken.jp/Linux/ubuntu jammy-updates/main curl 7.81.0-1ubuntu1.10 (asc) [488 B]
Get:4 http://ftp.riken.jp/Linux/ubuntu jammy-updates/main curl 7.81.0-1ubuntu1.10 (diff) [65.2 kB]
Fetched 4257 kB in 1s (4613 kB/s)
dpkg-source: info: extracting curl in curl-7.81.0
dpkg-source: info: unpacking curl_7.81.0.orig.tar.gz
dpkg-source: info: unpacking curl_7.81.0-1ubuntu1.10.debian.tar.xz
dpkg-source: info: using patch list from debian/patches/series
dpkg-source: info: applying 04_workaround_as_needed_bug.patch
dpkg-source: info: applying 06_always-disable-valgrind.patch
dpkg-source: info: applying 08_enable-zsh.patch
dpkg-source: info: applying 11_omit-directories-from-config.patch
dpkg-source: info: applying 13_fix-man-formatting.patch
dpkg-source: info: applying CVE-2022-22576.patch
dpkg-source: info: applying CVE-2022-27774-1.patch
dpkg-source: info: applying CVE-2022-27774-2.patch
dpkg-source: info: applying CVE-2022-27774-3.patch
dpkg-source: info: applying CVE-2022-27775.patch
dpkg-source: info: applying CVE-2022-27776.patch
dpkg-source: info: applying CVE-2022-27780.patch
dpkg-source: info: applying CVE-2022-27781.patch
dpkg-source: info: applying CVE-2022-27782.patch
dpkg-source: info: applying CVE-2022-32205.patch
dpkg-source: info: applying CVE-2022-32206.patch
dpkg-source: info: applying CVE-2022-32207.patch
dpkg-source: info: applying CVE-2022-32208.patch
dpkg-source: info: applying CVE-2022-35252.patch
dpkg-source: info: applying CVE-2022-32221.patch
dpkg-source: info: applying CVE-2022-42915.patch
dpkg-source: info: applying CVE-2022-42916.patch
dpkg-source: info: applying CVE-2022-43551.patch
dpkg-source: info: applying CVE-2022-43552.patch
dpkg-source: info: applying CVE-2023-23914_5-1.patch
dpkg-source: info: applying CVE-2023-23914_5-2.patch
dpkg-source: info: applying CVE-2023-23914_5-3.patch
dpkg-source: info: applying CVE-2023-23914_5-4.patch
dpkg-source: info: applying CVE-2023-23914_5-5.patch
dpkg-source: info: applying CVE-2023-23916-pre1.patch
dpkg-source: info: applying CVE-2023-23916.patch
dpkg-source: info: applying CVE-2023-27533.patch
dpkg-source: info: applying CVE-2023-27534-pre1.patch
dpkg-source: info: applying CVE-2023-27534.patch
dpkg-source: info: applying CVE-2023-27538.patch
dpkg-source: info: applying CVE-2023-27535-pre1.patch
dpkg-source: info: applying CVE-2023-27536.patch
dpkg-source: info: applying CVE-2023-27535.patch
dpkg-source: info: applying 90_gnutls.patch
dpkg-source: info: applying 99_nss.patch

2. debian/rules をみる

展開されたディレクトリの debian/rules に configure 設定が書いてあります

root@7073a24a73ad:/workspace# ls -hal curl-7.81.0/debian/rules 
-rwxr-xr-x 1 root root 5.1K Jan  5  2022 curl-7.81.0/debian/rules

curl-7.81.0/debian/rules の中身

CONFIGURE_ARGS = -- --disable-dependency-tracking        \
    --disable-symbol-hiding --enable-versioned-symbols  \
    --enable-threaded-resolver --with-lber-lib=lber     \
    --with-gssapi=/usr --with-nghttp2   \
    --includedir=/usr/include/$(DEB_HOST_MULTIARCH)     \
    --with-zsh-functions-dir=/usr/share/zsh/vendor-completions

# disable libssh2 on Ubuntu (see #888449)
ifeq ($(shell dpkg-vendor --derives-from Ubuntu && echo yes),yes)
    CONFIGURE_ARGS += --with-libssh --without-libssh2
else
    CONFIGURE_ARGS += --without-libssh --with-libssh2
endif

%:
    dh $@

override_dh_auto_configure:
    mkdir -p debian/build debian/build-gnutls debian/build-nss
    # pop the last patch (nss)
    quilt pop
    # pop the second last patch (gnutls)
    quilt pop
    # get the source without nss and gnutls patches
    tar -cf - --exclude=debian/build* --exclude=.pc . \
        | tar -xf - -C debian/build
    # push the second last patch which must be gnutls
    quilt push
    # get the source with gnutls patch applied
    tar -cf - --exclude=debian/build* --exclude=.pc . \
        | tar -xf - -C debian/build-gnutls
    # push the last patch which must be nss
    quilt push
    # get the source with nss patch applied
    tar -cf - --exclude=debian/build* --exclude=.pc . \
        | tar -xf - -C debian/build-nss
    # run buildconf and make sure to copy the patched ltmain.sh
    for flavour in build build-gnutls build-nss; do \
        (cd debian/$$flavour && ./buildconf && cp ../../ltmain.sh .) \
    done
    cd debian/build && dh_auto_configure ${CONFIGURE_ARGS} --with-openssl \
        --with-ca-path=/etc/ssl/certs \
        --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt
    cd debian/build-gnutls &&  dh_auto_configure ${CONFIGURE_ARGS} --with-gnutls  \
        --with-ca-path=/etc/ssl/certs               \
        --without-ssl --with-gnutls
    cd debian/build-nss && dh_auto_configure ${CONFIGURE_ARGS} --with-nss \
        --without-ssl --with-nss

感想

  • deb パッケージを自前でビルドするのは あんまりやったことが無くて 知識がない
  • override_dh_auto_configure がよくわからない。後で調べる
  • deb-src のミラーを参照せずに、任意の URL から source パッケージをもってきて調べる方法? 後で調べる

参考

RPM がどんな configure オプションでビルドされたかを調べる

とある RPM パッケージの configure を調べたい用事があったので、手順をエントリとして書き起こします。

環境

  • CentOS7 の docker で作業した

1. SRPMファイルシステムで展開する

今回は対象の SRPMrpm で直接 GET して展開します。vault.centos.org の SRPM を使います。

# rpm -ivh https://vault.centos.org/7.9.2009/updates/Source/SPackages/curl-7.29.0-59.el7_9.1.src.rpm

~/rpmbuild/SPECS に spec ファイルが展開されます。

# ls -hal ~/rpmbuild/SPECS/curl.spec 
-rw-rw-r-- 1 root root 58K Nov 16  2020 /root/rpmbuild/SPECS/curl.spec

spec ファイルの %configure を確かめます

%configure --disable-static \
    --enable-hidden-symbols \
    --enable-ipv6 \
    --enable-ldaps \
    --enable-manual \
    --enable-threaded-resolver \
    --with-ca-bundle=%{_sysconfdir}/pki/tls/certs/ca-bundle.crt \
    --with-gssapi${KRB5_PREFIX} \
    --with-libidn \
    --with-libssh2 \
    --without-ssl --with-nss

これで終わりです

感想

  • 久々に SRPM を調べる機会があったので思い出しつつ書き留めた
  • 簡単な手順ではあるけど、知らないと調べるのもひと手間かかりますよね
  • 会社の同僚で知らん人もおるだろうから 書いておこうという気分

TechFeed Experts Night#19 - トラブルシューティングから Linux カーネルに潜り込む の発表をしました

techfeed.io

トラブルシューティングから Linux カーネルに潜り込む をタイトルに発表をしました

speakerdeck.com

Linux カーネルのコードを読む動機は人によって様々と思いますが、私の場合はトラブルシューティングが大きく占めている感じです。

今回の発表は

を LT してみました。

持ち時間が短かったので 問題をどう調査していったかまでは全然説明できていないです。また別の機会にどこかで取り上げられたらいいかなと思っています。

謝辞

イベントの開催・運営・登壇の機会をご提供いただいた 株式会社テックフィード様 ありがとうございました!

また、登壇を推薦していただいた TenForward さん (id:defiant さん) ありがとうございました! ( 社外で発表しないとな〜と思っていたところでお声がけいただいてタイミングもバッチリでした )

sat さん、udzura さんも発表者として ご一緒できてよかったです。 いろんな角度で Linux カーネルの話を聞けてよいイベントでしたね。

補足: スライドで参照しているリンクや過去の発表資料

sysfs のリークについてまとめたスライド

speakerdeck.com

TCP OOM についてまとめたテックブログ

tech.pepabo.com

IBRS の不具合で Red Hat が出したセキュリティアドバイザリ

access.redhat.com