Merge "Support process path for WriteFileAction"

This commit is contained in:
Wei Wang 2022-03-01 00:06:57 +00:00 committed by Gerrit Code Review
commit a323e0233d
2 changed files with 95 additions and 49 deletions

View file

@ -350,14 +350,33 @@ void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) {
FdCacheHelper::Drop(fd_[cache_type]);
}
WriteFileAction::WriteFileAction(const std::string& path, const std::string& value,
bool logfailures)
: path_(path), value_(value), logfailures_(logfailures) {
FdCacheHelper::Init(path_, fd_);
WriteFileAction::WriteFileAction(const std::string& task_path, const std::string& proc_path,
const std::string& value, bool logfailures)
: task_path_(task_path), proc_path_(proc_path), value_(value), logfailures_(logfailures) {
FdCacheHelper::Init(task_path_, fd_[ProfileAction::RCT_TASK]);
if (!proc_path_.empty()) FdCacheHelper::Init(proc_path_, fd_[ProfileAction::RCT_PROCESS]);
}
bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path,
bool logfailures) {
bool WriteFileAction::WriteValueToFile(const std::string& value_, ResourceCacheType cache_type,
int uid, int pid, bool logfailures) const {
std::string value(value_);
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(pid), true);
CacheUseResult result = UseCachedFd(cache_type, value);
if (result != ProfileAction::UNUSED) {
return result == ProfileAction::SUCCESS;
}
std::string path;
if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) {
path = task_path_;
} else {
path = proc_path_;
}
// Use WriteStringToFd instead of WriteStringToFile because the latter will open file with
// O_TRUNC which causes kernfs_mutex contention
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
@ -378,21 +397,27 @@ bool WriteFileAction::WriteValueToFile(const std::string& value, const std::stri
ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type,
const std::string& value) const {
std::lock_guard<std::mutex> lock(fd_mutex_);
if (FdCacheHelper::IsCached(fd_)) {
if (FdCacheHelper::IsCached(fd_[cache_type])) {
// fd is cached, reuse it
if (!WriteStringToFd(value, fd_)) {
if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_;
return ProfileAction::FAIL;
bool ret = WriteStringToFd(value, fd_[cache_type]);
if (!ret && logfailures_) {
if (cache_type == ProfileAction::RCT_TASK || proc_path_.empty()) {
PLOG(ERROR) << "Failed to write '" << value << "' to " << task_path_;
} else {
PLOG(ERROR) << "Failed to write '" << value << "' to " << proc_path_;
}
}
return ProfileAction::SUCCESS;
return ret ? ProfileAction::SUCCESS : ProfileAction::FAIL;
}
if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) {
if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) {
// no permissions to access the file, ignore
return ProfileAction::SUCCESS;
}
if (cache_type == ResourceCacheType::RCT_TASK && fd_ == FdCacheHelper::FDS_APP_DEPENDENT) {
if (cache_type == ResourceCacheType::RCT_TASK &&
fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
// application-dependent path can't be used with tid
PLOG(ERROR) << "Application profile can't be applied to a thread";
return ProfileAction::FAIL;
@ -401,46 +426,64 @@ ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cac
}
bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
std::string value(value_);
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(pid), true);
CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, value);
if (result != ProfileAction::UNUSED) {
return result == ProfileAction::SUCCESS;
if (!proc_path_.empty()) {
return WriteValueToFile(value_, ProfileAction::RCT_PROCESS, uid, pid, logfailures_);
}
std::string path(path_);
path = StringReplace(path, "<uid>", std::to_string(uid), true);
path = StringReplace(path, "<pid>", std::to_string(pid), true);
DIR* d;
struct dirent* de;
char proc_path[255];
int t_pid;
return WriteValueToFile(value, path, logfailures_);
sprintf(proc_path, "/proc/%d/task", pid);
if (!(d = opendir(proc_path))) {
return false;
}
while ((de = readdir(d))) {
if (de->d_name[0] == '.') {
continue;
}
t_pid = atoi(de->d_name);
if (!t_pid) {
continue;
}
WriteValueToFile(value_, ProfileAction::RCT_TASK, uid, t_pid, logfailures_);
}
closedir(d);
return true;
}
bool WriteFileAction::ExecuteForTask(int tid) const {
std::string value(value_);
int uid = getuid();
return WriteValueToFile(value_, ProfileAction::RCT_TASK, getuid(), tid, logfailures_);
}
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(tid), true);
CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value);
if (result != ProfileAction::UNUSED) {
return result == ProfileAction::SUCCESS;
void WriteFileAction::EnableResourceCaching(ResourceCacheType cache_type) {
std::lock_guard<std::mutex> lock(fd_mutex_);
if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
return;
}
switch (cache_type) {
case (ProfileAction::RCT_TASK):
FdCacheHelper::Cache(task_path_, fd_[cache_type]);
break;
case (ProfileAction::RCT_PROCESS):
if (!proc_path_.empty()) FdCacheHelper::Cache(proc_path_, fd_[cache_type]);
break;
default:
LOG(ERROR) << "Invalid cache type is specified!";
break;
}
return WriteValueToFile(value, path_, logfailures_);
}
void WriteFileAction::EnableResourceCaching(ResourceCacheType) {
void WriteFileAction::DropResourceCaching(ResourceCacheType cache_type) {
std::lock_guard<std::mutex> lock(fd_mutex_);
FdCacheHelper::Cache(path_, fd_);
}
void WriteFileAction::DropResourceCaching(ResourceCacheType) {
std::lock_guard<std::mutex> lock(fd_mutex_);
FdCacheHelper::Drop(fd_);
FdCacheHelper::Drop(fd_[cache_type]);
}
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
@ -659,12 +702,14 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
}
} else if (action_name == "WriteFile") {
std::string attr_filepath = params_val["FilePath"].asString();
std::string attr_procfilepath = params_val["ProcFilePath"].asString();
std::string attr_value = params_val["Value"].asString();
// FilePath and Value are mandatory
if (!attr_filepath.empty() && !attr_value.empty()) {
std::string attr_logfailures = params_val["LogFailures"].asString();
bool logfailures = attr_logfailures.empty() || attr_logfailures == "true";
profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value,
logfailures));
profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_procfilepath,
attr_value, logfailures));
} else if (attr_filepath.empty()) {
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty filepath";

View file

@ -140,7 +140,8 @@ class SetCgroupAction : public ProfileAction {
// Write to file action
class WriteFileAction : public ProfileAction {
public:
WriteFileAction(const std::string& path, const std::string& value, bool logfailures);
WriteFileAction(const std::string& task_path, const std::string& proc_path,
const std::string& value, bool logfailures);
const char* Name() const override { return "WriteFile"; }
bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
@ -149,13 +150,13 @@ class WriteFileAction : public ProfileAction {
void DropResourceCaching(ResourceCacheType cache_type) override;
private:
std::string path_, value_;
std::string task_path_, proc_path_, value_;
bool logfailures_;
android::base::unique_fd fd_;
android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
mutable std::mutex fd_mutex_;
static bool WriteValueToFile(const std::string& value, const std::string& path,
bool logfailures);
bool WriteValueToFile(const std::string& value, ResourceCacheType cache_type, int uid, int pid,
bool logfailures) const;
CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
};