1 /*
2  * Copyright (c) 2024 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 "res_sched_exe_service_stub.h"
17 
18 #include <string_ex.h>
19 
20 #include "ipc_skeleton.h"
21 
22 #include "ipc_util.h"
23 #include "res_exe_type.h"
24 #include "res_sched_exe_common_utils.h"
25 #include "res_sched_exe_constants.h"
26 #include "res_sched_exe_log.h"
27 
28 namespace OHOS {
29 namespace ResourceSchedule {
30 namespace {
31     constexpr int32_t PAYLOAD_MAX_SIZE = 4096;
32     constexpr int32_t KILL_PROCESS_FAILED = -1;
33     constexpr int32_t RSS_UID = 1096;
34     const std::string RES_TYPE_EXT = "extType";
35 
IsValidToken(MessageParcel & data)36     bool IsValidToken(MessageParcel& data)
37     {
38         std::u16string descriptor = ResSchedExeServiceStub::GetDescriptor();
39         std::u16string remoteDescriptor = data.ReadInterfaceToken();
40         return descriptor == remoteDescriptor;
41     }
42 
IsTypeVaild(uint32_t type)43     bool IsTypeVaild(uint32_t type)
44     {
45         return type >= ResExeType::RES_TYPE_FIRST && type < ResExeType::RES_TYPE_LAST;
46     }
47 
IsTypeSync(uint32_t type)48     bool IsTypeSync(uint32_t type)
49     {
50         return IsTypeVaild(type) && type < ResExeType::RES_TYPE_SYNC_END;
51     }
52 
IsTypeDebug(uint32_t type)53     bool IsTypeDebug(uint32_t type)
54     {
55         return type == ResExeType::RES_TYPE_DEBUG;
56     }
57 
GetExtResType(uint32_t & resType,const nlohmann::json & context)58     bool GetExtResType(uint32_t& resType, const nlohmann::json& context)
59     {
60         if (resType != ResExeType::RES_TYPE_COMMON_SYNC && resType != ResExeType::RES_TYPE_COMMON_ASYNC) {
61             return true;
62         }
63         int type = 0;
64         if (!context.contains(RES_TYPE_EXT) || !context[RES_TYPE_EXT].is_string()
65             || !StrToInt(context[RES_TYPE_EXT], type)) {
66             RSSEXE_LOGE("use extend resType, but not send resTypeExt with payload");
67             return false;
68         }
69         resType = (uint32_t)type;
70         RSSEXE_LOGD("use extend resType = %{public}d.", resType);
71         return true;
72     }
73 
IsCallingClientRss()74     bool IsCallingClientRss()
75     {
76         int32_t clientUid = IPCSkeleton::GetCallingUid();
77         RSSEXE_LOGD("calling client uid is %{public}d, allowed uid is %{public}d", clientUid, RSS_UID);
78         return RSS_UID == clientUid;
79     }
80 }
81 
ResSchedExeServiceStub()82 ResSchedExeServiceStub::ResSchedExeServiceStub()
83 {
84     Init();
85 }
86 
~ResSchedExeServiceStub()87 ResSchedExeServiceStub::~ResSchedExeServiceStub()
88 {
89 }
90 
Init()91 void ResSchedExeServiceStub::Init()
92 {
93 }
94 
ReportRequestInner(MessageParcel & data,MessageParcel & reply)95 int32_t ResSchedExeServiceStub::ReportRequestInner(MessageParcel& data, MessageParcel& reply)
96 {
97     uint32_t resType = 0;
98     int64_t value = 0;
99     nlohmann::json context;
100     if (!ParseParcel(data, resType, value, context)) {
101         WRITE_PARCEL(reply, Int32, ResIpcErrCode::RSSEXE_DATA_ERROR,
102             ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
103         return ResIpcErrCode::RSSEXE_DATA_ERROR;
104     }
105 
106     int32_t uid = IPCSkeleton::GetCallingUid();
107     int32_t clientPid = IPCSkeleton::GetCallingPid();
108     RSSEXE_LOGD("receive data from ipc resType: %{public}u, value: %{public}lld, uid: %{public}d, pid: %{public}d",
109         resType, (long long)value, uid, clientPid);
110 
111     if (context.size() > PAYLOAD_MAX_SIZE) {
112         RSSEXE_LOGE("The payload is too long. DoS.");
113         WRITE_PARCEL(reply, Int32, ResIpcErrCode::RSSEXE_DATA_ERROR,
114             ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
115         return ResIpcErrCode::RSSEXE_DATA_ERROR;
116     }
117 
118     bool isSync = IsTypeSync(resType);
119     if (!GetExtResType(resType, context)) {
120         WRITE_PARCEL(reply, Int32, ResIpcErrCode::RSSEXE_DATA_ERROR,
121             ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
122         return ResIpcErrCode::RSSEXE_DATA_ERROR;
123     }
124     context["callingUid"] = std::to_string(uid);
125     context["clientPid"] = std::to_string(clientPid);
126 
127     int32_t ret = ResErrCode::RSSEXE_NO_ERR;
128     nlohmann::json result;
129     if (isSync) {
130         ret = SendRequestSync(resType, value, context, result);
131     } else {
132         SendRequestAsync(resType, value, context);
133     }
134     WRITE_PARCEL(reply, Int32, ret, ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
135     WRITE_PARCEL(reply, String, result.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace),
136         ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
137     return ret;
138 }
139 
KillProcessInner(MessageParcel & data,MessageParcel & reply)140 int32_t ResSchedExeServiceStub::KillProcessInner(MessageParcel& data, MessageParcel& reply)
141 {
142     pid_t pid = -1;
143     READ_PARCEL(data, Int32, pid, false, ResSchedExeServiceStub);
144     if (pid <= 0) {
145         WRITE_PARCEL(reply, Int32, KILL_PROCESS_FAILED, ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
146         return ResIpcErrCode::RSSEXE_DATA_ERROR;
147     }
148 
149     int32_t ret = KillProcess(pid);
150     WRITE_PARCEL(reply, Int32, ret, ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
151     return 0;
152 }
153 
ReportDebugInner(MessageParcel & data)154 int32_t ResSchedExeServiceStub::ReportDebugInner(MessageParcel& data)
155 {
156     uint32_t resType = 0;
157     READ_PARCEL(data, Uint32, resType, ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
158     if (!IsTypeDebug(resType)) {
159         return ResIpcErrCode::RSSEXE_DATA_ERROR;
160     }
161 
162     uint64_t curr = ResSchedExeCommonUtils::GetCurrentTimestampUs();
163     uint64_t start;
164     READ_PARCEL(data, Uint64, start, ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
165     RSSEXE_LOGD("IPC debug: server recieve request, current timestamp is %{public}lld.", (long long)curr);
166     RSSEXE_LOGD("IPC debug: server recieve request, cost time is %{public}lld.", (long long)(curr - start));
167     return ResErrCode::RSSEXE_NO_ERR;
168 }
169 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)170 int32_t ResSchedExeServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data,
171     MessageParcel &reply, MessageOption &option)
172 {
173     if (!IsCallingClientRss()) {
174         RSSEXE_LOGE("calling process has no permission!");
175         WRITE_PARCEL(reply, Int32, ResErrCode::RSSEXE_PERMISSION_DENIED,
176             ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
177         return ResErrCode::RSSEXE_PERMISSION_DENIED;
178     }
179 
180     if (!IsValidToken(data)) {
181         RSSEXE_LOGE("token is invalid");
182         WRITE_PARCEL(reply, Int32, ResIpcErrCode::RSSEXE_DATA_ERROR,
183             ResIpcErrCode::RSSEXE_DATA_ERROR, ResSchedExeServiceStub);
184         return ResIpcErrCode::RSSEXE_DATA_ERROR;
185     }
186 
187     RSSEXE_LOGD("code = %{public}u, flags = %{public}d.", code, option.GetFlags());
188 
189     switch (code) {
190         case ResIpcType::REQUEST_SEND_SYNC:
191             return ReportRequestInner(data, reply);
192         case ResIpcType::REQUEST_SEND_ASYNC:
193             return ReportRequestInner(data, reply);
194         case ResIpcType::REQUEST_KILL_PROCESS:
195             return KillProcessInner(data, reply);
196         case ResIpcType::REQUEST_SEND_DEBUG:
197             return ReportDebugInner(data);
198         default:
199             return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
200     }
201 }
202 
ParseParcel(MessageParcel & data,uint32_t & resType,int64_t & value,nlohmann::json & context)203 bool ResSchedExeServiceStub::ParseParcel(MessageParcel& data,
204     uint32_t& resType, int64_t& value, nlohmann::json& context)
205 {
206     READ_PARCEL(data, Uint32, resType, false, ResSchedExeServiceStub);
207     if (!IsTypeVaild(resType)) {
208         RSSEXE_LOGE("type:%{public}d is invalid", resType);
209         return false;
210     }
211 
212     READ_PARCEL(data, Int64, value, false, ResSchedExeServiceStub);
213 
214     std::string payload;
215     READ_PARCEL(data, String, payload, false, ResSchedExeServiceStub);
216     ResSchedExeCommonUtils::StringToJson(payload, context);
217     return true;
218 }
219 } // namespace ResourceSchedule
220 } // namespace OHOS
221 
222