/* This code triggers a bug which allows you to move a task outside its cgroup when in state 'freezing'. Tomasz Buchert 2010 1. Mount cgroup_freezer somewhere: mkdir /tmp/freezer mount -tcgroup -ofreezer none /tmp/freezer 2. Compile this program: gcc freezer_bug.c -obug 3. Run it. ./bug /tmp/freezer 4. Check what happened: ps aux | grep 'D ' */ #define __USE_ATFILE #include #include #include #include #include #include #include int write_file(int fd, const char* value) { return write(fd, value, strlen(value)); } int main(int argc, char** argv) { if (argc != 2) { printf("%s \n", argv[0]); return 1; } char spid[20]; int cg_fd = open(argv[1], O_RDONLY); int root_tasks = openat(cg_fd, "tasks", O_WRONLY); mkdirat(cg_fd, "freeze_zone", 0700); int zone_fd = openat(cg_fd, "freeze_zone", O_RDONLY); int cpus = openat(zone_fd, "cpuset.cpus", O_WRONLY); int mems = openat(zone_fd, "cpuset.mems", O_WRONLY); int tasks = openat(zone_fd, "tasks", O_WRONLY); int freezer = openat(zone_fd, "freezer.state", O_WRONLY); write_file(cpus, "0"); write_file(mems, "0"); int pid = fork(); if (!pid) { for(;;) ; } sprintf(spid, "%d", pid); printf("Locking pid %s down...\n", spid); write_file(tasks, spid); /* send pid to another cgroup */ write_file(freezer, "FROZEN"); /* freeze it */ if (write_file(root_tasks, spid) != -1) { /* move it back */ printf("Succesfully moved task out of freezing cgroup! BAD!\n"); } else { printf("Didn't work out! GOOD!\n"); } sleep(1); kill(pid, SIGKILL); return 0; }