Tong Zhang
1
, Wenbo Shen
2
, Dongyoon Lee
3
, Changhee Jung
4
,
Ahmed M. Azab
5
, Ruowen Wang
5
1
Virginia Tech,
2
Zhejiang University,
3
Stony Brook University,
4
Purdue University,
5
Samsung Research America, now at Google
PeX: A Permission Check
Analysis Framework for
Linux Kernel
1
2
Permission Control in Linux Is Complex
1. DAC (Discretionary Access Controls)
3. LSM (Linux Security Module)
e.g., SELinux, AppArmor
2. Capabilities
/bin/ping only has cap_net_raw (no more suid, full root)
e.g., drwxr-xr-x for /root
Many permission checks are placed in an ad-hoc manner,
hard to guarantee all of them are placed correctly
38 in Linux Kernel v4.18.5
190 hooks in Linux Kernel v4.18.5
x
3
prctl(“new”);
write(“new”)
SyS_write(“new”)
vfs_write
file->f_op->write
SyS_prctl(“new”)
security_file_permission
set_task_comm(“new”)
comm_write(“new”)
Privileged function
Permission check function
Example: Missing Permission Check is a Problem
Two methods to change a process name
Method 1: Use /proc/pid/comm file
Method 2: Use prctl system call
Goal: design a static analysis tool to find out
permission check bugs
(missing, inconsistent and redundant
permission checks)
bypass
4
prctl(“new”);
write(“new”)
SyS_write(“new”)
vfs_write
file->f_op->write
SyS_prctl(“new”)
security_file_permission
set_task_comm(“new”)
comm_write(“new”)
ICFG
Path Can Be Represented in Interprocedural Control Flow Graph
5
Traverse Interprocedural Control Flow Graph to Find Bugs
Permission Check Function
Privileged Function
Explore ICFG for all user
reachable path to find out bugs
First thing: we need to build an ICFG
Good Path
Bad Path
6
Challenge 1: Indirect Calls Makes Precise ICFG Hard to Build
Kernel frequently uses function pointer to call real driver implementation
115K indirect callsites in Linux Kernel v4.18.5
file->f_op->write_iter
ext4_file_write_iter
btrfs_file_write_iter
cifs_file_write_iter
nfs_file_write
Indirect Call
VFS layer
Network Layer
sk->sk_prot->sendmsg
ipv4 inet_send_msg
ipv6 inet_send_msg
7
ssize_t Write (struct file *, char __user *, size_t , loff_t *)
ssize_t Read (struct file *, char __user *, size_t , loff_t *)
Challenge 1: No Precise and Scalable Solution
Typed based approach (function signature) imprecise
ssize_t __vfs_write(struct file* file,…)
{
file->f_op->write(file, p, count, pos);
}
Advanced pointer analysis: not scalable
They do not scale for Linux kernel (~16 MLoC)
SVF
2
(used by K-Miner
1
,a static tool kernel analysis)
K-Miner: Gens, David, et al. "K-Miner: Uncovering Memory Corruption in Linux." NDSS. 2018.
SVF: Sui, Yulei, and Jingling Xue. "On-demand strong update analysis via value-flow refinement." Proceedings of the 2016 24th ACM
SIGSOFT international symposium on foundations of software engineering. ACM, 2016.
Can be applied to a smaller codebase, which harms soundness
x
8
Challenge 2: Three Other Things We Don’t Know
write(“new”)
SyS_write(“new”)
vfs_write
file->f_op->write
security_file_permission
set_task_comm(“new”)
comm_write(“new”)
Privileged function
Permission check function
Indirect Call
Direct Call
1. which function is permission check function
2. which function is privileged function
3. which permission check function is needed
for a privileged function
9
PeX Workflow
KIRIN
Indirect Call
Pointer Analysis
ICFG
Privileged
Function
Detection
Permission
Check
Wrapper
Detection
Permission
Check Error
Detection
Kernel
Source
(IR)
Challenge 1
Challenge 2
Permission check functions
provided by user
Bug Report
10
KIRIN Observation: Most Indirect Calls(~90%) in Linux Kernel
Use Well Defined Interface
Observation: kernel has well defined interface to connect different component together
Filesystem
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t,
loff_t *);
ssize_t (*write) (struct file *, char __user *, size_t,
loff_t *);
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
}
Network protocol
struct proto_ops {
int (*connect) (struct socket *sock, struct sockaddr
*vaddr, int sockaddr_len, int flags);
int (*listen) (struct socket *sock, int len);
int (*sendmsg) (struct socket *sock, struct msghdr
*m, size_t total_len);
int (*recvmsg) (struct socket *sock, struct msghdr
*m, size_t total_len, int flags);
}
11
KIRIN Step 1: Trace and Collect All Struct Initializations
file_operations proc_pid_set_comm_operations
{
.open = comm_open,
.read = seq_read,
.write = comm_write,
.llseek = seq_lseek,
.release = single_release,
}
KIRIN trace all statically and dynamically initialized struct
.write = ext4_file_write
.write = vfat_file_write
ssize_t __vfs_write(struct file* file,…)
{
file->f_op->write
12
KIRIN Step 2: Match Indirect Call Target Using Interface
struct file_operations {
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, char __user *, size_t, loff_t *);
}
Calling write function in struct file_operations
Possible callee: comm_write
Step 2 analyze the callsite
1.Match Interface
2.Match member
better precision than type-based method
better scalability than SVF because the
analys is simpler
13
PeX Workflow
KIRIN
Indirect Call
Pointer Analysis
ICFG
Privileged
Function
Detection
Permission
Check
Wrapper
Detection
Permission
Check Error
Detection
Kernel
Source
(IR)
Challenge 1
Challenge 2
Permission check
functions
provided by user
Bug Report
14
Dominator Based Privileged Function Detection
write(“new”)
SyS_write(“new”)
vfs_write
file->f_op->write
security_file_permission
set_task_comm(“new”)
comm_write(“new”)
Privileged function call
Permission check function
1. User reachable path, starting from system call
2. A callsite protected by the permission check
- the dominator analysis
3. Mark callee of the privileged function call as
privileged function
bar
foo
x
callsite
15
Traverse ICFG for Permission Check Error Detection
Indirect Call
Direct Call
1. Traverse ICFG for user
reachable path,
starting from system call
2. Find a control flow path
with no permission check
in a backward search
manner
Permission Check Function
Privileged Function
ICFG
Bad Path
x
Implementation and Evaluation
LLVM/Clang-6
16
Generate a single-file vmlinux.bc using wllvm
Evaluation
Linux-v4.18.5
defconfig(2.4M LoC)
allyesconfig(15.9MLoC)
Implementation
17
21 21
6
0
5
10
15
20
25
PeX-KIRIN PeX-TYPE PeX-K-Miner
Number of Bugs Detected
ICFG generated by K-
Miner is not sound, so
it detects less bugs
(Imprecise ICFG) (unsound ICFG)
Detection Capability – defconfig (2.4M LoC), PeX-KIRIN is Better
18
Detection Capability – defconfig (2.4M LoC), PeX-KIRIN is Better
72
210
853
218
348
1319
54
196
231
0
200
400
600
800
1000
1200
1400
DAC CAP LSM
Number of Warnings
PeX-KIRIN PeX-TYPE PeX-K-Miner
2. ICFG generated by K-Miner-SVF is unsound, so it generates less warnings
1. ICFG generated by KIRIN is more precise than type approach, so it generates less warnings
Conclusions
PeX: a static permission check analysis framework for Linux kernel
KIRIN: kernel call graph analysis
Permission check functions/Privileged functions and their mappings
Evaluated Linux kernel v4.18.5 and found 36 permission check bugs
19
Thank you !
20