Merge "init: clean up file / socket descriptor creation"
This commit is contained in:
commit
c8620ddafe
|
@ -107,7 +107,6 @@ cc_library_static {
|
|||
"bootchart.cpp",
|
||||
"builtins.cpp",
|
||||
"capabilities.cpp",
|
||||
"descriptors.cpp",
|
||||
"devices.cpp",
|
||||
"epoll.cpp",
|
||||
"firmware_handler.cpp",
|
||||
|
@ -254,7 +253,6 @@ cc_binary {
|
|||
"action_manager.cpp",
|
||||
"action_parser.cpp",
|
||||
"capabilities.cpp",
|
||||
"descriptors.cpp",
|
||||
"epoll.cpp",
|
||||
"keychords.cpp",
|
||||
"import_parser.cpp",
|
||||
|
|
|
@ -300,7 +300,8 @@ runs the service.
|
|||
|
||||
`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
|
||||
> Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
|
||||
launched process. _type_ must be "dgram", "stream" or "seqpacket". User and
|
||||
launched process. _type_ must be "dgram", "stream" or "seqpacket". _type_
|
||||
may end with "+passcred" to enable SO_PASSCRED on the socket. User and
|
||||
group default to 0. 'seclabel' is the SELinux security context for the
|
||||
socket. It defaults to the service security context, as specified by
|
||||
seclabel or computed based on the service executable file security context.
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "descriptors.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <cutils/android_get_control_file.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
|
||||
gid_t gid, int perm, const std::string& context)
|
||||
: name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
|
||||
}
|
||||
|
||||
DescriptorInfo::~DescriptorInfo() {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
|
||||
return os << " descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
|
||||
}
|
||||
|
||||
bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
|
||||
return name_ == other.name_ && type_ == other.type_ && key() == other.key();
|
||||
}
|
||||
|
||||
void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
|
||||
// Create
|
||||
const std::string& contextStr = context_.empty() ? globalContext : context_;
|
||||
int fd = Create(contextStr);
|
||||
if (fd < 0) return;
|
||||
|
||||
// Publish
|
||||
std::string publishedName = key() + name_;
|
||||
std::for_each(publishedName.begin(), publishedName.end(),
|
||||
[] (char& c) { c = isalnum(c) ? c : '_'; });
|
||||
|
||||
std::string val = std::to_string(fd);
|
||||
setenv(publishedName.c_str(), val.c_str(), 1);
|
||||
|
||||
// make sure we don't close on exec
|
||||
fcntl(fd, F_SETFD, 0);
|
||||
}
|
||||
|
||||
void DescriptorInfo::Clean() const {
|
||||
}
|
||||
|
||||
SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
|
||||
gid_t gid, int perm, const std::string& context)
|
||||
: DescriptorInfo(name, type, uid, gid, perm, context) {
|
||||
}
|
||||
|
||||
void SocketInfo::Clean() const {
|
||||
std::string path = android::base::StringPrintf("%s/%s", ANDROID_SOCKET_DIR, name().c_str());
|
||||
unlink(path.c_str());
|
||||
}
|
||||
|
||||
int SocketInfo::Create(const std::string& context) const {
|
||||
auto types = android::base::Split(type(), "+");
|
||||
int flags =
|
||||
((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
|
||||
bool passcred = types.size() > 1 && types[1] == "passcred";
|
||||
return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str());
|
||||
}
|
||||
|
||||
const std::string SocketInfo::key() const {
|
||||
return ANDROID_SOCKET_ENV_PREFIX;
|
||||
}
|
||||
|
||||
FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
|
||||
gid_t gid, int perm, const std::string& context)
|
||||
// defaults OK for uid,..., they are ignored for this class.
|
||||
: DescriptorInfo(name, type, uid, gid, perm, context) {
|
||||
}
|
||||
|
||||
int FileInfo::Create(const std::string&) const {
|
||||
int flags = (type() == "r") ? O_RDONLY :
|
||||
(type() == "w") ? O_WRONLY :
|
||||
O_RDWR;
|
||||
|
||||
// Make sure we do not block on open (eg: devices can chose to block on
|
||||
// carrier detect). Our intention is never to delay launch of a service
|
||||
// for such a condition. The service can perform its own blocking on
|
||||
// carrier detect.
|
||||
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name().c_str(),
|
||||
flags | O_NONBLOCK)));
|
||||
|
||||
if (fd < 0) {
|
||||
PLOG(ERROR) << "Failed to open file '" << name().c_str() << "'";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
|
||||
fcntl(fd, F_SETFL, flags);
|
||||
|
||||
LOG(INFO) << "Opened file '" << name().c_str() << "'"
|
||||
<< ", flags " << std::oct << flags << std::dec;
|
||||
|
||||
return fd.release();
|
||||
}
|
||||
|
||||
const std::string FileInfo::key() const {
|
||||
return ANDROID_FILE_ENV_PREFIX;
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _INIT_DESCRIPTORS_H
|
||||
#define _INIT_DESCRIPTORS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
class DescriptorInfo {
|
||||
public:
|
||||
DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
|
||||
gid_t gid, int perm, const std::string& context);
|
||||
virtual ~DescriptorInfo();
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
|
||||
bool operator==(const DescriptorInfo& other) const;
|
||||
|
||||
void CreateAndPublish(const std::string& globalContext) const;
|
||||
virtual void Clean() const;
|
||||
|
||||
protected:
|
||||
const std::string& name() const { return name_; }
|
||||
const std::string& type() const { return type_; }
|
||||
uid_t uid() const { return uid_; }
|
||||
gid_t gid() const { return gid_; }
|
||||
int perm() const { return perm_; }
|
||||
const std::string& context() const { return context_; }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string type_;
|
||||
uid_t uid_;
|
||||
gid_t gid_;
|
||||
int perm_;
|
||||
std::string context_;
|
||||
|
||||
virtual int Create(const std::string& globalContext) const = 0;
|
||||
virtual const std::string key() const = 0;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
|
||||
|
||||
class SocketInfo : public DescriptorInfo {
|
||||
public:
|
||||
SocketInfo(const std::string& name, const std::string& type, uid_t uid,
|
||||
gid_t gid, int perm, const std::string& context);
|
||||
void Clean() const override;
|
||||
private:
|
||||
virtual int Create(const std::string& context) const override;
|
||||
virtual const std::string key() const override;
|
||||
};
|
||||
|
||||
class FileInfo : public DescriptorInfo {
|
||||
public:
|
||||
FileInfo(const std::string& name, const std::string& type, uid_t uid,
|
||||
gid_t gid, int perm, const std::string& context);
|
||||
private:
|
||||
virtual int Create(const std::string& context) const override;
|
||||
virtual const std::string key() const override;
|
||||
};
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
||||
#endif
|
|
@ -994,10 +994,11 @@ void CreateSerializedPropertyInfo() {
|
|||
void StartPropertyService(Epoll* epoll) {
|
||||
property_set("ro.property_service.version", "2");
|
||||
|
||||
property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
false, 0666, 0, 0, nullptr);
|
||||
if (property_set_fd == -1) {
|
||||
PLOG(FATAL) << "start_property_service socket creation failed";
|
||||
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
false, 0666, 0, 0, {})) {
|
||||
property_set_fd = *result;
|
||||
} else {
|
||||
PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
|
||||
}
|
||||
|
||||
listen(property_set_fd, 8);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <processgroup/processgroup.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
|
@ -227,9 +228,11 @@ void Service::Reap(const siginfo_t& siginfo) {
|
|||
KillProcessGroup(SIGKILL);
|
||||
}
|
||||
|
||||
// Remove any descriptor resources we may have created.
|
||||
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
|
||||
// Remove any socket resources we may have created.
|
||||
for (const auto& socket : sockets_) {
|
||||
auto path = ANDROID_SOCKET_DIR "/" + socket.name;
|
||||
unlink(path.c_str());
|
||||
}
|
||||
|
||||
for (const auto& f : reap_callbacks_) {
|
||||
f(siginfo);
|
||||
|
@ -300,8 +303,12 @@ void Service::DumpState() const {
|
|||
LOG(INFO) << "service " << name_;
|
||||
LOG(INFO) << " class '" << Join(classnames_, " ") << "'";
|
||||
LOG(INFO) << " exec " << Join(args_, " ");
|
||||
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||
[] (const auto& info) { LOG(INFO) << *info; });
|
||||
for (const auto& socket : sockets_) {
|
||||
LOG(INFO) << " socket " << socket.name;
|
||||
}
|
||||
for (const auto& file : files_) {
|
||||
LOG(INFO) << " file " << file.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -419,8 +426,17 @@ Result<void> Service::Start() {
|
|||
setenv(key.c_str(), value.c_str(), 1);
|
||||
}
|
||||
|
||||
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||
std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
|
||||
for (const auto& socket : sockets_) {
|
||||
if (auto result = socket.CreateAndPublish(scon); !result) {
|
||||
LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& file : files_) {
|
||||
if (auto result = file.CreateAndPublish(); !result) {
|
||||
LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto result = WritePidToFiles(&writepid_files_); !result) {
|
||||
LOG(ERROR) << "failed to write pid to files: " << result.error();
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include "action.h"
|
||||
#include "capabilities.h"
|
||||
#include "descriptors.h"
|
||||
#include "keyword_map.h"
|
||||
#include "parser.h"
|
||||
#include "service_utils.h"
|
||||
|
@ -151,7 +150,8 @@ class Service {
|
|||
|
||||
std::string seclabel_;
|
||||
|
||||
std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
|
||||
std::vector<SocketDescriptor> sockets_;
|
||||
std::vector<FileDescriptor> files_;
|
||||
std::vector<std::pair<std::string, std::string>> environment_vars_;
|
||||
|
||||
Action onrestart_; // Commands to execute on restart.
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "service_parser.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
@ -28,6 +30,7 @@
|
|||
#include <system/thread_defs.h>
|
||||
|
||||
#include "rlimit_parser.h"
|
||||
#include "service_utils.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
@ -344,64 +347,98 @@ Result<void> ServiceParser::ParseTimeoutPeriod(std::vector<std::string>&& args)
|
|||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Result<void> ServiceParser::AddDescriptor(std::vector<std::string>&& args) {
|
||||
int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
|
||||
Result<uid_t> uid = 0;
|
||||
Result<gid_t> gid = 0;
|
||||
std::string context = args.size() > 6 ? args[6] : "";
|
||||
// name type perm [ uid gid context ]
|
||||
Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
|
||||
SocketDescriptor socket;
|
||||
socket.name = std::move(args[1]);
|
||||
|
||||
auto types = Split(args[2], "+");
|
||||
if (types[0] == "stream") {
|
||||
socket.type = SOCK_STREAM;
|
||||
} else if (types[0] == "dgram") {
|
||||
socket.type = SOCK_DGRAM;
|
||||
} else if (types[0] == "seqpacket") {
|
||||
socket.type = SOCK_SEQPACKET;
|
||||
} else {
|
||||
return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
|
||||
<< "' instead.";
|
||||
}
|
||||
|
||||
if (types.size() > 1) {
|
||||
if (types.size() == 2 && types[1] == "passcred") {
|
||||
socket.passcred = true;
|
||||
} else {
|
||||
return Error() << "Only 'passcred' may be used to modify the socket type";
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
char* end = nullptr;
|
||||
socket.perm = strtol(args[3].c_str(), &end, 8);
|
||||
if (errno != 0) {
|
||||
return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
|
||||
}
|
||||
if (end == args[3].c_str() || *end != '\0') {
|
||||
errno = EINVAL;
|
||||
return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
|
||||
}
|
||||
|
||||
if (args.size() > 4) {
|
||||
uid = DecodeUid(args[4]);
|
||||
auto uid = DecodeUid(args[4]);
|
||||
if (!uid) {
|
||||
return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
|
||||
}
|
||||
socket.uid = *uid;
|
||||
}
|
||||
|
||||
if (args.size() > 5) {
|
||||
gid = DecodeUid(args[5]);
|
||||
auto gid = DecodeUid(args[5]);
|
||||
if (!gid) {
|
||||
return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
|
||||
}
|
||||
socket.gid = *gid;
|
||||
}
|
||||
|
||||
auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context);
|
||||
socket.context = args.size() > 6 ? args[6] : "";
|
||||
|
||||
auto old = std::find_if(
|
||||
service_->descriptors_.begin(), service_->descriptors_.end(),
|
||||
[&descriptor](const auto& other) { return descriptor.get() == other.get(); });
|
||||
auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
|
||||
[&socket](const auto& other) { return socket.name == other.name; });
|
||||
|
||||
if (old != service_->descriptors_.end()) {
|
||||
return Error() << "duplicate descriptor " << args[1] << " " << args[2];
|
||||
if (old != service_->sockets_.end()) {
|
||||
return Error() << "duplicate socket descriptor '" << socket.name << "'";
|
||||
}
|
||||
|
||||
service_->descriptors_.emplace_back(std::move(descriptor));
|
||||
service_->sockets_.emplace_back(std::move(socket));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// name type perm [ uid gid context ]
|
||||
Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
|
||||
if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
|
||||
!StartsWith(args[2], "seqpacket")) {
|
||||
return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
|
||||
}
|
||||
return AddDescriptor<SocketInfo>(std::move(args));
|
||||
}
|
||||
|
||||
// name type perm [ uid gid context ]
|
||||
// name type
|
||||
Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
|
||||
if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
|
||||
return Error() << "file type must be 'r', 'w' or 'rw'";
|
||||
}
|
||||
std::string expanded;
|
||||
if (!expand_props(args[1], &expanded)) {
|
||||
|
||||
FileDescriptor file;
|
||||
file.type = args[2];
|
||||
|
||||
if (!expand_props(args[1], &file.name)) {
|
||||
return Error() << "Could not expand property in file path '" << args[1] << "'";
|
||||
}
|
||||
args[1] = std::move(expanded);
|
||||
if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
|
||||
if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
|
||||
return Error() << "file name must not be relative";
|
||||
}
|
||||
return AddDescriptor<FileInfo>(std::move(args));
|
||||
|
||||
auto old = std::find_if(service_->files_.begin(), service_->files_.end(),
|
||||
[&file](const auto& other) { return other.name == file.name; });
|
||||
|
||||
if (old != service_->files_.end()) {
|
||||
return Error() << "duplicate file descriptor '" << file.name << "'";
|
||||
}
|
||||
|
||||
service_->files_.emplace_back(std::move(file));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
|
||||
|
|
|
@ -81,9 +81,6 @@ class ServiceParser : public SectionParser {
|
|||
Result<void> ParseWritepid(std::vector<std::string>&& args);
|
||||
Result<void> ParseUpdatable(std::vector<std::string>&& args);
|
||||
|
||||
template <typename T>
|
||||
Result<void> AddDescriptor(std::vector<std::string>&& args);
|
||||
|
||||
bool IsValidName(const std::string& name) const;
|
||||
|
||||
ServiceList* service_list_;
|
||||
|
|
|
@ -27,9 +27,12 @@
|
|||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <cutils/android_get_control_file.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <processgroup/processgroup.h>
|
||||
|
||||
#include "mount_namespace.h"
|
||||
#include "util.h"
|
||||
|
||||
using android::base::GetProperty;
|
||||
using android::base::StartsWith;
|
||||
|
@ -135,8 +138,52 @@ void OpenConsole(const std::string& console) {
|
|||
dup2(fd, 2);
|
||||
}
|
||||
|
||||
void PublishDescriptor(const std::string& key, const std::string& name, int fd) {
|
||||
std::string published_name = key + name;
|
||||
for (auto& c : published_name) {
|
||||
c = isalnum(c) ? c : '_';
|
||||
}
|
||||
|
||||
std::string val = std::to_string(fd);
|
||||
setenv(published_name.c_str(), val.c_str(), 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result<void> SocketDescriptor::CreateAndPublish(const std::string& global_context) const {
|
||||
const auto& socket_context = context.empty() ? global_context : context;
|
||||
auto result = CreateSocket(name, type, passcred, perm, uid, gid, socket_context);
|
||||
if (!result) {
|
||||
return result.error();
|
||||
}
|
||||
|
||||
PublishDescriptor(ANDROID_SOCKET_ENV_PREFIX, name, *result);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> FileDescriptor::CreateAndPublish() const {
|
||||
int flags = (type == "r") ? O_RDONLY : (type == "w") ? O_WRONLY : O_RDWR;
|
||||
|
||||
// Make sure we do not block on open (eg: devices can chose to block on carrier detect). Our
|
||||
// intention is never to delay launch of a service for such a condition. The service can
|
||||
// perform its own blocking on carrier detect.
|
||||
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK)));
|
||||
|
||||
if (fd < 0) {
|
||||
return ErrnoError() << "Failed to open file '" << name << "'";
|
||||
}
|
||||
|
||||
// Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
|
||||
fcntl(fd, F_SETFL, flags);
|
||||
|
||||
LOG(INFO) << "Opened file '" << name << "', flags " << flags;
|
||||
|
||||
PublishDescriptor(ANDROID_FILE_ENV_PREFIX, name, fd.release());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
|
||||
for (const auto& [nstype, path] : info.namespaces_to_enter) {
|
||||
if (auto result = EnterNamespace(nstype, path.c_str()); !result) {
|
||||
|
|
|
@ -29,6 +29,25 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
struct SocketDescriptor {
|
||||
std::string name;
|
||||
int type = 0;
|
||||
uid_t uid = 0;
|
||||
gid_t gid = 0;
|
||||
int perm = 0;
|
||||
std::string context;
|
||||
bool passcred = false;
|
||||
|
||||
Result<void> CreateAndPublish(const std::string& global_context) const;
|
||||
};
|
||||
|
||||
struct FileDescriptor {
|
||||
std::string name;
|
||||
std::string type;
|
||||
|
||||
Result<void> CreateAndPublish() const;
|
||||
};
|
||||
|
||||
struct NamespaceInfo {
|
||||
int flags;
|
||||
// Pair of namespace type, path to name.
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/scopeguard.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <cutils/sockets.h>
|
||||
|
@ -77,32 +78,28 @@ Result<uid_t> DecodeUid(const std::string& name) {
|
|||
* daemon. We communicate the file descriptor's value via the environment
|
||||
* variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
|
||||
*/
|
||||
int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
|
||||
const char* socketcon) {
|
||||
if (socketcon) {
|
||||
if (setsockcreatecon(socketcon) == -1) {
|
||||
PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
|
||||
return -1;
|
||||
Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
|
||||
gid_t gid, const std::string& socketcon) {
|
||||
if (!socketcon.empty()) {
|
||||
if (setsockcreatecon(socketcon.c_str()) == -1) {
|
||||
return ErrnoError() << "setsockcreatecon(\"" << socketcon << "\") failed";
|
||||
}
|
||||
}
|
||||
|
||||
android::base::unique_fd fd(socket(PF_UNIX, type, 0));
|
||||
if (fd < 0) {
|
||||
PLOG(ERROR) << "Failed to open socket '" << name << "'";
|
||||
return -1;
|
||||
return ErrnoError() << "Failed to open socket '" << name << "'";
|
||||
}
|
||||
|
||||
if (socketcon) setsockcreatecon(NULL);
|
||||
if (!socketcon.empty()) setsockcreatecon(nullptr);
|
||||
|
||||
struct sockaddr_un addr;
|
||||
memset(&addr, 0 , sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
|
||||
name);
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR "/%s", name.c_str());
|
||||
|
||||
if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
|
||||
PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
|
||||
return -1;
|
||||
return ErrnoError() << "Failed to unlink old socket '" << name << "'";
|
||||
}
|
||||
|
||||
std::string secontext;
|
||||
|
@ -113,8 +110,7 @@ int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t u
|
|||
if (passcred) {
|
||||
int on = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
|
||||
PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
|
||||
return -1;
|
||||
return ErrnoError() << "Failed to set SO_PASSCRED '" << name << "'";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,19 +121,18 @@ int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t u
|
|||
setfscreatecon(nullptr);
|
||||
}
|
||||
|
||||
auto guard = android::base::make_scope_guard([&addr] { unlink(addr.sun_path); });
|
||||
|
||||
if (ret) {
|
||||
errno = savederrno;
|
||||
PLOG(ERROR) << "Failed to bind socket '" << name << "'";
|
||||
goto out_unlink;
|
||||
return ErrnoError() << "Failed to bind socket '" << name << "'";
|
||||
}
|
||||
|
||||
if (lchown(addr.sun_path, uid, gid)) {
|
||||
PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
|
||||
goto out_unlink;
|
||||
return ErrnoError() << "Failed to lchown socket '" << addr.sun_path << "'";
|
||||
}
|
||||
if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
|
||||
PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
|
||||
goto out_unlink;
|
||||
return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'";
|
||||
}
|
||||
|
||||
LOG(INFO) << "Created socket '" << addr.sun_path << "'"
|
||||
|
@ -145,11 +140,8 @@ int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t u
|
|||
<< ", user " << uid
|
||||
<< ", group " << gid;
|
||||
|
||||
guard.Disable();
|
||||
return fd.release();
|
||||
|
||||
out_unlink:
|
||||
unlink(addr.sun_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Result<std::string> ReadFile(const std::string& path) {
|
||||
|
|
|
@ -38,8 +38,8 @@ namespace init {
|
|||
|
||||
static const char kColdBootDoneProp[] = "ro.cold_boot_done";
|
||||
|
||||
int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
|
||||
const char* socketcon);
|
||||
Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
|
||||
gid_t gid, const std::string& socketcon);
|
||||
|
||||
Result<std::string> ReadFile(const std::string& path);
|
||||
Result<void> WriteFile(const std::string& path, const std::string& content);
|
||||
|
|
Loading…
Reference in New Issue