Merge changes I432016e2,Id208b11b,Ia6a38729,Icdaf9e35,I842a7a64, ...

* changes:
  logd: if eng build, be a bit more permissive about failures
  libcutils: klog inherit android_get_control_file("/dev/kmsg")
  logd: start logd service in logd uid
  logd: auditd + klogd control CAPS
  logd: drop capabilities in logd --reinit and logd.daemon
  logd: drop libminijail dependency
  logd: start logd services in logd gid
  logd: set executable's capabilities in file system
  logd: inherit android_get_control_file()
  init: service file keyword
  libcutils: add android_get_control_file()
  libcutils: add android_get_control_socket() test
This commit is contained in:
Treehugger Robot 2016-11-04 14:38:22 +00:00 committed by Gerrit Code Review
commit fc3e90689e
21 changed files with 845 additions and 165 deletions

37
include/cutils/files.h Normal file
View file

@ -0,0 +1,37 @@
/*
* 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 __CUTILS_FILES_H
#define __CUTILS_FILES_H
#define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_"
#ifdef __cplusplus
extern "C" {
#endif
/*
* android_get_control_file - simple helper function to get the file
* descriptor of our init-managed file. `path' is the filename path as
* given in init.rc. Returns -1 on error.
*/
int android_get_control_file(const char* path);
#ifdef __cplusplus
}
#endif
#endif /* __CUTILS_FILES_H */

View file

@ -46,6 +46,7 @@ LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
action.cpp \
capabilities.cpp \
descriptors.cpp \
import_parser.cpp \
init_parser.cpp \
log.cpp \
@ -125,8 +126,10 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES += \
libcutils \
libbase \
libselinux \
LOCAL_STATIC_LIBRARIES := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
LOCAL_CPPFLAGS := -Wall -Wextra -Werror
include $(BUILD_NATIVE_TEST)

104
init/descriptors.cpp Normal file
View 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
View 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

View file

@ -141,12 +141,20 @@ setenv <name> <value>
Set the environment variable <name> to <value> in the launched process.
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 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.
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
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.
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>
Change to 'username' before exec'ing this service.

View file

@ -36,7 +36,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
#include <system/thread_defs.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);
}
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() {
}
@ -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() {
// Keep capabilites on uid change.
if (capabilities_.any() && uid_) {
@ -273,11 +250,9 @@ bool Service::Reap() {
KillProcessGroup(SIGKILL);
}
// Remove any sockets we may have created.
for (const auto& si : sockets_) {
std::string tmp = StringPrintf(ANDROID_SOCKET_DIR "/%s", si.name.c_str());
unlink(tmp.c_str());
}
// Remove any descriptor resources we may have created.
std::for_each(descriptors_.begin(), descriptors_.end(),
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
if (flags_ & SVC_EXEC) {
LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
@ -330,9 +305,8 @@ void Service::DumpState() const {
LOG(INFO) << "service " << name_;
LOG(INFO) << " class '" << classname_ << "'";
LOG(INFO) << " exec "<< android::base::Join(args_, " ");
for (const auto& si : sockets_) {
LOG(INFO) << " socket " << si.name << " " << si.type << " " << std::oct << si.perm;
}
std::for_each(descriptors_.begin(), descriptors_.end(),
[] (const auto& info) { LOG(INFO) << *info; });
}
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;
}
/* 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) {
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
return false;
}
return AddDescriptor<SocketInfo>(args, err);
}
int perm = std::strtoul(args[3].c_str(), 0, 8);
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 socketcon = args.size() > 6 ? args[6] : "";
sockets_.emplace_back(args[1], args[2], uid, gid, perm, socketcon);
return true;
// name type perm [ uid gid context ]
bool Service::ParseFile(const std::vector<std::string>& args, std::string* err) {
if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
*err = "file type must be 'r', 'w' or 'rw'";
return false;
}
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) {
@ -524,6 +526,7 @@ Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
{"socket", {3, 6, &Service::ParseSocket}},
{"file", {2, 6, &Service::ParseFile}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
@ -613,7 +616,8 @@ bool Service::Start() {
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());
for (const auto& file : writepid_files_) {
@ -787,15 +791,6 @@ void Service::OpenConsole() const {
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;
ServiceManager::ServiceManager() {

View file

@ -27,6 +27,7 @@
#include "action.h"
#include "capabilities.h"
#include "descriptors.h"
#include "init_parser.h"
#include "keyword_map.h"
@ -48,18 +49,6 @@
class Action;
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 {
ServiceEnvironmentInfo();
ServiceEnvironmentInfo(const std::string& name, const std::string& value);
@ -113,9 +102,7 @@ private:
void StopOrReset(int how);
void ZapStdio() const;
void OpenConsole() const;
void PublishSocket(const std::string& name, int fd) const;
void KillProcessGroup(int signal);
void CreateSockets(const std::string& scon);
void SetProcessAttributes();
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 ParseSetenv(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 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 classname_;
std::string console_;
@ -155,7 +146,7 @@ private:
std::string seclabel_;
std::vector<SocketInfo> sockets_;
std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
std::vector<ServiceEnvironmentInfo> envvars_;
Action onrestart_; // Commands to execute on restart.

View file

@ -14,32 +14,32 @@
* limitations under the License.
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <ftw.h>
#include <pwd.h>
#include <unistd.h>
#include <selinux/label.h>
#include <selinux/android.h>
#include <selinux/label.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
#include <android-base/stringprintf.h>
#include "init.h"
#include "log.h"
@ -164,6 +164,76 @@ out_close:
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) {
content->clear();

View file

@ -27,6 +27,8 @@
int create_socket(const char *name, int type, mode_t perm,
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);
int write_file(const char* path, const char* content);

View file

@ -17,7 +17,15 @@
#include "util.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 <selinux/android.h>
TEST(util, read_file_ENOENT) {
std::string s("hello");
@ -41,3 +49,51 @@ TEST(util, decode_uid) {
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
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);
}

View file

@ -34,6 +34,7 @@ cc_library {
host_supported: true,
srcs: [
"config_utils.c",
"files.cpp",
"fs_config.c",
"canned_fs_config.c",
"hashmap.c",

111
libcutils/files.cpp Normal file
View file

@ -0,0 +1,111 @@
/*
* Copyright (C) 2016 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// This file contains files implementation that can be shared between
// platforms as long as the correct headers are included.
#define _GNU_SOURCE 1 // for asprintf
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cutils/files.h>
#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
#define TEMP_FAILURE_RETRY(exp) (exp)
#endif
int android_get_control_file(const char* path) {
if (!path) return -1;
char *key = NULL;
if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 0) return -1;
if (!key) return -1;
char *cp = key;
while (*cp) {
if (!isalnum(*cp)) *cp = '_';
++cp;
}
const char* val = getenv(key);
free(key);
if (!val) return -1;
errno = 0;
long fd = strtol(val, NULL, 10);
if (errno) return -1;
// validity checking
if ((fd < 0) || (fd > INT_MAX)) return -1;
#if defined(_SC_OPEN_MAX)
if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
#elif defined(OPEN_MAX)
if (fd >= OPEN_MAX) return -1;
#elif defined(_POSIX_OPEN_MAX)
if (fd >= _POSIX_OPEN_MAX) return -1;
#endif
#if defined(F_GETFD)
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
#elif defined(F_GETFL)
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
#else
struct stat s;
if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
#endif
#if defined(__linux__)
char *proc = NULL;
if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1;
if (!proc) return -1;
size_t len = strlen(path);
char *buf = static_cast<char *>(calloc(1, len + 2));
if (!buf) {
free(proc);
return -1;
}
ssize_t ret = TEMP_FAILURE_RETRY(readlink(proc, buf, len + 1));
free(proc);
int cmp = (len != static_cast<size_t>(ret)) || strcmp(buf, path);
free(buf);
if (ret < 0) return -1;
if (cmp != 0) return -1;
#endif
// It is what we think it is
return static_cast<int>(fd);
}

View file

@ -139,23 +139,35 @@ static const struct fs_path_config android_files[] = {
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" },
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" },
{ 00550, AID_LOGD, AID_LOGD, CAP_MASK_LONG(CAP_SYSLOG) |
CAP_MASK_LONG(CAP_AUDIT_CONTROL) |
CAP_MASK_LONG(CAP_SETGID),
"system/bin/logd" },
{ 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) |
CAP_MASK_LONG(CAP_SETGID),
"system/bin/run-as" },
{ 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND),
"system/bin/inputflinger" },
/* Support hostapd administering a network interface. */
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW), "system/bin/hostapd" },
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW),
"system/bin/hostapd" },
/* Support wifi_hal_legacy administering a network interface. */
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) | CAP_MASK_LONG(CAP_NET_RAW), "system/bin/hw/android.hardware.wifi@1.0-service" },
{ 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) |
CAP_MASK_LONG(CAP_NET_RAW),
"system/bin/hw/android.hardware.wifi@1.0-service" },
/* A non-privileged zygote that spawns isolated processes for web rendering. */
{ 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
CAP_MASK_LONG(CAP_SETGID) |
CAP_MASK_LONG(CAP_SETPCAP), "system/bin/webview_zygote32" },
CAP_MASK_LONG(CAP_SETPCAP),
"system/bin/webview_zygote32" },
{ 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) |
CAP_MASK_LONG(CAP_SETGID) |
CAP_MASK_LONG(CAP_SETPCAP), "system/bin/webview_zygote64" },
CAP_MASK_LONG(CAP_SETPCAP),
"system/bin/webview_zygote64" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },

View file

@ -24,6 +24,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <cutils/files.h>
#include <cutils/klog.h>
static int klog_level = KLOG_DEFAULT_LEVEL;
@ -37,7 +38,11 @@ void klog_set_level(int level) {
}
static int __open_klog(void) {
return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
static const char kmsg_device[] = "/dev/kmsg";
int ret = android_get_control_file(kmsg_device);
if (ret >= 0) return ret;
return TEMP_FAILURE_RETRY(open(kmsg_device, O_WRONLY | O_CLOEXEC));
}
#define LOG_BUF_MAX 512

View file

@ -28,11 +28,31 @@
// This file contains socket implementation that can be shared between
// platforms as long as the correct headers are included.
#define _GNU_SOURCE 1 // For asprintf
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#if !defined(_WIN32)
#include <netinet/in.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(_WIN32)
#include <sys/un.h>
#endif
#include <unistd.h>
#include <string>
#include <cutils/sockets.h>
#if !defined(_WIN32)
#include <netinet/in.h>
#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define
#define TEMP_FAILURE_RETRY(exp) (exp)
#endif
int socket_get_local_port(cutils_socket_t sock) {
@ -47,22 +67,56 @@ int socket_get_local_port(cutils_socket_t sock) {
}
int android_get_control_socket(const char* name) {
char key[64];
snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
char *key = NULL;
if (asprintf(&key, ANDROID_SOCKET_ENV_PREFIX "%s", name) < 0) return -1;
if (!key) return -1;
char *cp = key;
while (*cp) {
if (!isalnum(*cp)) *cp = '_';
++cp;
}
const char* val = getenv(key);
if (!val) {
return -1;
}
free(key);
if (!val) return -1;
errno = 0;
long ret = strtol(val, NULL, 10);
if (errno) {
return -1;
}
if (ret < 0 || ret > INT_MAX) {
return -1;
}
long fd = strtol(val, NULL, 10);
if (errno) return -1;
return static_cast<int>(ret);
// validity checking
if ((fd < 0) || (fd > INT_MAX)) return -1;
#if defined(_SC_OPEN_MAX)
if (fd >= sysconf(_SC_OPEN_MAX)) return -1;
#elif defined(OPEN_MAX)
if (fd >= OPEN_MAX) return -1;
#elif defined(_POSIX_OPEN_MAX)
if (fd >= _POSIX_OPEN_MAX) return -1;
#endif
#if defined(F_GETFD)
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1;
#elif defined(F_GETFL)
if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1;
#else
struct stat s;
if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1;
#endif
#if !defined(_WIN32)
struct sockaddr_un addr;
socklen_t addrlen = sizeof(addr);
int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
if (ret < 0) return -1;
char *path = NULL;
if (asprintf(&path, ANDROID_SOCKET_DIR"/%s", name) < 0) return -1;
if (!path) return -1;
int cmp = strcmp(addr.sun_path, path);
free(path);
if (cmp != 0) return -1;
#endif
// It is what we think it is
return static_cast<int>(fd);
}

View file

@ -14,7 +14,7 @@
cc_defaults {
name: "libcutils_test_default",
srcs: ["sockets_test.cpp"],
srcs: ["sockets_test.cpp", "files_test.cpp"],
target: {
android: {

View file

@ -0,0 +1,46 @@
/*
* 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 <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <cutils/files.h>
#include <gtest/gtest.h>
TEST(FilesTest, android_get_control_file) {
static const char key[] = ANDROID_FILE_ENV_PREFIX "_dev_kmsg";
static const char name[] = "/dev/kmsg";
EXPECT_EQ(unsetenv(key), 0);
EXPECT_EQ(android_get_control_file(name), -1);
int fd;
ASSERT_GE(fd = open(name, O_RDONLY | O_CLOEXEC), 0);
EXPECT_EQ(android_get_control_file(name), -1);
char val[32];
snprintf(val, sizeof(val), "%d", fd);
EXPECT_EQ(setenv(key, val, true), 0);
EXPECT_EQ(android_get_control_file(name), fd);
close(fd);
EXPECT_EQ(android_get_control_file(name), -1);
EXPECT_EQ(unsetenv(key), 0);
EXPECT_EQ(android_get_control_file(name), -1);
}

View file

@ -18,10 +18,14 @@
// IPv6 capabilities. These tests assume that no UDP packets are lost, which
// should be the case for loopback communication, but is not guaranteed.
#include <cutils/sockets.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <time.h>
#include <cutils/sockets.h>
#include <gtest/gtest.h>
// Makes sure the passed sockets are valid, sends data between them, and closes
@ -185,3 +189,36 @@ TEST(SocketsTest, TestTcpReceiveTimeout) {
TEST(SocketsTest, TestSocketSendBuffersFailure) {
EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
}
TEST(SocketsTest, android_get_control_socket) {
static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest.android_get_control_socket";
static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX);
EXPECT_EQ(unsetenv(key), 0);
EXPECT_EQ(android_get_control_socket(name), -1);
int fd;
ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0);
EXPECT_EQ(android_get_control_socket(name), -1);
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);
unlink(addr.sun_path);
EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0);
EXPECT_EQ(android_get_control_socket(name), -1);
char val[32];
snprintf(val, sizeof(val), "%d", fd);
EXPECT_EQ(setenv(key, val, true), 0);
EXPECT_EQ(android_get_control_socket(name), fd);
socket_close(fd);
EXPECT_EQ(android_get_control_socket(name), -1);
EXPECT_EQ(unlink(addr.sun_path), 0);
EXPECT_EQ(android_get_control_socket(name), -1);
EXPECT_EQ(unsetenv(key), 0);
EXPECT_EQ(android_get_control_socket(name), -1);
}

View file

@ -29,7 +29,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libbase \
libpackagelistparser \
libminijail
libcap
# This is what we want to do:
# event_logtags = $(shell \

View file

@ -2,10 +2,15 @@ service logd /system/bin/logd
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
group root system readproc
file /proc/kmsg r
file /dev/kmsg w
user logd
group logd system readproc
writepid /dev/cpuset/system-background/tasks
service logd-reinit /system/bin/logd --reinit
oneshot
disabled
user logd
group logd
writepid /dev/cpuset/system-background/tasks

View file

@ -39,13 +39,12 @@
#include <android-base/macros.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/files.h>
#include <cutils/sockets.h>
#include <libminijail.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include <scoped_minijail.h>
#include <utils/threads.h>
#include "CommandListener.h"
@ -90,34 +89,81 @@
// logd
//
static int drop_privs() {
static int drop_privs(bool klogd, bool auditd) {
// Tricky, if ro.build.type is "eng" then this is true because of the
// side effect that ro.debuggable == 1 as well, else it is false.
bool eng = __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);
struct sched_param param;
memset(&param, 0, sizeof(param));
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
return -1;
android::prdebug("failed to set background scheduling policy");
if (!eng) return -1;
}
if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
return -1;
android::prdebug("failed to set batch scheduler");
if (!eng) return -1;
}
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
return -1;
android::prdebug("failed to set background cgroup");
if (!eng) return -1;
}
if (prctl(PR_SET_DUMPABLE, 0) < 0) {
if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
android::prdebug("failed to clear PR_SET_DUMPABLE");
return -1;
}
if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
android::prdebug("failed to set PR_SET_KEEPCAPS");
if (!eng) return -1;
}
std::unique_ptr<struct _cap_struct, int(*)(void *)> caps(cap_init(), cap_free);
if (cap_clear(caps.get()) < 0) return -1;
cap_value_t cap_value[] = {
CAP_SETGID, // must be first for below
klogd ? CAP_SYSLOG : CAP_SETGID,
auditd ? CAP_AUDIT_CONTROL : CAP_SETGID
};
if (cap_set_flag(caps.get(), CAP_PERMITTED,
arraysize(cap_value), cap_value,
CAP_SET) < 0) return -1;
if (cap_set_flag(caps.get(), CAP_EFFECTIVE,
arraysize(cap_value), cap_value,
CAP_SET) < 0) return -1;
if (cap_set_proc(caps.get()) < 0) {
android::prdebug("failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
if (!eng) return -1;
}
gid_t groups[] = { AID_READPROC };
ScopedMinijail j(minijail_new());
minijail_set_supplementary_gids(j.get(), arraysize(groups), groups);
minijail_change_uid(j.get(), AID_LOGD);
minijail_change_gid(j.get(), AID_LOGD);
minijail_use_caps(j.get(), CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_AUDIT_CONTROL));
minijail_enter(j.get());
if (setgroups(arraysize(groups), groups) == -1) {
android::prdebug("failed to set AID_READPROC groups");
if (!eng) return -1;
}
if (setgid(AID_LOGD) != 0) {
android::prdebug("failed to set AID_LOGD gid");
if (!eng) return -1;
}
if (setuid(AID_LOGD) != 0) {
android::prdebug("failed to set AID_LOGD uid");
if (!eng) return -1;
}
if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) return -1;
if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) return -1;
if (cap_set_proc(caps.get()) < 0) {
android::prdebug("failed to clear CAP_SETGID (%d)", errno);
if (!eng) return -1;
}
return 0;
}
@ -189,11 +235,16 @@ static void *reinit_thread_start(void * /*obj*/) {
set_sched_policy(0, SP_BACKGROUND);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
// If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
// else, we have even lesser privileges and accept our fate. Not worth
// checking for error returns setting this thread's privileges.
(void)setgid(AID_SYSTEM);
(void)setuid(AID_SYSTEM);
cap_t caps = cap_init();
(void)cap_clear(caps);
(void)cap_set_proc(caps);
(void)cap_free(caps);
// If we are AID_ROOT, we should drop to AID_LOGD+AID_SYSTEM, if we are
// anything else, we have even lesser privileges and accept our fate. Not
// worth checking for error returns setting this thread's privileges.
(void)setgid(AID_SYSTEM); // readonly access to /data/system/packages.list
(void)setuid(AID_LOGD); // access to everything logd.
while (reinit_running && !sem_wait(&reinit) && reinit_running) {
@ -311,6 +362,39 @@ static void readDmesg(LogAudit *al, LogKlog *kl) {
}
}
static int issueReinit() {
cap_t caps = cap_init();
(void)cap_clear(caps);
(void)cap_set_proc(caps);
(void)cap_free(caps);
int sock = TEMP_FAILURE_RETRY(
socket_local_client("logd",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM));
if (sock < 0) return -errno;
static const char reinitStr[] = "reinit";
ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
if (ret < 0) return -errno;
struct pollfd p;
memset(&p, 0, sizeof(p));
p.fd = sock;
p.events = POLLIN;
ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
if (ret < 0) return -errno;
if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
static const char success[] = "success";
char buffer[sizeof(success) - 1];
memset(buffer, 0, sizeof(buffer));
ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
if (ret < 0) return -errno;
return strncmp(buffer, success, sizeof(success) - 1) != 0;
}
// Foreground waits for exit of the main persistent threads
// that are started here. The threads are created to manage
// UNIX domain client sockets for writing, reading and
@ -318,6 +402,17 @@ static void readDmesg(LogAudit *al, LogKlog *kl) {
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
int main(int argc, char *argv[]) {
// issue reinit command. KISS argument parsing.
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
return issueReinit();
}
static const char dev_kmsg[] = "/dev/kmsg";
fdDmesg = android_get_control_file(dev_kmsg);
if (fdDmesg < 0) {
fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
}
int fdPmesg = -1;
bool klogd = __android_logger_property_get_bool("logd.kernel",
BOOL_DEFAULT_TRUE |
@ -325,43 +420,13 @@ int main(int argc, char *argv[]) {
BOOL_DEFAULT_FLAG_ENG |
BOOL_DEFAULT_FLAG_SVELTE);
if (klogd) {
fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
}
fdDmesg = open("/dev/kmsg", O_WRONLY);
// issue reinit command. KISS argument parsing.
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
int sock = TEMP_FAILURE_RETRY(
socket_local_client("logd",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM));
if (sock < 0) {
return -errno;
static const char proc_kmsg[] = "/proc/kmsg";
fdPmesg = android_get_control_file(proc_kmsg);
if (fdPmesg < 0) {
fdPmesg = TEMP_FAILURE_RETRY(open(proc_kmsg,
O_RDONLY | O_NDELAY | O_CLOEXEC));
}
static const char reinit[] = "reinit";
ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit)));
if (ret < 0) {
return -errno;
}
struct pollfd p;
memset(&p, 0, sizeof(p));
p.fd = sock;
p.events = POLLIN;
ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
if (ret < 0) {
return -errno;
}
if ((ret == 0) || !(p.revents & POLLIN)) {
return -ETIME;
}
static const char success[] = "success";
char buffer[sizeof(success) - 1];
memset(buffer, 0, sizeof(buffer));
ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
if (ret < 0) {
return -errno;
}
return strncmp(buffer, success, sizeof(success) - 1) != 0;
if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
}
// Reinit Thread
@ -386,7 +451,10 @@ int main(int argc, char *argv[]) {
pthread_attr_destroy(&attr);
}
if (drop_privs() != 0) {
bool auditd = __android_logger_property_get_bool("logd.auditd",
BOOL_DEFAULT_TRUE |
BOOL_DEFAULT_FLAG_PERSIST);
if (drop_privs(klogd, auditd) != 0) {
return -1;
}
@ -441,9 +509,6 @@ int main(int argc, char *argv[]) {
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
bool auditd = __android_logger_property_get_bool("logd.auditd",
BOOL_DEFAULT_TRUE |
BOOL_DEFAULT_FLAG_PERSIST);
LogAudit *al = NULL;
if (auditd) {
al = new LogAudit(logBuf, reader,