git bisectを用いてsyscallテーブルの表記変更コミットを探す
linuxにシステムコールを追加しようと思ったりすると、
arch/x86/entry/syscalls/syscall_64.tbl
にsys*と書くと思っていたのですが、最近は__x64_sys*という表記に変わっていることに気づきました。
例えばLinux v4.15ではシステムコールテーブルは以下の様になっています。
# 64-bit system call numbers and entry vectors # # The format is: # <number> <abi> <name> <entry point> # # The abi is "common", "64" or "x32" for this file. # 0 common read sys_read 1 common write sys_write 2 common open sys_open 3 common close sys_close 4 common stat sys_newstat 5 common fstat sys_newfstat 6 common lstat sys_newlstat 7 common poll sys_poll 8 common lseek sys_lseek 9 common mmap sys_mmap 10 common mprotect sys_mprotect
ただ最近(v5.0)このテーブルを見直したら以下のように変更されていました。
# # 64-bit system call numbers and entry vectors # # The format is: # <number> <abi> <name> <entry point> # # The __x64_sys_*() stubs are created on-the-fly for sys_*() system calls # # The abi is "common", "64" or "x32" for this file. # 0 common read __x64_sys_read 1 common write __x64_sys_write 2 common open __x64_sys_open 3 common close __x64_sys_close 4 common stat __x64_sys_newstat 5 common fstat __x64_sys_newfstat 6 common lstat __x64_sys_newlstat 7 common poll __x64_sys_poll 8 common lseek __x64_sys_lseek 9 common mmap __x64_sys_mmap 10 common mprotect __x64_sys_mprotect
git bisect というコマンドを思い出し、良い練習問題だと思って調べてみることにしました。
manのドキュメントの言葉を借りると、git bisectは
git-bisect - Use binary search to find the commit that introduced a bug
すなわち、ある段階まで動いていたコードにどの段階でバグが入り込んだかを調べる機能です。
テストスクリプトを走らせて*12分探索で該当コミットを探してくれるので、一つずつさかのぼって確認するのと比べ、高速で探索が可能です。
今回はバグではありませんが、以下のテストスクリプト(test.sh)を使い、__x64という表記が混入する場所を探ることにしました。
#!/bin/sh set -eu egrep "\ssys_open" arch/x86/entry/syscalls/syscall_64.tbl
git bisect ではまず、該当コミットがある範囲を決めます。
git bisect run <bad/new-commit> <good/old-commit>
今回、v5.0ではx64_sys*という表記となり、v4.15ではsys*という表記であることがわかっているので、以下のように実行しました。
git bisect start v5.0 v4.15 Bisecting: 44096 revisions left to test after this (roughly 16 steps) [93b9bcdf9fbcb683d4e8c44ee8cec0989053d4de] btrfs: remove unused parameter from btrfs_parse_subvol_options
「だいたい16ステップで終わるよ」と教えてくれるのは便利。
次に、実際に探索を行いたいと思います。
git bisect run ./test.sh
running ./test.sh
Bisecting: 22106 revisions left to test after this (roughly 15 steps)
[38047d5c269bbdedf900fc86954913f3dffa01f1] Merge tag 'driver-core-4.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 10700 revisions left to test after this (roughly 14 steps)
[135c5504a600ff9b06e321694fbcac78a9530cd4] Merge tag 'drm-next-2018-06-06-1' of git://anongit.freedesktop.org/drm/drm
running ./test.sh
Bisecting: 5696 revisions left to test after this (roughly 13 steps)
[a72db42cee37a43f8a40e1f47358ac86921ad8e4] Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
running ./test.sh
Bisecting: 2942 revisions left to test after this (roughly 12 steps)
[28da7be5ebc096ada5e6bc526c623bdd8c47800a] Merge tag 'mailbox-v4.17' of git://git.linaro.org/landing-teams/working/fujitsu/integration
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 1471 revisions left to test after this (roughly 11 steps)
[5504ed29692faad06ea74c4275e96a8ffc83a1e1] mm/hmm: do not differentiate between empty entry or missing directory
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 733 revisions left to test after this (roughly 10 steps)
[80a17a5f501ea048d86f81d629c94062b76610d4] Merge tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 373 revisions left to test after this (roughly 9 steps)
[ba2b137d10bafc3cc514e52172b549e64a5402fb] Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 193 revisions left to test after this (roughly 8 steps)
[f0d98d85831bf1a3b1f56f8c14af60797aaca536] Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
running ./test.sh
Bisecting: 71 revisions left to test after this (roughly 7 steps)
[174e719439b8224d7cedfbdd9529de396cac01ff] Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 30 revisions left to test after this (roughly 5 steps)
[9fb71c2f230df44bdd237e9a4457849a3909017d] Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
running ./test.sh
Bisecting: 18 revisions left to test after this (roughly 4 steps)
[6b0a02e86c293c32a50d49b33a1f04420585d40b] Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 9 revisions left to test after this (roughly 3 steps)
[5ac9efa3c50d7caff9f3933bb8a3ad1139d92d92] syscalls/core, syscalls/x86: Clean up compat syscall stub naming convention
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[d94a155c59c98c19b98ee949eaab6a0312bbd6be] x86/cpu: Prevent cpuinfo_x86::x86_phys_bits adjustment corruption
running ./test.sh
2 common open sys_open
257 common openat sys_openat
304 common open_by_handle_at sys_open_by_handle_at
Bisecting: 2 revisions left to test after this (roughly 1 step)
[c76fc98260751e71c884dc1a18a07e427ef033b5] syscalls/x86: Adapt syscall_wrapper.h to the new syscall stub naming convention
running ./test.sh
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[d5a00528b58cdb2c71206e18bd021e34c4eab878] syscalls/core, syscalls/x86: Rename struct pt_regs-based sys_*() to __x64_sys_*()
running ./test.sh
d5a00528b58cdb2c71206e18bd021e34c4eab878 is the first bad commit
commit d5a00528b58cdb2c71206e18bd021e34c4eab878
Author: Dominik Brodowski <linux@dominikbrodowski.net>
Date: Mon Apr 9 12:51:44 2018 +0200
syscalls/core, syscalls/x86: Rename struct pt_regs-based sys_*() to __x64_sys_*()
This rename allows us to have a coherent syscall stub naming convention on
64-bit x86 (0xffffffff prefix removed):
810f0af0 t kernel_waitid # common (32/64) kernel helper
<inline> __do_sys_waitid # inlined helper doing actual work
810f0be0 t __se_sys_waitid # C func calling inlined helper
<inline> __do_compat_sys_waitid # inlined helper doing actual work
810f0d80 t __se_compat_sys_waitid # compat C func calling inlined helper
810f2080 T __x64_sys_waitid # x64 64-bit-ptregs -> C stub
810f20b0 T __ia32_sys_waitid # ia32 32-bit-ptregs -> C stub[*]
810f2470 T __ia32_compat_sys_waitid # ia32 32-bit-ptregs -> compat C stub
810f2490 T __x32_compat_sys_waitid # x32 64-bit-ptregs -> compat C stub
[*] This stub is unused, as the syscall table links
__ia32_compat_sys_waitid instead of __ia32_sys_waitid as we need
a compat variant here.
Suggested-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20180409105145.5364-4-linux@dominikbrodowski.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
:040000 040000 3f963b85ebd00a03e36f36f6417684a64da0b8dc e83d401c538f34cb271d6c0ae3c8563f43db6a5f M arch
bisect run success
うまく行きました。
これで、ちょうど”バグ”が入り込んだコミット。 すなわちここでは_x64_sys*という表記に変わったコミットにチェックアウトした状態となっています。
git diff HEAD~とすると
前略 -0 common read sys_read -1 common write sys_write -2 common open sys_open -3 common close sys_close -4 common stat sys_newstat -5 common fstat sys_newfstat 中略 +0 common read __x64_sys_read +1 common write __x64_sys_write +2 common open __x64_sys_open +3 common close __x64_sys_close +4 common stat __x64_sys_newstat +5 common fstat __x64_sys_newfstat 後略
となっていたので、このコミット(d5a00528b58cdb2c71206e18bd021e34c4eab878)で間違いなさそうです。
さて、このコミットがどのバージョンかですが、
git merge-base --is-ancestor v4.16 HEAD に成功して、git merge-base --is-ancestor v4.17 HEADに失敗したのでv4.17から変更が入っていそうです。
おわり