blob: f673ccd26a2583f66a3de97b4a736a96097088bb [file] [log] [blame]
// Copyright 2015 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.
#include "soma/container_spec_wrapper.h"
#include <sys/types.h>
#include <algorithm>
#include <limits>
#include <set>
#include <string>
#include <base/files/file_path.h>
#include <base/memory/scoped_vector.h>
#include "soma/device_filter.h"
#include "soma/namespace.h"
#include "soma/port.h"
#include "soma/proto_bindings/soma_container_spec.pb.h"
#include "soma/sysfs_filter.h"
#include "soma/usb_device_filter.h"
using google::protobuf::RepeatedField;
using google::protobuf::RepeatedPtrField;
namespace soma {
namespace {
void SetListenPorts(ContainerSpec::PortSpec* port_spec,
const std::set<parser::port::Number>& ports) {
// If the wildcard port is in the set, just allow all and bail early.
if (ports.find(parser::port::kWildcard) != ports.end()) {
port_spec->set_allow_all(true);
return;
}
for (const parser::port::Number& port : ports) {
// The parsing code should have ensured this, so just DCHECK()
DCHECK(port <= std::numeric_limits<uint16_t>::max());
port_spec->add_ports(static_cast<uint16_t>(port));
}
}
bool ListenPortIsAllowed(const ContainerSpec::PortSpec& port_spec,
parser::port::Number port) {
if (port_spec.allow_all())
return true;
const RepeatedField<uint32>& ports = port_spec.ports();
return std::find(ports.begin(), ports.end(), port) != ports.end();
}
} // namespace
ContainerSpecWrapper::ContainerSpecWrapper(
const std::string& name,
const base::FilePath& service_bundle_path,
uid_t uid,
gid_t gid) {
internal_.set_name(name);
internal_.set_service_bundle_path(service_bundle_path.value());
internal_.set_uid(uid);
internal_.set_gid(gid);
}
ContainerSpecWrapper::~ContainerSpecWrapper() = default;
void ContainerSpecWrapper::SetServiceNames(
const std::vector<std::string>& service_names) {
internal_.clear_service_names();
for (const std::string& name : service_names)
internal_.add_service_names(name);
}
void ContainerSpecWrapper::SetCommandLine(
const std::vector<std::string>& command_line) {
internal_.clear_command_line();
for (const std::string& arg : command_line)
internal_.add_command_line(arg);
}
void ContainerSpecWrapper::SetNamespaces(
const std::set<parser::ns::Kind>& namespaces) {
internal_.clear_namespaces();
for (const parser::ns::Kind& ns : namespaces)
internal_.add_namespaces(ns);
}
void ContainerSpecWrapper::SetTcpListenPorts(
const std::set<parser::port::Number>& ports) {
internal_.clear_tcp_listen_ports();
SetListenPorts(internal_.mutable_tcp_listen_ports(), ports);
}
void ContainerSpecWrapper::SetUdpListenPorts(
const std::set<parser::port::Number>& ports) {
internal_.clear_udp_listen_ports();
SetListenPorts(internal_.mutable_udp_listen_ports(), ports);
}
void ContainerSpecWrapper::SetDevicePathFilters(
const parser::DevicePathFilter::Set& filters) {
internal_.clear_device_path_filters();
for (const parser::DevicePathFilter& filter : filters)
internal_.add_device_path_filters()->set_filter(filter.filter().value());
}
void ContainerSpecWrapper::SetDeviceNodeFilters(
const parser::DeviceNodeFilter::Set& filters) {
internal_.clear_device_node_filters();
for (const parser::DeviceNodeFilter& parser_filter : filters) {
ContainerSpec::DeviceNodeFilter* filter =
internal_.add_device_node_filters();
filter->set_major(parser_filter.major());
filter->set_minor(parser_filter.minor());
}
}
void ContainerSpecWrapper::AddSysfsFilter(const std::string& filter) {
sysfs_filters_.push_back(new SysfsFilter(base::FilePath(filter)));
}
void ContainerSpecWrapper::AddUSBDeviceFilter(int vid, int pid) {
usb_device_filters_.push_back(new USBDeviceFilter(vid, pid));
}
bool ContainerSpecWrapper::ProvidesServiceNamed(const std::string& name) const {
const RepeatedPtrField<std::string>& names = internal_.service_names();
return std::find(names.begin(), names.end(), name) != names.end();
}
bool ContainerSpecWrapper::ShouldApplyNamespace(
parser::ns::Kind candidate) const {
const RepeatedField<int>& namespaces = internal_.namespaces();
return std::find(namespaces.begin(), namespaces.end(), candidate) !=
namespaces.end();
}
bool ContainerSpecWrapper::TcpListenPortIsAllowed(
parser::port::Number port) const {
return ListenPortIsAllowed(internal_.tcp_listen_ports(), port);
}
bool ContainerSpecWrapper::UdpListenPortIsAllowed(
parser::port::Number port) const {
return ListenPortIsAllowed(internal_.udp_listen_ports(), port);
}
bool ContainerSpecWrapper::DevicePathIsAllowed(
const base::FilePath& query) const {
const RepeatedPtrField<ContainerSpec::DevicePathFilter>& filters =
internal_.device_path_filters();
return
filters.end() !=
std::find_if(filters.begin(), filters.end(),
[query](const ContainerSpec::DevicePathFilter& to_check) {
parser::DevicePathFilter parser_filter(
base::FilePath(to_check.filter()));
return parser_filter.Allows(query);
});
}
bool ContainerSpecWrapper::DeviceNodeIsAllowed(int major, int minor) const {
const RepeatedPtrField<ContainerSpec::DeviceNodeFilter>& filters =
internal_.device_node_filters();
return
filters.end() !=
std::find_if(
filters.begin(), filters.end(),
[major, minor](const ContainerSpec::DeviceNodeFilter& to_check) {
parser::DeviceNodeFilter parser_filter(to_check.major(),
to_check.minor());
return parser_filter.Allows(major, minor);
});
}
} // namespace soma