apmanager: run daemon inside minijail
Run apmanager inside a minijail with limited privileges and system calls
through seccomp filter.
BUG=chromium:442186
TEST=Verify AP services with client connectiviy on arm (peach_pit),
x86 (x86-alex), and amd64 (stumpy) platforms.
CQ-DEPEND=CL:236097
Change-Id: I10b2b0c6943cad134028894505d54e2ca4993a26
Reviewed-on: https://chromium-review.googlesource.com/236098
Tested-by: Zeping Qiu <zqiu@chromium.org>
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Commit-Queue: Zeping Qiu <zqiu@chromium.org>
Trybot-Ready: Zeping Qiu <zqiu@chromium.org>
diff --git a/dhcp_server.cc b/dhcp_server.cc
index c60bd32..0a895a9 100644
--- a/dhcp_server.cc
+++ b/dhcp_server.cc
@@ -10,6 +10,8 @@
#include <base/files/file_util.h>
#include <base/strings/stringprintf.h>
+#include "apmanager/daemon.h"
+
using std::string;
namespace apmanager {
@@ -105,11 +107,9 @@
// terminated. Configure dnsmasq to run in "foreground" so no extra process
// will be spawned.
config += "keep-in-foreground\n";
- // TODO(zqiu): by default, dnsmasq process will be started under "nobody".
- // Set the user to "root" for now, since both the daemon and hostapd are
- // running under "root". Update the user once we switch the daemon and
- // hostapd over to "apmanager" user.
- config += "user=root\n";
+ // Explicitly set the user to apmanager. If not set, dnsmasq will default to
+ // run as "nobody".
+ base::StringAppendF(&config, "user=%s\n", Daemon::kAPManagerUserName);
base::StringAppendF(
&config, "dhcp-range=%s,%s\n", address_low.c_str(), address_high.c_str());
base::StringAppendF(&config, "interface=%s\n", interface_name_.c_str());
diff --git a/dhcp_server_unittest.cc b/dhcp_server_unittest.cc
index ba13631..4bc133b 100644
--- a/dhcp_server_unittest.cc
+++ b/dhcp_server_unittest.cc
@@ -30,7 +30,7 @@
"bind-interfaces\n"
"log-dhcp\n"
"keep-in-foreground\n"
- "user=root\n"
+ "user=apmanager\n"
"dhcp-range=192.168.1.1,192.168.1.128\n"
"interface=test_interface\n"
"dhcp-leasefile=/tmp/dhcpd-1.leases\n";
diff --git a/init/apmanager-seccomp-amd64.policy b/init/apmanager-seccomp-amd64.policy
new file mode 100644
index 0000000..2ebd303
--- /dev/null
+++ b/init/apmanager-seccomp-amd64.policy
@@ -0,0 +1,84 @@
+# Tested on stumpy board
+getegid: 1
+geteuid: 1
+getgid: 1
+getpid: 1
+getresgid: 1
+getresuid: 1
+gettid: 1
+getuid: 1
+setgroups: 1
+setresgid: 1
+setresuid: 1
+
+clock_getres: 1
+clock_gettime: 1
+nanosleep: 1
+alarm: 1
+
+connect: 1
+bind: 1
+getsockname: 1
+pipe: 1
+recvfrom: 1
+recvmsg: 1
+sendmsg: 1
+select: 1
+sendto: 1
+setsockopt: 1
+socket: 1
+socketpair: 1
+
+close: 1
+creat: 1
+ioctl: 1
+open: 1
+prctl: 1
+read: 1
+write: 1
+arch_prctl: 1
+capget: 1
+
+brk: 1
+dup2: 1
+clone: 1
+fork: 1
+mmap: 1
+munmap: 1
+
+fcntl: 1
+fstat: 1
+fsync: 1
+ftruncate: 1
+lseek: 1
+stat: 1
+
+futex: 1
+
+exit: 1
+exit_group: 1
+kill: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+signalfd4: 1
+tkill: 1
+
+epoll_create: 1
+epoll_ctl: 1
+epoll_wait: 1
+poll: 1
+wait4: 1
+
+chdir: 1
+readlink: 1
+umask: 1
+
+set_robust_list: 1
+set_tid_address: 1
+
+execve: 1
+mprotect: 1
+access: 1
+getrlimit: 1
+unlink: 1
\ No newline at end of file
diff --git a/init/apmanager-seccomp-arm.policy b/init/apmanager-seccomp-arm.policy
new file mode 100644
index 0000000..19777c1
--- /dev/null
+++ b/init/apmanager-seccomp-arm.policy
@@ -0,0 +1,78 @@
+# Tested on peach_pit board
+socket: 1
+setsockopt: 1
+bind: 1
+clock_gettime: 1
+_newselect: 1
+recvfrom: 1
+epoll_ctl: 1
+gettid: 1
+write: 1
+epoll_wait: 1
+read: 1
+open: 1
+futex: 1
+brk: 1
+fstat64: 1
+mmap2: 1
+close: 1
+munmap: 1
+sendmsg: 1
+poll: 1
+recvmsg: 1
+fork: 1
+clone: 1
+ioctl: 1
+rt_sigprocmask: 1
+rt_sigaction: 1
+rt_sigreturn: 1
+sigreturn: 1
+connect: 1
+sendto: 1
+creat: 1
+access: 1
+set_robust_list: 1
+set_tid_address: 1
+wait4: 1
+exit: 1
+exit_group: 1
+epoll_create: 1
+
+fcntl64: 1
+prctl: 1
+capget: 1
+capset: 1
+dup2: 1
+
+getpid: 1
+getuid32: 1
+setgroups32: 1
+setresgid32: 1
+setresuid32: 1
+setresgid32: 1
+setresuid32: 1
+setitimer: 1
+mprotect: 1
+stat64: 1
+send: 1
+_llseek: 1
+signalfd4: 1
+execve: 1
+
+getsockname: 1
+readlink: 1
+gettimeofday: 1
+
+restart_syscall: 1
+uname: 1
+ARM_set_tls: 1
+ugetrlimit: 1
+kill: 1
+nanosleep: 1
+
+umask: 1
+pipe: 1
+chdir: 1
+ftruncate64: 1
+fsync: 1
+unlink: 1
\ No newline at end of file
diff --git a/init/apmanager-seccomp-mips.policy b/init/apmanager-seccomp-mips.policy
new file mode 100644
index 0000000..b683c04
--- /dev/null
+++ b/init/apmanager-seccomp-mips.policy
@@ -0,0 +1 @@
+# Stub for now until we have mips hw.
diff --git a/init/apmanager-seccomp-x86.policy b/init/apmanager-seccomp-x86.policy
new file mode 100644
index 0000000..122a897
--- /dev/null
+++ b/init/apmanager-seccomp-x86.policy
@@ -0,0 +1,65 @@
+# Tested on x86-alex board
+clock_gettime: 1
+_newselect: 1
+epoll_ctl: 1
+gettid: 1
+write: 1
+gettimeofday: 1
+epoll_wait: 1
+read: 1
+open: 1
+brk: 1
+fstat64: 1
+mmap2: 1
+close: 1
+munmap: 1
+poll: 1
+rt_sigprocmask: 1
+clone: 1
+signalfd4: 1
+ioctl: 1
+set_robust_list: 1
+fork: 1
+stat64: 1
+execve: 1
+kill: 1
+fcntl64: 1
+access: 1
+mprotect: 1
+waitpid: 1
+set_thread_area: 1
+set_tid_address: 1
+futex: 1
+rt_sigaction: 1
+ugetrlimit: 1
+uname: 1
+readlink: 1
+nanosleep: 1
+restart_syscall: 1
+exit_group: 1
+alarm: 1
+sigreturn: 1
+umask: 1
+_llseek: 1
+capget: 1
+pipe: 1
+chdir: 1
+getuid32: 1
+dup2: 1
+getpid: 1
+stat64: 1
+ftruncate64: 1
+fsync: 1
+prctl: 1
+capset: 1
+getresgid32: 1
+getresuid32: 1
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+setresgid32: 1
+setresuid32: 1
+tgkill: 1
+time: 1
+epoll_create: 1
+socketcall: 1
\ No newline at end of file
diff --git a/init/apmanager.conf b/init/apmanager.conf
index 06dd54f..ad06be0 100644
--- a/init/apmanager.conf
+++ b/init/apmanager.conf
@@ -7,6 +7,7 @@
start on starting system-services
stop on stopping system-services
+expect fork
env APMANAGER_LOG_LEVEL=0
diff --git a/main.cc b/main.cc
index b6c860a..d5fdb55 100644
--- a/main.cc
+++ b/main.cc
@@ -36,6 +36,7 @@
const char kLoggerCommand[] = "/usr/bin/logger";
const char kLoggerUser[] = "syslog";
+const char kSeccompFilePath[] = "/usr/share/policy/apmanager-seccomp.policy";
} // namespace
@@ -83,11 +84,15 @@
}
void DropPrivileges(chromeos::Minijail* minijail) {
- // TODO(zqiu): Need to figure out the right set of privileges to allow
- // hostapd to configure interfaces.
struct minijail* jail = minijail->New();
minijail->DropRoot(jail, apmanager::Daemon::kAPManagerUserName,
apmanager::Daemon::kAPManagerGroupName);
+ // Permissions needed for the daemon and its child processes for managing
+ // network interfaces and binding to network sockets.
+ minijail->UseCapabilities(jail, CAP_TO_MASK(CAP_NET_ADMIN) |
+ CAP_TO_MASK(CAP_NET_RAW) |
+ CAP_TO_MASK(CAP_NET_BIND_SERVICE));
+ minijail->UseSeccompFilter(jail, kSeccompFilePath);
minijail_enter(jail);
minijail->Destroy(jail);
}
@@ -98,11 +103,9 @@
LOG(INFO) << __func__ << ": Dropping privileges";
- // TODO(zqiu): temporary, until we figure out the exact privileges required
- // to start required daemons (hostapd and dnsmasq).
// Now that the daemon has all the resources it needs to run, we can drop
// privileges further.
- // DropPrivileges(minijail);
+ DropPrivileges(minijail);
}
int main(int argc, char* argv[]) {