summaryrefslogtreecommitdiff
path: root/init/service_parser.cpp
diff options
context:
space:
mode:
authorTom Cherry <tomcherry@google.com>2019-07-09 13:33:36 -0700
committerTom Cherry <tomcherry@google.com>2019-07-15 12:17:30 -0700
commit2e4c85f157bd52d4daaf0b4e67280aa72f98da07 (patch)
treebb553134c66c156072cc747c99d93812acc5bc5f /init/service_parser.cpp
parent8a779ee959996b413a8539d2a571e34803be0bf5 (diff)
init: clean up file / socket descriptor creation
clang-tidy hinted that some of this code wasn't right. Looking deeper, there is really not much related to file and socket descriptors, except that they're published in similar ways to the environment. All of the abstraction into a 'Descriptor' class takes us further away from specifying what we really mean. This removes that abstraction, adds stricter checks and better errors for parsing init scripts, reports sockets and files that are unable to be acquired before exec, and updates the README.md for the passcred option. Test: build, logd (uses files and sockets) works Change-Id: I59e611e95c85bdbefa779ef69b32b9dd4ee203e2
Diffstat (limited to 'init/service_parser.cpp')
-rw-r--r--init/service_parser.cpp97
1 files changed, 67 insertions, 30 deletions
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 88ce364c4..0fbbeb828 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -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));
- return {};
-}
+ service_->sockets_.emplace_back(std::move(socket));
-// 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));
+ return {};
}
-// 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) {