blob: 73a713f2b36a27c541d77e8c288371aaa74187e4 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBCONTAINER_LIBCONTAINER_UTIL_H_
#define LIBCONTAINER_LIBCONTAINER_UTIL_H_
#include <linux/loop.h>
#include <string>
#include <vector>
#include <base/callback_forward.h>
#include <base/files/file_path.h>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <base/macros.h>
#include <libminijail.h>
#include "libcontainer/config.h"
#include "libcontainer/libcontainer.h"
namespace libcontainer {
// WaitablePipe provides a way for one process to wait on another. This only
// uses the read(2) and close(2) syscalls, so it can work even in a restrictive
// environment. Each process must call only one of Wait() and Signal() exactly
// once.
struct WaitablePipe {
WaitablePipe();
~WaitablePipe();
WaitablePipe(WaitablePipe&&);
WaitablePipe(const WaitablePipe&) = delete;
WaitablePipe& operator=(const WaitablePipe&) = delete;
// Waits for Signal() to be called.
void Wait();
// Notifies the process that called Wait() to continue running.
void Signal();
int pipe_fds[2];
};
// HookState holds two WaitablePipes so that the container can wait for its
// parent to run prestart hooks just prior to calling execve(2).
class HookState {
public:
HookState();
~HookState();
HookState(HookState&& state);
HookState(const HookState&) = delete;
HookState& operator=(const HookState&) = delete;
// Initializes this HookState so that WaitForHookAndRun() can be invoked and
// waited upon when |j| reaches |event|. Returns true on success.
bool InstallHook(minijail* j, minijail_hook_event_t event);
// Waits for the event specified in InstallHook() and invokes |callbacks| in
// the caller process. Returns true if all callbacks succeeded.
bool WaitForHookAndRun(const std::vector<HookCallback>& callbacks,
pid_t container_pid);
private:
// A function that can be passed to minijail_add_hook() that blocks the
// process in the container until the parent has finished running whatever
// operations are needed outside the container. This is not expected to be
// called directly.
static int WaitHook(void* payload);
bool installed_ = false;
WaitablePipe reached_pipe_;
WaitablePipe ready_pipe_;
};
// Loopdev represents an active loopback device.
struct Loopdev {
// The path of the loopback device. e.g. /dev/loop1
base::FilePath path;
// An open file descriptor for the loopback device. Has the autoclear flag,
// such that the kernel will automatically remove it once all references to it
// are closed.
base::ScopedFD fd;
// Information about the loop device.
struct loop_info64 info;
};
// Given a uid/gid map of "inside1 outside1 length1, ...", and an id inside of
// the user namespace, populate |id_out|. Returns true on success.
bool GetUsernsOutsideId(const std::string& map, int id, int* id_out);
bool MakeDir(const base::FilePath& path, int uid, int gid, int mode);
bool TouchFile(const base::FilePath& path, int uid, int gid, int mode);
// Find a free loop device and attach it.
bool LoopdevSetup(const base::FilePath& source, Loopdev* loopdev_out);
// Detach the specified loop device.
bool LoopdevDetach(Loopdev* loopdev);
// Create a new device mapper target for the source.
bool DeviceMapperSetup(const base::FilePath& source,
const std::string& verity_cmdline,
base::FilePath* dm_path_out,
std::string* dm_name_out);
// Tear down the device mapper target.
bool DeviceMapperDetach(const std::string& dm_name);
// Match mount_one in minijail, mount one mountpoint with
// consideration for combination of MS_BIND/MS_RDONLY flag.
bool MountExternal(const std::string& src,
const std::string& dest,
const std::string& type,
unsigned long flags,
const std::string& data);
// Creates a pipe using pipe2(2) and returns both ends as base::ScopedFDs.
bool Pipe2(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe, int flags);
// Creates a callback that will fork(2)+execve(2) the program specified by args.
HookCallback CreateExecveCallback(base::FilePath filename,
std::vector<std::string> args,
base::ScopedFD stdin_fd,
base::ScopedFD stdout_fd,
base::ScopedFD stderr_fd);
// Wraps a callback to be run in a subset of the container's namespaces.
HookCallback AdaptCallbackToRunInNamespaces(HookCallback callback,
std::vector<int> nstypes);
// Similar to base::CreateDirectory, but allows specifying the created
// directories' mode and owner.
bool CreateDirectoryOwnedBy(const base::FilePath& full_path,
mode_t mode,
uid_t uid,
gid_t gid);
} // namespace libcontainer
#endif // LIBCONTAINER_LIBCONTAINER_UTIL_H_