Follow the outline of the open syscall
Invocation of open
Internal translation to main handler
Manipulating the file descriptor table
Thoughts?
Get a handle to an inode
inode
Create entry in the file descriptor table
Invoke underlying filesystem-specific code
struct files_struct
->files in task_struct
Resolve a path
Perform validation
Create entry in file descriptor table
SYSCALL_DEFINE3(open,...
openat(2) is preferred
openat(2)
force_o_largefile()
Do we have ARCH_32_BIT_OFF_T?
ARCH_32_BIT_OFF_T
strace ./twinkle_twinkle
open becomes openat
open
openat
SYSCALL_CANCEL()
list of syscalls
AT_FDCWD
struct open_how
Built from int flags and umode_t mode
int flags
umode_t mode
For openat, done in do_sys_open()
do_sys_open()
Added in fddb5d430ad9f ("open: introduce openat2(2) syscall")
openat didn't check for unknown flags
flags
Extending with new features troublesome
Follow symlinks in each component of patch
By default, follow for last component, unless O_NOFOLLOW
O_NOFOLLOW
O_PATH
RESOLVE_BENEATH: all resolutions in subtree
RESOLVE_BENEATH
RESOLVE_NO_ROOT: can't cross into another mount namespace
RESOLVE_NO_ROOT
RESOLVE_NO_SYMLINKS: Like O_NOFOLLOW for whole path resolution process
RESOLVE_NO_SYMLINKS
Like O_NOFOLLOW
build_open_how()
Invalid flags quietly discarded
openat2 would -EINVAL with bad flags
-EINVAL
S_IALLUGO: permission bits
S_IALLUGO
permission bits
read, write, exec for user, group, and other
build_open_flags()
struct open_how => struct open_flags
struct open_flags
getname called => getname_flags
Like a copy_from_user for filenames
copy_from_user
allocates memory, performs validation
namei: name-to-inode
What the heck is "omirr"
Important enough for fundamental changes to pathname lookup
In and out of the kernel
SYSCALL_DEFINE0(fork)
kernel_clone() calls copy_process()
kernel_clone()
copy_process()
copy_process() calls copy_files()
copy_files()
dup_fd()
alloc_fdtable()
get_unused_fd_flags()
do_filp_open()
Relies on path_openat()
path_openat()
Finally: do_open()
do_open()
vfs_open()
Uses struct dentry in struct path
struct dentry
struct path
dentry: cache directory entry items: inode+path
call to fops_get
call to fops->open()
fd_install()
sudo bpftrace -e 'k:kkey_open { printf("%s\n", kstack); }'
Open resolves a path into an inode
An open file descriptor refers to a struct file in the current->files structure
struct file
current->files
The newer openat2 provides useful symlink resolution options
openat2
Everything is a file descriptor in Linux, and open is the first step