/* * Copyright (C) 2023 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 "./context.h" #include // For AID_APP_START. #include #include #include #include #include "./string-utils.h" #include "./test-app.h" namespace shell_as { namespace { bool ParseIdFromProcStatusLine(char* line, uid_t* id) { // The user and group ID lines of the status file look like: // // Uid: // Gid: std::vector ids; if (!SplitIdsAndSkip(line, "\t\n ", /*num_to_skip=*/1, &ids) || ids.size() < 1) { return false; } *id = ids[0]; return true; } bool ParseGroupsFromProcStatusLine(char* line, std::vector* ids) { // The supplementary groups line of the status file looks like: // // Groups: ... return SplitIdsAndSkip(line, "\t\n ", /*num_to_skip=*/1, ids); } bool ParseProcStatusFile(const pid_t process_id, uid_t* real_user_id, gid_t* real_group_id, std::vector* supplementary_group_ids) { std::string proc_status_path = std::string("/proc/") + std::to_string(process_id) + "/status"; FILE* status_file = fopen(proc_status_path.c_str(), "r"); if (status_file == nullptr) { std::cerr << "Unable to open '" << proc_status_path << "'" << std::endl; } bool parsed_user = false; bool parsed_group = false; bool parsed_supplementary_groups = false; while (true) { size_t line_length = 0; char* line = nullptr; if (getline(&line, &line_length, status_file) < 0) { free(line); break; } if (strncmp("Uid:", line, 4) == 0) { parsed_user = ParseIdFromProcStatusLine(line, real_user_id); } else if (strncmp("Gid:", line, 4) == 0) { parsed_group = ParseIdFromProcStatusLine(line, real_group_id); } else if (strncmp("Groups:", line, 7) == 0) { parsed_supplementary_groups = ParseGroupsFromProcStatusLine(line, supplementary_group_ids); } free(line); } fclose(status_file); return parsed_user && parsed_group && parsed_supplementary_groups; } } // namespace bool SecurityContextFromProcess(const pid_t process_id, SecurityContext* context) { char* selinux_context; if (getpidcon(process_id, &selinux_context) != 0) { std::cerr << "Unable to obtain SELinux context from process " << process_id << std::endl; return false; } cap_t capabilities = cap_get_pid(process_id); if (capabilities == nullptr) { std::cerr << "Unable to obtain capability set from process " << process_id << std::endl; return false; } uid_t user_id = 0; gid_t group_id = 0; std::vector supplementary_group_ids; if (!ParseProcStatusFile(process_id, &user_id, &group_id, &supplementary_group_ids)) { std::cerr << "Unable to obtain user and group IDs from process " << process_id << std::endl; return false; } context->selinux_context = selinux_context; context->user_id = user_id; context->group_id = group_id; context->supplementary_group_ids = supplementary_group_ids; context->capabilities = capabilities; return true; } bool SecurityContextFromTestApp(SecurityContext* context) { pid_t test_app_pid = 0; if (!SetupAndStartTestApp(&test_app_pid)) { std::cerr << "Unable to install test app." << std::endl; return false; } return SecurityContextFromProcess(test_app_pid, context); } SeccompFilter SeccompFilterFromUserId(uid_t user_id) { // Copied from: // frameworks/base/core/jni/com_android_internal_os_Zygote.cpp return user_id >= AID_APP_START ? kAppFilter : kSystemFilter; } } // namespace shell_as