diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 73aa2af01..dc7c3686b 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -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, "", std::to_string(uid), true); + value = StringReplace(value, "", 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 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, "", std::to_string(uid), true); - value = StringReplace(value, "", 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, "", std::to_string(uid), true); - path = StringReplace(path, "", 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, "", std::to_string(uid), true); - value = StringReplace(value, "", 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 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 lock(fd_mutex_); - FdCacheHelper::Cache(path_, fd_); -} - -void WriteFileAction::DropResourceCaching(ResourceCacheType) { - std::lock_guard 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(attr_filepath, attr_value, - logfailures)); + profile->Add(std::make_unique(attr_filepath, attr_procfilepath, + attr_value, logfailures)); } else if (attr_filepath.empty()) { LOG(WARNING) << "WriteFile: invalid parameter: " << "empty filepath"; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index e6e65fb07..9ee3781a6 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -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; };