1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "./context.h"
18
19 #include <private/android_filesystem_config.h> // For AID_APP_START.
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include <iostream>
24 #include <string>
25
26 #include "./string-utils.h"
27 #include "./test-app.h"
28
29 namespace shell_as {
30
31 namespace {
32
ParseIdFromProcStatusLine(char * line,uid_t * id)33 bool ParseIdFromProcStatusLine(char* line, uid_t* id) {
34 // The user and group ID lines of the status file look like:
35 //
36 // Uid: <real> <effective> <saved> <filesystem>
37 // Gid: <real> <effective> <saved> <filesystem>
38 std::vector<uid_t> ids;
39 if (!SplitIdsAndSkip(line, "\t\n ", /*num_to_skip=*/1, &ids) ||
40 ids.size() < 1) {
41 return false;
42 }
43 *id = ids[0];
44 return true;
45 }
46
ParseGroupsFromProcStatusLine(char * line,std::vector<gid_t> * ids)47 bool ParseGroupsFromProcStatusLine(char* line, std::vector<gid_t>* ids) {
48 // The supplementary groups line of the status file looks like:
49 //
50 // Groups: <group1> <group2> <group3> ...
51 return SplitIdsAndSkip(line, "\t\n ", /*num_to_skip=*/1, ids);
52 }
53
ParseProcStatusFile(const pid_t process_id,uid_t * real_user_id,gid_t * real_group_id,std::vector<gid_t> * supplementary_group_ids)54 bool ParseProcStatusFile(const pid_t process_id, uid_t* real_user_id,
55 gid_t* real_group_id,
56 std::vector<gid_t>* supplementary_group_ids) {
57 std::string proc_status_path =
58 std::string("/proc/") + std::to_string(process_id) + "/status";
59 FILE* status_file = fopen(proc_status_path.c_str(), "r");
60 if (status_file == nullptr) {
61 std::cerr << "Unable to open '" << proc_status_path << "'" << std::endl;
62 }
63 bool parsed_user = false;
64 bool parsed_group = false;
65 bool parsed_supplementary_groups = false;
66 while (true) {
67 size_t line_length = 0;
68 char* line = nullptr;
69 if (getline(&line, &line_length, status_file) < 0) {
70 free(line);
71 break;
72 }
73 if (strncmp("Uid:", line, 4) == 0) {
74 parsed_user = ParseIdFromProcStatusLine(line, real_user_id);
75 } else if (strncmp("Gid:", line, 4) == 0) {
76 parsed_group = ParseIdFromProcStatusLine(line, real_group_id);
77 } else if (strncmp("Groups:", line, 7) == 0) {
78 parsed_supplementary_groups =
79 ParseGroupsFromProcStatusLine(line, supplementary_group_ids);
80 }
81 free(line);
82 }
83 fclose(status_file);
84 return parsed_user && parsed_group && parsed_supplementary_groups;
85 }
86
87 } // namespace
88
SecurityContextFromProcess(const pid_t process_id,SecurityContext * context)89 bool SecurityContextFromProcess(const pid_t process_id,
90 SecurityContext* context) {
91 char* selinux_context;
92 if (getpidcon(process_id, &selinux_context) != 0) {
93 std::cerr << "Unable to obtain SELinux context from process " << process_id
94 << std::endl;
95 return false;
96 }
97
98 cap_t capabilities = cap_get_pid(process_id);
99 if (capabilities == nullptr) {
100 std::cerr << "Unable to obtain capability set from process " << process_id
101 << std::endl;
102 return false;
103 }
104
105 uid_t user_id = 0;
106 gid_t group_id = 0;
107 std::vector<gid_t> supplementary_group_ids;
108 if (!ParseProcStatusFile(process_id, &user_id, &group_id,
109 &supplementary_group_ids)) {
110 std::cerr << "Unable to obtain user and group IDs from process "
111 << process_id << std::endl;
112 return false;
113 }
114
115 context->selinux_context = selinux_context;
116 context->user_id = user_id;
117 context->group_id = group_id;
118 context->supplementary_group_ids = supplementary_group_ids;
119 context->capabilities = capabilities;
120 return true;
121 }
122
SecurityContextFromTestApp(SecurityContext * context)123 bool SecurityContextFromTestApp(SecurityContext* context) {
124 pid_t test_app_pid = 0;
125 if (!SetupAndStartTestApp(&test_app_pid)) {
126 std::cerr << "Unable to install test app." << std::endl;
127 return false;
128 }
129 return SecurityContextFromProcess(test_app_pid, context);
130 }
131
SeccompFilterFromUserId(uid_t user_id)132 SeccompFilter SeccompFilterFromUserId(uid_t user_id) {
133 // Copied from:
134 // frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
135 return user_id >= AID_APP_START ? kAppFilter : kSystemFilter;
136 }
137
138 } // namespace shell_as
139