1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdlib>
17 #include <cstdio>
18 #include <iostream>
19 #include <fstream>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <securec.h>
26 #include <sys/prctl.h>
27 #include <sys/wait.h>
28 #include <sys/mman.h>
29 #include <pwd.h>
30 #include <string>
31 #ifdef SUPPORT_SELINUX_TRANSITTO
32 #include <policycoreutils.h>
33 #include <selinux/selinux.h>
34 #endif
35
36 #include "bundle_mgr_interface.h"
37 #include "bundle_mgr_proxy.h"
38 #include "iservice_registry.h"
39 #include "system_ability_definition.h"
40 #include "system_ability_manager_proxy.h"
41 #include "hilog/log.h"
42
43 using namespace std;
44
45 constexpr OHOS::HiviewDFX::HiLogLabel TRANS_LOG_LABLE = { LOG_CORE, 0xD002D0C, "TRANSITTO" };
46
GetApplicationInfo(const string & bundleName,int & uid)47 bool GetApplicationInfo(const string& bundleName, int& uid)
48 {
49 OHOS::sptr<OHOS::ISystemAbilityManager> systemAbilityManager =
50 OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
51 if (systemAbilityManager == nullptr) {
52 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail to get system abilityManger.");
53 return false;
54 }
55
56 OHOS::sptr<OHOS::IRemoteObject> remoteObject =
57 systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
58 if (remoteObject == nullptr) {
59 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail to get bundle service.");
60 return false;
61 }
62
63 OHOS::sptr<OHOS::AppExecFwk::BundleMgrProxy> bundleMgrProxy =
64 OHOS::iface_cast<OHOS::AppExecFwk::BundleMgrProxy>(remoteObject);
65 if (bundleMgrProxy == nullptr) {
66 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail to get bundle proxy.");
67 return false;
68 }
69
70 OHOS::HiviewDFX::HiLog::Info(TRANS_LOG_LABLE, "start to get ApplicationInfo");
71 // 0: GET_BASIC_APPLICATION_INFO
72 uid = bundleMgrProxy->GetUidByDebugBundleName(bundleName, OHOS::AppExecFwk::Constants::ANY_USERID);
73 if (uid < 0) {
74 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail to get application info, uid is %{public}d.", uid);
75 return false;
76 }
77 OHOS::HiviewDFX::HiLog::Info(TRANS_LOG_LABLE, "get ApplicationInfo success uid is %{private}d.", uid);
78 return true;
79 }
80
ChangeUidGid(int uid,int gid)81 bool ChangeUidGid(int uid, int gid)
82 {
83 OHOS::HiviewDFX::HiLog::Info(TRANS_LOG_LABLE, "start change uid gid.");
84 if (setresgid(gid, gid, gid) < 0) {
85 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail set gid, errno is %{publci}d.", errno);
86 return false;
87 }
88
89 if (setresuid(uid, uid, uid) < 0) {
90 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail set uid, errno is %{publci}d.", errno);
91 return false;
92 }
93 return true;
94 }
95
InitEnv(int uid)96 void InitEnv(int uid)
97 {
98 OHOS::HiviewDFX::HiLog::Info(TRANS_LOG_LABLE, "start set env.");
99
100 unsetenv("IFS");
101
102 passwd* pw = getpwuid(uid);
103 if (pw != nullptr) {
104 setenv("LOGNAME", pw->pw_name, 1);
105 setenv("SHELL", pw->pw_shell, 1);
106 setenv("USER", pw->pw_name, 1);
107 } else {
108 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail to getpwuid, errno is %{public}d.", errno);
109 }
110 return;
111 }
112
SetSelinux()113 bool SetSelinux()
114 {
115 OHOS::HiviewDFX::HiLog::Info(TRANS_LOG_LABLE, "start change selinux context.");
116 string seContext = "u:r:transitto_hap:s0";
117 #ifdef SUPPORT_SELINUX_TRANSITTO
118 if (setcon(seContext.c_str()) != 0) {
119 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "fail to set selinux context, errno is %{public}d.", errno);
120 return false;
121 }
122 #endif
123 OHOS::HiviewDFX::HiLog::Info(TRANS_LOG_LABLE, "change selinux context successfully.");
124 return true;
125 }
126
Help()127 void Help()
128 {
129 cout << "\ntransitto is a debuggable tool. your command can transit to the domain of debuggable bundle.\n"
130 "usage:\n"
131 "transitto <debuggable bundleName> <command>\n" << endl;
132 }
133
CheckValid(int argc,char ** argv)134 bool CheckValid(int argc, char** argv)
135 {
136 if (argc <= 1) {
137 cout << "argc is empty" << endl;
138 Help();
139 return false;
140 }
141
142 string secCom = argv[1];
143 if (argc == 2 && (secCom == "-h" || secCom == "--help")) {
144 Help();
145 return false;
146 }
147
148 int oldUid = getuid();
149 // 0, root, 2000 shell
150 if (oldUid != 0 && oldUid != 2000) {
151 cout << "only root or shell can run this object" << endl;
152 Help();
153 return false;
154 }
155 return true;
156 }
157
main(int argc,char * argv[])158 int main(int argc, char* argv[])
159 {
160 if (!CheckValid(argc, argv)) {
161 return -1;
162 }
163
164 string bundleName = argv[1];
165 int* bundleUidPtr = static_cast<int*>(mmap(nullptr, sizeof(int),
166 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
167 if (bundleUidPtr == MAP_FAILED || bundleUidPtr == nullptr) {
168 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "mmap fail.");
169 return -1;
170 }
171 *bundleUidPtr = -1;
172
173 int pid = fork(); // for security_bounded_transition single thread
174 if (pid == 0) {
175 int uid = -1;
176 GetApplicationInfo(bundleName, uid);
177 *bundleUidPtr = uid;
178 _exit(0);
179 } else {
180 wait(nullptr);
181 }
182
183 int uid = *bundleUidPtr;
184 munmap(bundleUidPtr, sizeof(int));
185
186 string commod = (argc > 2) ? argv[2] : ""; // 2 com
187 // normal_hap uid = 200000 * usrid + bundleid % 200000, userid is 100 or 0(shared)
188 if (uid <= 20000000 || !ChangeUidGid(uid, uid) || !SetSelinux()) {
189 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE, "uid is %{public}d.", uid);
190 return -1;
191 }
192
193 InitEnv(uid);
194 if (argc > 2 && execvp(argv[2], argv + 2) < 0) { // 2: offset
195 OHOS::HiviewDFX::HiLog::Error(TRANS_LOG_LABLE,
196 "fail to execvp, com is %{public}s, errno %{public}d.", argv[2], errno); // 2: offset
197 return -1;
198 }
199
200 execlp("/system/bin/sh", "sh", nullptr);
201 return 0;
202 }