2 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "anbox/android/ip_config_builder.h"
19 #include "anbox/common/binder_device_allocator.h"
20 #include "anbox/common/binder_device.h"
21 #include "anbox/container/lxc_container.h"
22 #include "anbox/system_configuration.h"
23 #include "anbox/logger.h"
24 #include "anbox/utils.h"
31 #include <boost/filesystem.hpp>
32 #include <boost/throw_exception.hpp>
34 #include <sys/capability.h>
35 #include <sys/prctl.h>
36 #include <sys/types.h>
42 namespace fs = boost::filesystem;
45 constexpr unsigned int unprivileged_uid{100000};
46 constexpr unsigned int android_system_uid{1000};
47 constexpr const char *default_container_ip_address{"192.168.250.2"};
48 constexpr const std::uint32_t default_container_ip_prefix_length{24};
49 constexpr const char *default_host_ip_address{"192.168.250.1"};
50 constexpr const char *default_dns_server{"8.8.8.8"};
51 constexpr int num_needed_binders{1};
53 #ifdef ENABLE_LXC2_SUPPORT
54 constexpr const char *lxc_config_idmap_key{"lxc.id_map"};
55 constexpr const char *lxc_config_net_type_key{"lxc.network.type"};
56 constexpr const char *lxc_config_net_flags_key{"lxc.network.flags"};
57 constexpr const char *lxc_config_net_link_key{"lxc.network.link"};
58 constexpr const char *lxc_config_pty_max_key{"lxc.pts"};
59 constexpr const char *lxc_config_tty_max_key{"lxc.tty"};
60 constexpr const char *lxc_config_uts_name_key{"lxc.utsname"};
61 constexpr const char *lxc_config_tty_dir_key{"lxc.devttydir"};
62 constexpr const char *lxc_config_init_cmd_key{"lxc.init_cmd"};
63 constexpr const char *lxc_config_rootfs_path_key{"lxc.rootfs"};
64 constexpr const char *lxc_config_log_level_key{"lxc.loglevel"};
65 constexpr const char *lxc_config_log_file_key{"lxc.logfile"};
66 constexpr const char *lxc_config_apparmor_profile_key{"lxc.aa_profile"};
68 constexpr const char *lxc_config_idmap_key{"lxc.idmap"};
69 constexpr const char *lxc_config_net_type_key{"lxc.net.0.type"};
70 constexpr const char *lxc_config_net_flags_key{"lxc.net.0.flags"};
71 constexpr const char *lxc_config_net_link_key{"lxc.net.0.link"};
72 constexpr const char *lxc_config_pty_max_key{"lxc.pty.max"};
73 constexpr const char *lxc_config_tty_max_key{"lxc.tty.max"};
74 constexpr const char *lxc_config_uts_name_key{"lxc.uts.name"};
75 constexpr const char *lxc_config_tty_dir_key{"lxc.tty.dir"};
76 constexpr const char *lxc_config_init_cmd_key{"lxc.init.cmd"};
77 constexpr const char *lxc_config_rootfs_path_key{"lxc.rootfs.path"};
78 constexpr const char *lxc_config_log_level_key{"lxc.log.level"};
79 constexpr const char *lxc_config_log_file_key{"lxc.log.file"};
80 constexpr const char *lxc_config_apparmor_profile_key{"lxc.apparmor.profile"};
83 constexpr int device_major(dev_t dev) {
84 return int(((dev >> 8) & 0xfff) | ((dev >> 32) & (0xfffff000)));
87 constexpr int device_minor(dev_t dev) {
88 return int((dev & 0xff) | ((dev >> 12) & (0xffffff00)));
94 LxcContainer::LxcContainer(bool privileged,
96 const std::string& container_network_address,
97 const std::string &container_network_gateway,
98 const std::vector<std::string> &container_network_dns_servers,
99 const network::Credentials &creds)
100 : state_(State::inactive),
102 privileged_(privileged),
103 rootfs_overlay_(rootfs_overlay),
104 container_network_address_(container_network_address),
105 container_network_gateway_(container_network_gateway),
106 container_network_dns_servers_(container_network_dns_servers),
108 utils::ensure_paths({
109 SystemConfiguration::instance().container_config_dir(),
110 SystemConfiguration::instance().container_state_dir(),
111 SystemConfiguration::instance().log_dir(),
115 LxcContainer::~LxcContainer() {
118 lxc_container_put(container_);
121 void LxcContainer::setup_id_map() {
122 const auto base_id = unprivileged_uid;
123 const auto max_id = 100000;
125 set_config_item(lxc_config_idmap_key, utils::string_format("u 0 %d %d", base_id, android_system_uid - 1));
126 set_config_item(lxc_config_idmap_key, utils::string_format("g 0 %d %d", base_id, android_system_uid - 1));
128 // We need to bind the user id for the one running the client side
129 // process as he is the owner of various socket files we bind mount
130 // into the container.
131 set_config_item(lxc_config_idmap_key, utils::string_format("u %d %d 1", android_system_uid, creds_.uid()));
132 set_config_item(lxc_config_idmap_key, utils::string_format("g %d %d 1", android_system_uid, creds_.gid()));
134 set_config_item(lxc_config_idmap_key, utils::string_format("u %d %d %d", android_system_uid + 1,
135 base_id + android_system_uid + 1,
136 max_id - creds_.uid() - 1));
137 set_config_item(lxc_config_idmap_key, utils::string_format("g %d %d %d", android_system_uid + 1,
138 base_id + android_system_uid + 1,
139 max_id - creds_.gid() - 1));
142 void LxcContainer::setup_network() {
143 if (!fs::exists("/sys/class/net/anbox0")) {
144 WARNING("Anbox bridge interface 'anbox0' doesn't exist. Network functionality will not be available");
148 set_config_item(lxc_config_net_type_key, "veth");
149 set_config_item(lxc_config_net_flags_key, "up");
150 set_config_item(lxc_config_net_link_key, "anbox0");
152 // Instead of relying on DHCP we will give Android a static IP configuration
153 // for the virtual ethernet interface LXC creates for us. This will be bridged
154 // to the host and will allows us to have reliable network connectivity and
155 // not depend on any other system service.
157 android::IpConfigBuilder ip_conf;
158 ip_conf.set_version(android::IpConfigBuilder::Version::Version2);
159 ip_conf.set_assignment(android::IpConfigBuilder::Assignment::Static);
161 std::string address = default_container_ip_address;
162 std::uint32_t ip_prefix_length = default_container_ip_prefix_length;
163 if (!container_network_address_.empty()) {
164 auto tokens = utils::string_split(container_network_address_, '/');
165 if (tokens.size() == 1 || tokens.size() == 2)
167 if (tokens.size() == 2)
168 ip_prefix_length = atoi(tokens[1].c_str());
170 ip_conf.set_link_address(address, ip_prefix_length);
172 std::string gateway = default_host_ip_address;
173 if (!container_network_gateway_.empty())
174 gateway = container_network_gateway_;
175 ip_conf.set_gateway(gateway);
177 if (container_network_dns_servers_.size() > 0)
178 ip_conf.set_dns_servers(container_network_dns_servers_);
180 ip_conf.set_dns_servers({default_dns_server});
184 std::vector<std::uint8_t> buffer(512);
185 common::BinaryWriter writer(buffer.begin(), buffer.end());
186 const auto size = ip_conf.write(writer);
188 const auto data_ethernet_path = fs::path("data") / "misc" / "ethernet";
189 const auto ip_conf_dir = SystemConfiguration::instance().data_dir() / data_ethernet_path;
190 if (!fs::exists(ip_conf_dir))
191 fs::create_directories(ip_conf_dir);
193 // We have to walk through the created directory hierachy now and
194 // ensure the permissions are set correctly. Otherwise the Android
195 // system will fail to boot as it isn't allowed to write anything
196 // into these directories. As previous versions of Anbox which were
197 // published to our users did this incorrectly we need to check on
198 // every startup if those directories are still owned by root and
199 // if they are we move them over to the unprivileged user.
200 auto path = SystemConfiguration::instance().data_dir();
201 for (auto iter = data_ethernet_path.begin(); iter != data_ethernet_path.end(); iter++) {
205 if (stat(path.c_str(), &st) < 0) {
206 WARNING("Cannot retrieve permissions of path %s", path);
210 if (st.st_uid != 0 && st.st_gid != 0)
213 if (::chown(path.c_str(), unprivileged_uid, unprivileged_uid) < 0)
214 WARNING("Failed to set owner for path '%s'", path);
217 const auto ip_conf_path = ip_conf_dir / "ipconfig.txt";
218 if (fs::exists(ip_conf_path))
219 fs::remove(ip_conf_path);
221 std::ofstream f(ip_conf_path.string(), std::ofstream::binary);
223 f.write(reinterpret_cast<const char*>(buffer.data()), size);
226 ERROR("Failed to write IP configuration. Network functionality will not be available.");
230 void LxcContainer::add_device(const std::string& device, const DeviceSpecification& spec) {
232 const std::string *old_device_name;
233 if (!spec.old_device_name.empty())
234 old_device_name = &spec.old_device_name;
236 old_device_name = &device;
237 int r = stat(old_device_name->c_str(), &st);
239 const auto msg = utils::string_format("Failed to retrieve information about device %s", device);
240 throw std::runtime_error(msg);
243 const auto major = device_major(st.st_rdev);
244 const auto minor = device_minor(st.st_rdev);
245 const auto mode = ((st.st_mode >> 9) << 9) | (spec.permission & ~(1 << 9));
246 const auto new_device_name = fs::basename(device);
247 const auto devices_path = fs::path(SystemConfiguration::instance().container_devices_dir());
248 const auto new_device_path = (devices_path / new_device_name).string();
250 const auto encoded_device_number = (minor & 0xff) | (major << 8) | ((minor & !0xff) << 12);
251 r = mknod(new_device_path.c_str(), mode, encoded_device_number);
253 auto msg = utils::string_format("Failed to create node for device %s: %s",
254 device, strerror(errno));
255 throw std::runtime_error(msg);
258 auto base_uid = unprivileged_uid;
262 const auto shifted_uid = base_uid + st.st_uid;
263 const auto shifted_gid = base_uid + st.st_gid;
264 r = chown(new_device_path.c_str(), shifted_uid, shifted_gid);
266 auto msg = utils::string_format("Failed to change ownership of new node for %s: %s",
267 device, strerror(errno));
268 throw std::runtime_error(msg);
271 // Needed as mknod respects the umask
272 r = chmod(new_device_path.c_str(), mode);
274 auto msg = utils::string_format("Failed to change mode of new node for %s: %s",
275 device, strerror(errno));
276 throw::std::runtime_error(msg);
279 auto target_path = device;
280 // Strip a leading slash as LXC doesn't like that
281 if (utils::string_starts_with(device, "/"))
282 target_path = device.substr(1, device.length() - 1);
284 const auto entry = utils::string_format("%s %s none bind,create=file,optional 0 0",
285 new_device_path, target_path);
286 set_config_item("lxc.mount.entry", entry);
289 bool LxcContainer::create_binder_devices(unsigned int device_count, std::vector<std::unique_ptr<common::BinderDevice>>& devices) {
290 // We will always allocate a static set of binders devices even if the container
291 // doesn't use all of them
292 for (unsigned int n = 0; n < device_count; n++) {
293 auto device = common::BinderDeviceAllocator::new_device();
297 DEBUG("Allocated binder device %s", device->path());
298 devices.push_back(std::move(device));
304 void LxcContainer::start(const Configuration &configuration) {
306 throw std::runtime_error("You have to start the container as root");
308 if (container_ && container_->is_running(container_)) {
309 WARNING("Container already started, stopping it now");
310 container_->stop(container_);
314 const auto container_config_dir = SystemConfiguration::instance().container_config_dir();
315 DEBUG("Containers are stored in %s", container_config_dir);
317 // Remove container config to be be able to rewrite it
318 ::unlink(utils::string_format("%s/default/config", container_config_dir).c_str());
320 container_ = lxc_container_new("default", container_config_dir.c_str());
322 throw std::runtime_error("Failed to create LXC container instance");
324 // If container is still running (for example after a crash) we stop it here
325 // to ensure its configuration is synchronized.
326 if (container_->is_running(container_))
327 container_->stop(container_);
330 // We can mount proc/sys as rw here as we will run the container unprivileged
332 set_config_item("lxc.mount.auto", "proc:mixed sys:mixed cgroup:mixed");
334 set_config_item("lxc.autodev", "1");
335 set_config_item(lxc_config_pty_max_key, "1024");
336 set_config_item(lxc_config_tty_max_key, "0");
337 set_config_item(lxc_config_uts_name_key, "anbox");
339 set_config_item("lxc.group.devices.deny", "");
340 set_config_item("lxc.group.devices.allow", "");
342 // We can't move bind-mounts, so don't use /dev/lxc/
343 set_config_item(lxc_config_tty_dir_key, "");
345 set_config_item("lxc.environment", "PATH=/system/bin:/system/sbin:/system/xbin");
347 set_config_item(lxc_config_init_cmd_key, "/anbox-init.sh");
349 #ifdef ENABLE_SNAP_CONFINEMENT
350 // If we're running inside the snap environment snap-confine already created a
351 // cgroup for us we need to use as otherwise presevering a namespace wont help.
352 if (utils::is_env_set("SNAP"))
353 set_config_item("lxc.namespace.keep", "cgroup");
356 auto rootfs_path = SystemConfiguration::instance().rootfs_dir();
358 rootfs_path = SystemConfiguration::instance().combined_rootfs_dir();
360 DEBUG("Using rootfs path %s", rootfs_path);
361 set_config_item(lxc_config_rootfs_path_key, rootfs_path);
363 set_config_item(lxc_config_log_level_key, "0");
364 const auto log_path = SystemConfiguration::instance().log_dir();
365 set_config_item(lxc_config_log_file_key, utils::string_format("%s/container.log", log_path).c_str());
367 #ifndef ENABLE_LXC2_SUPPORT
368 // Dump the console output to disk to have a chance to debug early boot problems
369 set_config_item("lxc.console.logfile", utils::string_format("%s/console.log", log_path).c_str());
370 set_config_item("lxc.console.rotate", "1");
375 #ifdef ENABLE_SNAP_CONFINEMENT
376 // We take the AppArmor profile snapd has defined for us as part of the
377 // anbox-support interface. The container manager itself runs within a
378 // child profile snap.anbox.container-manager//lxc too.
379 set_config_item("lxc.apparmor.profile", "snap.anbox.container-manager//container");
381 set_config_item(lxc_config_apparmor_profile_key, "unconfined");
387 auto bind_mounts = configuration.bind_mounts;
388 auto devices = configuration.devices;
390 // If we have binderfs support we can dynamically allocate all our devices
391 if (common::BinderDeviceAllocator::is_supported()) {
392 DEBUG("Using binderfs to allocate our own binder nodes");
394 std::vector<std::unique_ptr<common::BinderDevice>> binder_devices;
395 if (!create_binder_devices(num_needed_binders, binder_devices) ||
396 binder_devices.size() != num_needed_binders)
397 throw std::runtime_error("Failed to allocate necessary binder devices");
399 bind_mounts.insert({binder_devices[0]->path().string(), "/dev/binder"});
400 binder_devices_ = std::move(binder_devices);
402 DEBUG("Using static binder device /dev/binder");
403 devices.insert({"/dev/binder", { 0666 }});
406 for (const auto &bind_mount : bind_mounts) {
407 std::string create_type = "file";
409 if (fs::is_directory(bind_mount.first))
412 auto target_path = bind_mount.second;
413 // The target path needs to be absolute and pointing to the right
414 // location inside the target rootfs as otherwise we get problems
415 // when running in confined environments like snap's.
416 if (!utils::string_starts_with(target_path, "/"))
417 target_path = std::string("/") + target_path;
418 target_path = rootfs_path + target_path;
420 const auto entry = utils::string_format("%s %s none bind,create=%s,optional 0 0",
421 bind_mount.first, target_path, create_type);
422 set_config_item("lxc.mount.entry", entry);
425 // Additional devices we need in our container
426 devices.insert({"/dev/console", {0600}});
427 devices.insert({"/dev/full", {0666}});
428 devices.insert({"/dev/null", {0666}});
429 devices.insert({"/dev/random", {0666}});
430 devices.insert({"/dev/tty", {0666}});
431 devices.insert({"/dev/urandom", {0666}});
432 devices.insert({"/dev/zero", {0666}});
433 devices.insert({"/dev/tun", {0660, "/dev/net/tun"}});
434 devices.insert({"/dev/ashmem", {0666}});
436 // Remove all left over devices from last time first before
437 // creating any new ones
438 const auto devices_dir = SystemConfiguration::instance().container_devices_dir();
439 fs::remove_all(devices_dir);
440 fs::create_directories(devices_dir);
442 for (const auto& device : devices)
443 add_device(device.first, device.second);
445 // If we have any additional properties we add them at the top of default.prop
446 // within the Android rootfs which we overlay with a bind mount.
447 if (configuration.extra_properties.size() > 0) {
448 const auto container_state_dir = SystemConfiguration::instance().container_state_dir();
449 auto old_default_prop_path = fs::path(rootfs_path) / "default.prop";
450 auto new_default_prop_path = fs::path(container_state_dir) / "default.prop";
451 auto default_prop_content = utils::read_file_if_exists_or_throw(old_default_prop_path.string());
453 std::ofstream default_props;
454 default_props.open(new_default_prop_path.string(), std::ios_base::out);
455 if (!default_props.is_open())
456 throw std::runtime_error("Failed to open new default properties file");
458 default_props << "# Properties added by Anbox" << std::endl;
459 for (const auto& prop : configuration.extra_properties)
460 default_props << prop << std::endl;
462 default_props << std::endl
463 << default_prop_content << std::endl;
465 default_props.close();
467 set_config_item("lxc.mount.entry",
468 utils::string_format("%s %s/default.prop none bind,optional,ro 0 0",
469 new_default_prop_path.string(), rootfs_path));
472 if (!container_->save_config(container_, nullptr))
473 throw std::runtime_error("Failed to save container configuration");
475 if (!container_->start(container_, 0, nullptr))
476 throw std::runtime_error("Failed to start container");
478 state_ = Container::State::running;
480 DEBUG("Container successfully started");
483 void LxcContainer::stop() {
484 if (!container_ || !container_->is_running(container_))
487 if (!container_->stop(container_))
488 throw std::runtime_error("Failed to stop container");
490 state_ = Container::State::inactive;
491 binder_devices_.clear();
493 DEBUG("Container successfully stopped");
496 void LxcContainer::set_config_item(const std::string &key,
497 const std::string &value) {
498 if (!container_->set_config_item(container_, key.c_str(), value.c_str())) {
499 const auto msg = utils::string_format("Failed to set config item %s", key);
500 throw std::runtime_error(msg);
504 Container::State LxcContainer::state() { return state_; }
505 } // namespace container