libprocessgroup: implement task profile validity checks
Provide profile validity check functions for cases when user wants to
check whether a profile can be successfully applied before actually
applying it. Add test cases to cover new APIs.
Also add a wrapper function for framework code to call it.
Bug: 277233783
Test: atest task_profiles_test
Test: manually verify freezer with outdated cgroup configuration
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Li Li <dualli@google.com>
Change-Id: Iefb321dead27adbe67721972f164efea213c06cb
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 1731828..44dba2a 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -259,6 +259,31 @@
return true;
}
+bool SetAttributeAction::IsValidForProcess(uid_t, pid_t pid) const {
+ return IsValidForTask(pid);
+}
+
+bool SetAttributeAction::IsValidForTask(int tid) const {
+ std::string path;
+
+ if (!attribute_->GetPathForTask(tid, &path)) {
+ return false;
+ }
+
+ if (!access(path.c_str(), W_OK)) {
+ // operation will succeed
+ return true;
+ }
+
+ if (!access(path.c_str(), F_OK)) {
+ // file exists but not writable
+ return false;
+ }
+
+ // file does not exist, ignore if optional
+ return optional_;
+}
+
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
@@ -396,6 +421,39 @@
FdCacheHelper::Drop(fd_[cache_type]);
}
+bool SetCgroupAction::IsValidForProcess(uid_t uid, pid_t pid) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_PROCESS])) {
+ return true;
+ }
+
+ if (fd_[ProfileAction::RCT_PROCESS] == FdCacheHelper::FDS_INACCESSIBLE) {
+ return false;
+ }
+
+ std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
+ return access(procs_path.c_str(), W_OK) == 0;
+}
+
+bool SetCgroupAction::IsValidForTask(int) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_TASK])) {
+ return true;
+ }
+
+ if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_INACCESSIBLE) {
+ return false;
+ }
+
+ if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ return false;
+ }
+
+ std::string tasks_path = controller()->GetTasksFilePath(path_);
+ return access(tasks_path.c_str(), W_OK) == 0;
+}
+
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) {
@@ -532,6 +590,37 @@
FdCacheHelper::Drop(fd_[cache_type]);
}
+bool WriteFileAction::IsValidForProcess(uid_t, pid_t) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_PROCESS])) {
+ return true;
+ }
+
+ if (fd_[ProfileAction::RCT_PROCESS] == FdCacheHelper::FDS_INACCESSIBLE) {
+ return false;
+ }
+
+ return access(proc_path_.empty() ? task_path_.c_str() : proc_path_.c_str(), W_OK) == 0;
+}
+
+bool WriteFileAction::IsValidForTask(int) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_[ProfileAction::RCT_TASK])) {
+ return true;
+ }
+
+ if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_INACCESSIBLE) {
+ return false;
+ }
+
+ if (fd_[ProfileAction::RCT_TASK] == FdCacheHelper::FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ return false;
+ }
+
+ return access(task_path_.c_str(), W_OK) == 0;
+}
+
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
profile->ExecuteForProcess(uid, pid);
@@ -558,6 +647,24 @@
}
}
+bool ApplyProfileAction::IsValidForProcess(uid_t uid, pid_t pid) const {
+ for (const auto& profile : profiles_) {
+ if (!profile->IsValidForProcess(uid, pid)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ApplyProfileAction::IsValidForTask(int tid) const {
+ for (const auto& profile : profiles_) {
+ if (!profile->IsValidForTask(tid)) {
+ return false;
+ }
+ }
+ return true;
+}
+
void TaskProfile::MoveTo(TaskProfile* profile) {
profile->elements_ = std::move(elements_);
profile->res_cached_ = res_cached_;
@@ -620,6 +727,20 @@
res_cached_ = false;
}
+bool TaskProfile::IsValidForProcess(uid_t uid, pid_t pid) const {
+ for (const auto& element : elements_) {
+ if (!element->IsValidForProcess(uid, pid)) return false;
+ }
+ return true;
+}
+
+bool TaskProfile::IsValidForTask(int tid) const {
+ for (const auto& element : elements_) {
+ if (!element->IsValidForTask(tid)) return false;
+ }
+ return true;
+}
+
void TaskProfiles::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const {
for (auto& iter : profiles_) {
iter.second->DropResourceCaching(cache_type);