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
890
open()の実装を読んでみる
Kernel/VM探検隊@北陸 part4で発表した資料です
happynote3966
November 10, 2018
Tweet
Share
More Decks by happynote3966
See All by happynote3966
QEMUを用いた自動バイナリ防御機構の開発_公開版.pdf
happynote3966
6
3.9k
CWEから学ぶ脆弱性
happynote3966
3
1.5k
Other Decks in Technology
See All in Technology
モノタロウ x クリエーションラインで実現する チームトポロジーにおける プラットフォームチーム・ ストリームアラインドチームの 効果的なコラボレーション
creationline
0
470
RALGO : AIを組織に組み込む方法 -アルゴリズム中心組織設計- #RSGT2026 / RALGO: How to Integrate AI into an Organization – Algorithm-Centric Organizational Design
kyonmm
PRO
3
780
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
2.9k
AI: The stuff that nobody shows you
jnunemaker
PRO
1
160
Keynoteから見るAWSの頭の中
nrinetcom
PRO
1
160
『君の名は』と聞く君の名は。 / Your name, you who asks for mine.
nttcom
1
150
Contract One Engineering Unit 紹介資料
sansan33
PRO
0
12k
[PR] はじめてのデジタルアイデンティティという本を書きました
ritou
0
770
ハッカソンから社内プロダクトへ AIエージェント ko☆shi 開発で学んだ4つの重要要素
leveragestech
0
560
2025年の医用画像AI/AI×medical_imaging_in_2025_generated_by_AI
tdys13
0
310
旬のブリと旬の技術で楽しむ AI エージェント設計開発レシピ
chack411
1
110
テストセンター受験、オンライン受験、どっちなんだい?
yama3133
0
200
Featured
See All Featured
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
58
41k
It's Worth the Effort
3n
187
29k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
190
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
180
Bash Introduction
62gerente
615
210k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.1k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
120
BBQ
matthewcrist
89
9.9k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
34k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
94
How to train your dragon (web standard)
notwaldorf
97
6.5k
Making Projects Easy
brettharned
120
6.5k
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!