init: service file keyword am: 62767fe29f am: cc46af0fc9
am: 3b23d2864f
Change-Id: I0bd95c3fe9112b5b66a1f43b6bc52f570fd459d1
This commit is contained in:
commit
5bee4e3d10
9 changed files with 386 additions and 79 deletions
|
|
@ -46,6 +46,7 @@ LOCAL_CPPFLAGS := $(init_cflags)
|
||||||
LOCAL_SRC_FILES:= \
|
LOCAL_SRC_FILES:= \
|
||||||
action.cpp \
|
action.cpp \
|
||||||
capabilities.cpp \
|
capabilities.cpp \
|
||||||
|
descriptors.cpp \
|
||||||
import_parser.cpp \
|
import_parser.cpp \
|
||||||
init_parser.cpp \
|
init_parser.cpp \
|
||||||
log.cpp \
|
log.cpp \
|
||||||
|
|
@ -125,8 +126,10 @@ LOCAL_SRC_FILES := \
|
||||||
LOCAL_SHARED_LIBRARIES += \
|
LOCAL_SHARED_LIBRARIES += \
|
||||||
libcutils \
|
libcutils \
|
||||||
libbase \
|
libbase \
|
||||||
|
libselinux \
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := libinit
|
LOCAL_STATIC_LIBRARIES := libinit
|
||||||
LOCAL_SANITIZE := integer
|
LOCAL_SANITIZE := integer
|
||||||
LOCAL_CLANG := true
|
LOCAL_CLANG := true
|
||||||
|
LOCAL_CPPFLAGS := -Wall -Wextra -Werror
|
||||||
include $(BUILD_NATIVE_TEST)
|
include $(BUILD_NATIVE_TEST)
|
||||||
|
|
|
||||||
104
init/descriptors.cpp
Normal file
104
init/descriptors.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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 <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <android-base/stringprintf.h>
|
||||||
|
#include <cutils/files.h>
|
||||||
|
#include <cutils/sockets.h>
|
||||||
|
|
||||||
|
#include "init.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
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 = android::base::StringPrintf("%d", fd);
|
||||||
|
add_environment(publishedName.c_str(), val.c_str());
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
unlink(android::base::StringPrintf(ANDROID_SOCKET_DIR "/%s", name().c_str()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int SocketInfo::Create(const std::string& context) const {
|
||||||
|
int flags = ((type() == "stream" ? SOCK_STREAM :
|
||||||
|
(type() == "dgram" ? SOCK_DGRAM :
|
||||||
|
SOCK_SEQPACKET)));
|
||||||
|
return create_socket(name().c_str(), flags, 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)
|
||||||
|
: DescriptorInfo(name, type, uid, gid, perm, context) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileInfo::Create(const std::string& context) const {
|
||||||
|
int flags = ((type() == "r" ? O_RDONLY :
|
||||||
|
(type() == "w" ? (O_WRONLY | O_CREAT) :
|
||||||
|
(O_RDWR | O_CREAT))));
|
||||||
|
return create_file(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string FileInfo::key() const {
|
||||||
|
return ANDROID_FILE_ENV_PREFIX;
|
||||||
|
}
|
||||||
78
init/descriptors.h
Normal file
78
init/descriptors.h
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -141,12 +141,20 @@ setenv <name> <value>
|
||||||
Set the environment variable <name> to <value> in the launched process.
|
Set the environment variable <name> to <value> in the launched process.
|
||||||
|
|
||||||
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
|
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
|
||||||
Create a unix domain socket named /dev/socket/<name> and pass
|
Create a unix domain socket named /dev/socket/<name> and pass its fd to the
|
||||||
its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
|
launched process. <type> must be "dgram", "stream" or "seqpacket". User and
|
||||||
User and group default to 0.
|
group default to 0. 'seclabel' is the SELinux security context for the
|
||||||
'seclabel' is the SELinux security context for the socket.
|
socket. It defaults to the service security context, as specified by
|
||||||
It defaults to the service security context, as specified by seclabel or
|
seclabel or computed based on the service executable file security context.
|
||||||
computed based on the service executable file security context.
|
For native executables see libcutils android_get_control_socket().
|
||||||
|
|
||||||
|
file <path> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
|
||||||
|
Open/Create a file path and pass its fd to the launched process. <type> must
|
||||||
|
be "r", "w" or "rw". User and group default to 0. 'seclabel' is the SELinux
|
||||||
|
security context for the file if it must be created. It defaults to the
|
||||||
|
service security context, as specified by seclabel or computed based on the
|
||||||
|
service executable file security context. For native executables see
|
||||||
|
libcutils android_get_control_file().
|
||||||
|
|
||||||
user <username>
|
user <username>
|
||||||
Change to 'username' before exec'ing this service.
|
Change to 'username' before exec'ing this service.
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@
|
||||||
#include <android-base/stringprintf.h>
|
#include <android-base/stringprintf.h>
|
||||||
#include <android-base/strings.h>
|
#include <android-base/strings.h>
|
||||||
#include <cutils/android_reboot.h>
|
#include <cutils/android_reboot.h>
|
||||||
#include <cutils/sockets.h>
|
|
||||||
#include <system/thread_defs.h>
|
#include <system/thread_defs.h>
|
||||||
|
|
||||||
#include <processgroup/processgroup.h>
|
#include <processgroup/processgroup.h>
|
||||||
|
|
@ -145,14 +144,6 @@ static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>*
|
||||||
strs->push_back(nullptr);
|
strs->push_back(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
|
|
||||||
gid_t gid, int perm, const std::string& socketcon)
|
|
||||||
: name(name), type(type), uid(uid), gid(gid), perm(perm), socketcon(socketcon) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
|
ServiceEnvironmentInfo::ServiceEnvironmentInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,20 +204,6 @@ void Service::KillProcessGroup(int signal) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service::CreateSockets(const std::string& context) {
|
|
||||||
for (const auto& si : sockets_) {
|
|
||||||
int socket_type = ((si.type == "stream" ? SOCK_STREAM :
|
|
||||||
(si.type == "dgram" ? SOCK_DGRAM :
|
|
||||||
SOCK_SEQPACKET)));
|
|
||||||
const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : context.c_str();
|
|
||||||
|
|
||||||
int s = create_socket(si.name.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon);
|
|
||||||
if (s >= 0) {
|
|
||||||
PublishSocket(si.name, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Service::SetProcessAttributes() {
|
void Service::SetProcessAttributes() {
|
||||||
// Keep capabilites on uid change.
|
// Keep capabilites on uid change.
|
||||||
if (capabilities_.any() && uid_) {
|
if (capabilities_.any() && uid_) {
|
||||||
|
|
@ -273,11 +250,9 @@ bool Service::Reap() {
|
||||||
KillProcessGroup(SIGKILL);
|
KillProcessGroup(SIGKILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any sockets we may have created.
|
// Remove any descriptor resources we may have created.
|
||||||
for (const auto& si : sockets_) {
|
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||||
std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
|
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
|
||||||
unlink(tmp.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags_ & SVC_EXEC) {
|
if (flags_ & SVC_EXEC) {
|
||||||
LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
|
LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
|
||||||
|
|
@ -330,9 +305,8 @@ void Service::DumpState() const {
|
||||||
LOG(INFO) << "service " << name_;
|
LOG(INFO) << "service " << name_;
|
||||||
LOG(INFO) << " class '" << classname_ << "'";
|
LOG(INFO) << " class '" << classname_ << "'";
|
||||||
LOG(INFO) << " exec "<< android::base::Join(args_, " ");
|
LOG(INFO) << " exec "<< android::base::Join(args_, " ");
|
||||||
for (const auto& si : sockets_) {
|
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||||
LOG(INFO) << " socket " << si.name << " " << si.type << " " << std::oct << si.perm;
|
[] (const auto& info) { LOG(INFO) << *info; });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
|
bool Service::ParseCapabilities(const std::vector<std::string>& args, std::string* err) {
|
||||||
|
|
@ -469,20 +443,48 @@ bool Service::ParseSetenv(const std::vector<std::string>& args, std::string* err
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* name type perm [ uid gid context ] */
|
template <typename T>
|
||||||
|
bool Service::AddDescriptor(const std::vector<std::string>& args, std::string* err) {
|
||||||
|
int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
|
||||||
|
uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
|
||||||
|
gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
|
||||||
|
std::string context = args.size() > 6 ? args[6] : "";
|
||||||
|
|
||||||
|
auto descriptor = std::make_unique<T>(args[1], args[2], uid, gid, perm, context);
|
||||||
|
|
||||||
|
auto old =
|
||||||
|
std::find_if(descriptors_.begin(), descriptors_.end(),
|
||||||
|
[&descriptor] (const auto& other) { return descriptor.get() == other.get(); });
|
||||||
|
|
||||||
|
if (old != descriptors_.end()) {
|
||||||
|
*err = "duplicate descriptor " + args[1] + " " + args[2];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptors_.emplace_back(std::move(descriptor));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// name type perm [ uid gid context ]
|
||||||
bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
|
bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
|
||||||
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
|
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
|
||||||
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
|
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return AddDescriptor<SocketInfo>(args, err);
|
||||||
|
}
|
||||||
|
|
||||||
int perm = std::strtoul(args[3].c_str(), 0, 8);
|
// name type perm [ uid gid context ]
|
||||||
uid_t uid = args.size() > 4 ? decode_uid(args[4].c_str()) : 0;
|
bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
|
||||||
gid_t gid = args.size() > 5 ? decode_uid(args[5].c_str()) : 0;
|
if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
|
||||||
std::string socketcon = args.size() > 6 ? args[6] : "";
|
*err = "file type must be 'r', 'w' or 'rw'";
|
||||||
|
return false;
|
||||||
sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
|
}
|
||||||
return true;
|
if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
|
||||||
|
*err = "file name must not be relative";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return AddDescriptor<FileInfo>(args, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
|
bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
|
||||||
|
|
@ -524,6 +526,7 @@ Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
|
||||||
{"seclabel", {1, 1, &Service::ParseSeclabel}},
|
{"seclabel", {1, 1, &Service::ParseSeclabel}},
|
||||||
{"setenv", {2, 2, &Service::ParseSetenv}},
|
{"setenv", {2, 2, &Service::ParseSetenv}},
|
||||||
{"socket", {3, 6, &Service::ParseSocket}},
|
{"socket", {3, 6, &Service::ParseSocket}},
|
||||||
|
{"file", {2, 6, &Service::ParseFile}},
|
||||||
{"user", {1, 1, &Service::ParseUser}},
|
{"user", {1, 1, &Service::ParseUser}},
|
||||||
{"writepid", {1, kMax, &Service::ParseWritepid}},
|
{"writepid", {1, kMax, &Service::ParseWritepid}},
|
||||||
};
|
};
|
||||||
|
|
@ -613,7 +616,8 @@ bool Service::Start() {
|
||||||
add_environment(ei.name.c_str(), ei.value.c_str());
|
add_environment(ei.name.c_str(), ei.value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateSockets(scon);
|
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||||
|
std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
|
||||||
|
|
||||||
std::string pid_str = StringPrintf("%d", getpid());
|
std::string pid_str = StringPrintf("%d", getpid());
|
||||||
for (const auto& file : writepid_files_) {
|
for (const auto& file : writepid_files_) {
|
||||||
|
|
@ -787,15 +791,6 @@ void Service::OpenConsole() const {
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service::PublishSocket(const std::string& name, int fd) const {
|
|
||||||
std::string key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX "%s", name.c_str());
|
|
||||||
std::string val = StringPrintf("%d", fd);
|
|
||||||
add_environment(key.c_str(), val.c_str());
|
|
||||||
|
|
||||||
/* make sure we don't close-on-exec */
|
|
||||||
fcntl(fd, F_SETFD, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ServiceManager::exec_count_ = 0;
|
int ServiceManager::exec_count_ = 0;
|
||||||
|
|
||||||
ServiceManager::ServiceManager() {
|
ServiceManager::ServiceManager() {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "action.h"
|
#include "action.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
|
#include "descriptors.h"
|
||||||
#include "init_parser.h"
|
#include "init_parser.h"
|
||||||
#include "keyword_map.h"
|
#include "keyword_map.h"
|
||||||
|
|
||||||
|
|
@ -48,18 +49,6 @@
|
||||||
class Action;
|
class Action;
|
||||||
class ServiceManager;
|
class ServiceManager;
|
||||||
|
|
||||||
struct SocketInfo {
|
|
||||||
SocketInfo();
|
|
||||||
SocketInfo(const std::string& name, const std::string& type, uid_t uid,
|
|
||||||
gid_t gid, int perm, const std::string& socketcon);
|
|
||||||
std::string name;
|
|
||||||
std::string type;
|
|
||||||
uid_t uid;
|
|
||||||
gid_t gid;
|
|
||||||
int perm;
|
|
||||||
std::string socketcon;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ServiceEnvironmentInfo {
|
struct ServiceEnvironmentInfo {
|
||||||
ServiceEnvironmentInfo();
|
ServiceEnvironmentInfo();
|
||||||
ServiceEnvironmentInfo(const std::string& name, const std::string& value);
|
ServiceEnvironmentInfo(const std::string& name, const std::string& value);
|
||||||
|
|
@ -113,9 +102,7 @@ private:
|
||||||
void StopOrReset(int how);
|
void StopOrReset(int how);
|
||||||
void ZapStdio() const;
|
void ZapStdio() const;
|
||||||
void OpenConsole() const;
|
void OpenConsole() const;
|
||||||
void PublishSocket(const std::string& name, int fd) const;
|
|
||||||
void KillProcessGroup(int signal);
|
void KillProcessGroup(int signal);
|
||||||
void CreateSockets(const std::string& scon);
|
|
||||||
void SetProcessAttributes();
|
void SetProcessAttributes();
|
||||||
|
|
||||||
bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
|
bool ParseCapabilities(const std::vector<std::string>& args, std::string *err);
|
||||||
|
|
@ -134,9 +121,13 @@ private:
|
||||||
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
|
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
|
||||||
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
|
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
|
||||||
bool ParseSocket(const std::vector<std::string>& args, std::string* err);
|
bool ParseSocket(const std::vector<std::string>& args, std::string* err);
|
||||||
|
bool ParseFile(const std::vector<std::string>& args, std::string* err);
|
||||||
bool ParseUser(const std::vector<std::string>& args, std::string* err);
|
bool ParseUser(const std::vector<std::string>& args, std::string* err);
|
||||||
bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
|
bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
|
||||||
|
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string classname_;
|
std::string classname_;
|
||||||
std::string console_;
|
std::string console_;
|
||||||
|
|
@ -155,7 +146,7 @@ private:
|
||||||
|
|
||||||
std::string seclabel_;
|
std::string seclabel_;
|
||||||
|
|
||||||
std::vector<SocketInfo> sockets_;
|
std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
|
||||||
std::vector<ServiceEnvironmentInfo> envvars_;
|
std::vector<ServiceEnvironmentInfo> envvars_;
|
||||||
|
|
||||||
Action onrestart_; // Commands to execute on restart.
|
Action onrestart_; // Commands to execute on restart.
|
||||||
|
|
|
||||||
|
|
@ -14,32 +14,32 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <ftw.h>
|
#include <unistd.h>
|
||||||
#include <pwd.h>
|
|
||||||
|
|
||||||
#include <selinux/label.h>
|
|
||||||
#include <selinux/android.h>
|
#include <selinux/android.h>
|
||||||
|
#include <selinux/label.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
|
#include <android-base/stringprintf.h>
|
||||||
#include <android-base/strings.h>
|
#include <android-base/strings.h>
|
||||||
|
|
||||||
/* for ANDROID_SOCKET_* */
|
/* for ANDROID_SOCKET_* */
|
||||||
#include <cutils/sockets.h>
|
#include <cutils/sockets.h>
|
||||||
#include <android-base/stringprintf.h>
|
|
||||||
|
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
@ -164,6 +164,76 @@ out_close:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create_file - opens and creates a file as dictated in init.rc.
|
||||||
|
* This file is inherited by the daemon. We communicate the file
|
||||||
|
* descriptor's value via the environment variable ANDROID_FILE_<basename>
|
||||||
|
*/
|
||||||
|
int create_file(const char *path, int flags, mode_t perm, uid_t uid,
|
||||||
|
gid_t gid, const char *filecon)
|
||||||
|
{
|
||||||
|
char *secontext = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (filecon) {
|
||||||
|
if (setsockcreatecon(filecon) == -1) {
|
||||||
|
PLOG(ERROR) << "setsockcreatecon(\"" << filecon << "\") failed";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (sehandle) {
|
||||||
|
ret = selabel_lookup(sehandle, &secontext, path, perm);
|
||||||
|
if (ret != -1) {
|
||||||
|
ret = setfscreatecon(secontext);
|
||||||
|
if (ret == -1) {
|
||||||
|
freecon(secontext);
|
||||||
|
PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm));
|
||||||
|
|
||||||
|
if (filecon) {
|
||||||
|
setsockcreatecon(NULL);
|
||||||
|
lsetfilecon(path, filecon);
|
||||||
|
} else {
|
||||||
|
setfscreatecon(NULL);
|
||||||
|
freecon(secontext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
PLOG(ERROR) << "Failed to open/create file '" << path << "'";
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
|
||||||
|
|
||||||
|
ret = lchown(path, uid, gid);
|
||||||
|
if (ret) {
|
||||||
|
PLOG(ERROR) << "Failed to lchown file '" << path << "'";
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
if (perm != static_cast<mode_t>(-1)) {
|
||||||
|
ret = fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW);
|
||||||
|
if (ret) {
|
||||||
|
PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Created file '" << path << "'"
|
||||||
|
<< ", mode " << std::oct << perm << std::dec
|
||||||
|
<< ", user " << uid
|
||||||
|
<< ", group " << gid;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (fd >= 0) close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
bool read_file(const char* path, std::string* content) {
|
bool read_file(const char* path, std::string* content) {
|
||||||
content->clear();
|
content->clear();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
int create_socket(const char *name, int type, mode_t perm,
|
int create_socket(const char *name, int type, mode_t perm,
|
||||||
uid_t uid, gid_t gid, const char *socketcon);
|
uid_t uid, gid_t gid, const char *socketcon);
|
||||||
|
int create_file(const char *path, int mode, mode_t perm,
|
||||||
|
uid_t uid, gid_t gid, const char *filecon);
|
||||||
|
|
||||||
bool read_file(const char* path, std::string* content);
|
bool read_file(const char* path, std::string* content);
|
||||||
int write_file(const char* path, const char* content);
|
int write_file(const char* path, const char* content);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,15 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cutils/files.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <selinux/android.h>
|
||||||
|
|
||||||
TEST(util, read_file_ENOENT) {
|
TEST(util, read_file_ENOENT) {
|
||||||
std::string s("hello");
|
std::string s("hello");
|
||||||
|
|
@ -41,3 +49,51 @@ TEST(util, decode_uid) {
|
||||||
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
|
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
|
||||||
EXPECT_EQ(123U, decode_uid("123"));
|
EXPECT_EQ(123U, decode_uid("123"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct selabel_handle *sehandle;
|
||||||
|
|
||||||
|
TEST(util, create_file) {
|
||||||
|
if (!sehandle) sehandle = selinux_android_file_context_handle();
|
||||||
|
|
||||||
|
static const char path[] = "/data/local/tmp/util.create_file.test";
|
||||||
|
static const char key[] = ANDROID_FILE_ENV_PREFIX "_data_local_tmp_util_create_file_test";
|
||||||
|
EXPECT_EQ(unsetenv(key), 0);
|
||||||
|
unlink(path);
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
uid_t uid = decode_uid("logd");
|
||||||
|
gid_t gid = decode_uid("system");
|
||||||
|
mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH;
|
||||||
|
static const char context[] = "u:object_r:misc_logd_file:s0";
|
||||||
|
EXPECT_GE(fd = create_file(path, O_RDWR | O_CREAT, perms, uid, gid, context), 0);
|
||||||
|
if (fd < 0) return;
|
||||||
|
static const char hello[] = "hello world\n";
|
||||||
|
static const ssize_t len = strlen(hello);
|
||||||
|
EXPECT_EQ(write(fd, hello, len), len);
|
||||||
|
char buffer[sizeof(hello)];
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
EXPECT_GE(lseek(fd, 0, SEEK_SET), 0);
|
||||||
|
EXPECT_EQ(read(fd, buffer, sizeof(buffer)), len);
|
||||||
|
EXPECT_EQ(strcmp(hello, buffer), 0);
|
||||||
|
char val[32];
|
||||||
|
snprintf(val, sizeof(val), "%d", fd);
|
||||||
|
EXPECT_EQ(android_get_control_file(path), -1);
|
||||||
|
setenv(key, val, true);
|
||||||
|
EXPECT_EQ(android_get_control_file(path), fd);
|
||||||
|
close(fd);
|
||||||
|
EXPECT_EQ(android_get_control_file(path), -1);
|
||||||
|
EXPECT_EQ(unsetenv(key), 0);
|
||||||
|
struct stat st;
|
||||||
|
EXPECT_EQ(stat(path, &st), 0);
|
||||||
|
EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms);
|
||||||
|
EXPECT_EQ(st.st_uid, uid);
|
||||||
|
EXPECT_EQ(st.st_gid, gid);
|
||||||
|
security_context_t con;
|
||||||
|
EXPECT_GE(getfilecon(path, &con), 0);
|
||||||
|
EXPECT_NE(con, static_cast<security_context_t>(NULL));
|
||||||
|
if (con) {
|
||||||
|
EXPECT_EQ(context, std::string(con));
|
||||||
|
}
|
||||||
|
freecon(con);
|
||||||
|
EXPECT_EQ(unlink(path), 0);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue