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