Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
open()の実装を読んでみる
Search
happynote3966
November 10, 2018
Technology
1
850
open()の実装を読んでみる
Kernel/VM探検隊@北陸 part4で発表した資料です
happynote3966
November 10, 2018
Tweet
Share
More Decks by happynote3966
See All by happynote3966
QEMUを用いた自動バイナリ防御機構の開発_公開版.pdf
happynote3966
6
3.7k
CWEから学ぶ脆弱性
happynote3966
3
1.2k
Other Decks in Technology
See All in Technology
帳票構造化タスクにおけるLLMファインチューニングの性能評価
yosukeyoshida
1
230
AWS DDoS攻撃防御の最前線
ryutakondo
0
120
2時間で300+テーブルをデータ基盤に連携するためのAI活用 / FukuokaDataEngineer
sansan_randd
0
130
S3 Glacier のデータを Athena からクエリしようとしたらどうなるのか/try-to-query-s3-glacier-from-athena
emiki
0
180
マルチプロダクト×マルチテナントを支えるモジュラモノリスを中心としたアソビューのアーキテクチャ
disc99
0
310
o11yツールを乗り換えた話
tak0x00
1
240
Jamf Connect ZTNAとMDMで実現! 金融ベンチャーにおける「デバイストラスト」実例と軌跡 / Kyash Device Trust
rela1470
0
150
Oracle Cloud Infrastructure:2025年7月度サービス・アップデート
oracle4engineer
PRO
1
120
AI によるドキュメント処理を加速するためのOCR 結果の永続化と再利用戦略
tomoaki25
0
400
2025新卒研修・HTML/CSS #弁護士ドットコム
bengo4com
3
13k
【CEDEC2025】『Shadowverse: Worlds Beyond』二度目のDCG開発でゲームをリデザインする~遊びやすさと競技性の両立~
cygames
PRO
1
290
LTに影響を受けてテンプレリポジトリを作った話
hol1kgmg
0
290
Featured
See All Featured
Done Done
chrislema
185
16k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
21k
Documentation Writing (for coders)
carmenintech
73
5k
How to train your dragon (web standard)
notwaldorf
96
6.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3.1k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Rails Girls Zürich Keynote
gr2m
95
14k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
870
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
139
34k
Producing Creativity
orderedlist
PRO
346
40k
Fireside Chat
paigeccino
38
3.6k
Transcript
open()の実装を 読んでみる Kernel/VM探検隊@北陸 part4 @happynote3966
$ whoami はっぴーのーと(@happynote3966) どこかの学生 happynote3966.hatenadiary.com 興味のあること:OSとか仮想化とかセキュリティとか SecHack365というイベントでQEMUをイジイジ 2
$ whoami はっぴーのーと(@happynote3966) どこかの学生 happynote3966.hatenadiary.com 興味のあること:OSとか仮想化とかセキュリティとか SecHack365というイベントでQEMUをイジイジ 3
動機 OSの勉強のためにLinuxのソースコードを読んでみようとは誰もが考える →何度か挑んでみてもワケがわからなくなり終了する 「Linuxのコア部分の入り口になるシステムコールなら読みやすいんじゃないか?」 →「じゃあやってみよう!とりあえず open()からやってみるか!」 ユーザーモードアプリケーション ライブラリ システムコール(open) い
ろ い ろ
Linuxのバージョン commit 31130a16d459de809cd1c03eabc9567d094aae6a 4.19-rc1(だと思う)
どこにopen()があるのか?
システムコールの呼び出し場所 fs/open.c内の1074行目
do_sys_open
do_sys_open
呼び出しの前提 int fd = open(“file.txt”,O_RDONLY)
読む時に意識すること likelyマクロとunlikelyマクロを利用する(※) likelyマクロは条件が真になりやすく、unlikelyマクロは条件が偽になりやすい →likelyの部分はなるべく読んで、unlikelyの部分はなるべく読まない errnoの存在を利用する 今回はopen()システムコールが無事に成功することを前提にする →errnoが代入されたりするようなところはなるべく読まない (※)https://qiita.com/kaityo256/items/8a0c5376fad17907e1f6
build_open_flags()周辺を読む
ソースコード
やっていること 開きたいファイルのopen_flags構造体を初期化している 関数自体は0を返すので、呼び出し元の次のif文は実行されない struct open_flags{ int open_flag; umode_t mode; int
acc_mode; int intent; int lookup_flags; }
open_flags open_flag = 0 mode = 0 acc_mode = 004
intent = 0x100 (LOOKUP_OPEN) lookup_flags = 0x001 (LOOKUP_FOLLOW)
tmp = getname(filename)周辺を読む (getname_flags(filename,0,NULL))
ソースコード
やっていること 開きたいファイルの名前に関するfilename構造体を スラブアロケータから取得して初期化している その後、初期化したfilename構造体へのポインタを返す struct filename{ const char *name; const
__user char *uptr int refcnt; struct audit_names *aname; const char iname[]; }
open_flags open_flag = 0 mode = 0 acc_mode = 004
intent = 0x100 (LOOKUP_OPEN) lookup_flags = 0x001 (LOOKUP_FOLLOW) filename name = iname uptr = “file.txt”(userland) refcnt = 1 aname = NULL iname[] = “file.txt”
fd = get_unused_fd_flags(flags)周辺を読む (__alloc_fd(current->files,0,rlimit(RLIMIT_NOFILE),flags))
ソースコード
やっていること 開きたいファイルのファイルディスクリプタを割り当ててもらう 今割り当てられているファイルディスクリプタの中から空いているものを選ぶ (今回だと3になる) struct fdtable{ unsigned int max_fds; struct
file __rcu **fd; unsigned long *close_on_exec; unsigned long *open_fds; unsigned long *full_fds_bits; struct rcu_head rcu; }
イメージ struct fdtable{ unsigned int max_fds; struct file __rcu **fd;
unsigned long *close_on_exec; unsigned long *open_fds; unsigned long *full_fds_bits; struct rcu_head rcu; } kvmallocで割り当てられた領域 open_fdsの領域 11100000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 close_on_execの領域 full_fds_bitsの領域
do_filp_openを読む
ソースコード
set_nameidata()での処理 パス名の検索処理に関連する構造体であるnameidata構造体を初期化する struct nameidata{ struct path path; struct qstr last;
struct path root; struct inode *inode; unsigned int flags; unsigned seq, m_seq; int last_type; unsigned depth; int total_link_count; struct saved { struct path link; struct delayed_call done; const char *name; unsigned seq; } *stack, internal[EMBEDDED_LEVELS]; struct filename *name; struct nameidata *saved; struct inode *link_inode; unsigned root_seq; int dtf; }
open_flags open_flag = 0 mode = 0 acc_mode = 004
intent = 0x100 (LOOKUP_OPEN) lookup_flags = 0x001 (LOOKUP_FOLLOW) filename name = iname uptr = “file.txt”(userland) refcnt = 1 aname = NULL iname[] = “file.txt” nameidata path last root inode flags seq m_seq last_type depth total_link_count = old->total_link_count; stack internal[EMBEDDED_LEVELS] name saved = current->nameidata link_inode root_seq dfd = AT_FDCWD
path_openat()
alloc_empty_file()での処理 オープンされているファイルとプロセスとのやり取りに関する file構造体を作成している struct file{ union { struct llist_node fu_llist;
struct rcu_head fu_rcuhead; }f_u; struct path fpath; struct inode *f_inode; const struct file_operations *f_op; spinlock_t f_lock; enum rw_hint f_write_hint; atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; struct mutex f_pos_lock; loff_t f_pos; struct fown_struct f_owner; const struct cred *f_cred; struct file_ra_state f_ra; u64 f_verson; void *f_security; void *private_data; struct list_head f_ep_links; struct list_head f_tfile_lliink; struct address_space *f_mapping; errseq_t f_wb_err; }
open_flags open_flag = 0 mode = 0 acc_mode = 004
intent = 0x100 (LOOKUP_OPEN) lookup_flags = 0x001 (LOOKUP_FOLLOW) filename name = iname uptr = “file.txt”(userland) refcnt = 1 aname = NULL iname[] = “file.txt” nameidata path last root inode flags seq m_seq last_type depth total_link_count = old->total_link_count; stack internal[EMBEDDED_LEVELS] name saved = current->nameidata link_inode root_seq dfd = AT_FDCWD file f_u; fpath; f_inode; f_op; f_lock; f_write_hint; f_count = 1 f_flags = 0 f_mode = 1(FMODE_READ) f_pos_lock; f_pos; f_owner; f_cred = current->cred f_ra; f_verson; f_security; private_data; f_ep_links; f_tfile_lliink; f_mapping; f_wb_err;
path_init(一部省略)
open_flags open_flag = 0 mode = 0 acc_mode = 004
intent = 0x100 (LOOKUP_OPEN) lookup_flags = 0x001 (LOOKUP_FOLLOW) filename name = iname uptr = “file.txt”(userland) refcnt = 1 aname = NULL iname[] = “file.txt” nameidata path = current->fs->pwd last = (.hash_len = hash_len,.name = ) root inode = flags = LOOKUP_FOLLOW | LOOKUP_RCU | LOOKUP_PARENT seq m_seq last_type = LAST_NORM depth = 0 total_link_count = old->total_link_count; stack internal[EMBEDDED_LEVELS] name saved = current->nameidata link_inode root_seq dfd = AT_FDCWD file f_u; fpath; f_inode; f_op; f_lock; f_write_hint; f_count = 1 f_flags = 0 f_mode = 1(FMODE_READ) f_pos_lock; f_pos; f_owner; f_cred = current->cred f_ra; f_verson; f_security; private_data; f_ep_links; f_tfile_lliink; f_mapping; f_wb_err; dentry struct inode *d_inode; inode const struct file_operations i_fop; file_operations (ext4_file_operations)
link_path_walk()の処理 dエントリキャッシュのハッシュテーブルを探すために ハッシュ値を計算するらしい (詳しいハッシュの計算などは分からなかった)
do_last()(※抜粋)
vfs_open()
do_dentry_open()(※抜粋)
open_flags open_flag = 0 mode = 0 acc_mode = 004
intent = 0x100 (LOOKUP_OPEN) lookup_flags = 0x001 (LOOKUP_FOLLOW) filename name = iname uptr = “file.txt”(userland) refcnt = 1 aname = NULL iname[] = “file.txt” nameidata path = current->fs->pwd last = (.hash_len = hash_len,.name = ) root inode = flags = LOOKUP_FOLLOW | LOOKUP_RCU | LOOKUP_PARENT seq m_seq last_type = LAST_NORM depth = 0 total_link_count = old->total_link_count; stack internal[EMBEDDED_LEVELS] name saved = current->nameidata link_inode root_seq dfd = AT_FDCWD file f_u; fpath; f_inode; f_op; f_lock; f_write_hint; f_count = 1 f_flags = 0 f_mode = 1(FMODE_READ) f_pos_lock; f_pos; f_owner; f_cred = current->cred f_ra; f_verson; f_security; private_data; f_ep_links; f_tfile_lliink; f_mapping; f_wb_err; dentry struct inode *d_inode; inode const struct file_operations i_fop; file_operations (ext4_file_operations)
file_operations構造体(※抜粋) struct file_operations{ struct module *owner; loff_t (*llseek) (struct file
*,loff_t, int); ssize_t (*read) (struct file *, char __user *,size_t,loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); int (*iterate_shared) (struct file *, struct dir_context *); __poll_t (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file*, struct vm_area_struct *); unsigned long mmap_supported_flags; int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync);
ファイルシステムの確認 ファイルシステムの種類を確認するにはdf -Tコマンドを使う
ext4のfile_operations fs/ext4/inode.cにある
まとめ ①ファイルの権限やモードに関するopen_flags構造体を作成し
まとめ ①ファイルの権限やモードに関するopen_flags構造体を作成し ②ファイルの名前に関するfilename構造体を作成して
まとめ ①ファイルの権限やモードに関するopen_flags構造体を作成し ②ファイルの名前に関するfilename構造体を作成して ③空いているファイルディスクリプタを探して
まとめ ①ファイルの権限やモードに関するopen_flags構造体を作成し ②ファイルの名前に関するfilename構造体を作成して ③空いているファイルディスクリプタを探して ④指定されたファイル名が存在する ファイルシステムに沿ったfile_operationsのopenを実行する
今後の課題や感想 [課題]もっと色んな引数のパターンを想定したソースコードリーディングを行う すごく単純な場合で読んだために「特殊な場合」を読めていない [課題]カーネルデバッグをしながら読むべきだった 実際の値を確認していないからどこか間違っている可能性大
今後の課題や感想 [課題]もっと色んな引数のパターンを想定したソースコードリーディングを行う すごく単純な場合で読んだために「特殊な場合」を読めていない [課題]カーネルデバッグをしながら読むべきだった 実際の値を確認していないからどこか間違っている可能性大 [感想]Linuxの一部を理解するだけでも難しかったのに Linux & 人の気持ちを完全に理解しているLinusはスゴイ
Thank you for your attention!