Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
open()の実装を読んでみる
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
happynote3966
November 10, 2018
Technology
920
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
open()の実装を読んでみる
Kernel/VM探検隊@北陸 part4で発表した資料です
happynote3966
November 10, 2018
More Decks by happynote3966
See All by happynote3966
QEMUを用いた自動バイナリ防御機構の開発_公開版.pdf
happynote3966
6
4.1k
CWEから学ぶ脆弱性
happynote3966
3
1.6k
Other Decks in Technology
See All in Technology
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
5
25k
HHKBエバンジェリストになる方法
941
0
100
「守り」で活用するオンデバイスLLM 〜写ってはいけないを総力戦で防ぐ〜 / iOSDC Japan 2026
nakamuuu
0
160
MCPをつなげて作る組織横断のAIエージェント基盤(の開発工程)
tsubakimoto_s
0
130
Minecraft JavaのMODをSwiftで作る
1mash0
0
160
GoにおけるFFIのこれまでとこれから
goccy
5
3.4k
おい、エージェントを使って終わらせろ
nwiizo
0
250
登壇の自信を奪う3匹のオバケ / 3 Ghosts That Rob You of Your Confidence in Public Speaking
pauli
8
930
バイブコーディング時代のWebアプリ開発入門~Cloud Runで学ぶセキュアなビルドとデプロイ
waiwai2111
1
130
AIを活用するために決めた "やらないこと" - 価値に注目する / Not betting on AI
soudai
PRO
1
520
What the customer really needed
kawaguti
PRO
2
170
今話題のAI「Jev」って何? 宇宙最速で学ぶ会
minorun365
PRO
21
13k
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
280
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.8k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
570
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
720
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
42k
Bash Introduction
62gerente
615
220k
We Have a Design System, Now What?
morganepeng
55
8.3k
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
230
Writing Fast Ruby
sferik
630
63k
Believing is Seeing
oripsolob
1
220
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
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!