1 /*
2  * Copyright (c) 2022 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 "dslm_ipc_process.h"
17 
18 #include <map>
19 #include <utility>
20 
21 #include "ipc_skeleton.h"
22 #include "iremote_broker.h"
23 #include "securec.h"
24 
25 #include "dslm_callback_info.h"
26 #include "dslm_callback_proxy.h"
27 #include "dslm_core_process.h"
28 #include "dslm_device_list.h"
29 #include "utils_log.h"
30 
31 namespace {
32 constexpr uint32_t DFT_TIMEOUT = 45;
33 constexpr uint32_t MAX_TIMEOUT = 60;
34 constexpr uint32_t MIN_TIMEOUT = 1;
35 constexpr uint32_t WARNING_GATE = 64;
36 constexpr uint32_t COOKIE_SHIFT = 32;
37 constexpr uint32_t UNLOAD_TIMEOUT = 10000;
38 } // namespace
39 
40 namespace OHOS {
41 namespace Security {
42 namespace DeviceSecurityLevel {
ProcessCallback(uint32_t owner,uint32_t cookie,uint32_t result,const DslmCallbackInfo * info)43 static void ProcessCallback(uint32_t owner, uint32_t cookie, uint32_t result, const DslmCallbackInfo *info)
44 {
45     if ((cookie == 0) || (info == nullptr)) {
46         return;
47     }
48     auto object = Singleton<DslmIpcProcess::RemoteHolder>::GetInstance().Pop(owner, cookie);
49     if (object == nullptr) {
50         SECURITY_LOG_ERROR("Pop failed");
51         return;
52     }
53 
54     auto proxy = iface_cast<DslmCallbackProxy>(object);
55     if (proxy == nullptr) {
56         SECURITY_LOG_ERROR("iface_cast failed");
57         return;
58     }
59     DslmCallbackProxy::ResponseInfo resInfo = {result, info->level, info->extraBuff, info->extraLen};
60     proxy->ResponseDeviceSecurityLevel(cookie, resInfo);
61 }
62 
DslmGetRequestFromParcel(MessageParcel & data,DeviceIdentify & identify,RequestOption & option,sptr<IRemoteObject> & object,uint32_t & cookie)63 int32_t DslmIpcProcess::DslmGetRequestFromParcel(MessageParcel &data, DeviceIdentify &identify, RequestOption &option,
64     sptr<IRemoteObject> &object, uint32_t &cookie)
65 {
66     uint32_t expected = sizeof(DeviceIdentify) + sizeof(RequestOption) + sizeof(uint32_t);
67     uint32_t actual = data.GetReadableBytes();
68     if (expected >= actual) {
69         SECURITY_LOG_ERROR("unexpected input, length error");
70         return ERR_INVALID_PARA;
71     }
72 
73     identify.length = data.ReadUint32();
74 
75     const uint8_t *dataRead = data.ReadBuffer(DEVICE_ID_MAX_LEN);
76     if (dataRead == nullptr) {
77         SECURITY_LOG_ERROR("unexpected input, buffer error");
78         return ERR_INVALID_PARA;
79     }
80     if (memcpy_s(identify.identity, DEVICE_ID_MAX_LEN, dataRead, DEVICE_ID_MAX_LEN) != EOK) {
81         SECURITY_LOG_ERROR("unexpected input, buffer copy error");
82         return ERR_INVALID_PARA;
83     }
84 
85     option.challenge = data.ReadUint64();
86     option.timeout = data.ReadUint32();
87     if (option.timeout < MIN_TIMEOUT || option.timeout > MAX_TIMEOUT) {
88         option.timeout = DFT_TIMEOUT;
89     }
90 
91     option.extra = data.ReadUint32();
92 
93     object = data.ReadRemoteObject();
94     if (object == nullptr) {
95         SECURITY_LOG_ERROR("unexpected input, callback ipc error");
96         return ERR_INVALID_PARA;
97     }
98     cookie = data.ReadUint32();
99     if (cookie == 0) {
100         SECURITY_LOG_ERROR("unexpected input, cookie error");
101         return ERR_INVALID_PARA;
102     }
103 
104     return SUCCESS;
105 }
106 
DslmSetResponseToParcel(MessageParcel & reply,uint32_t status)107 int32_t DslmIpcProcess::DslmSetResponseToParcel(MessageParcel &reply, uint32_t status)
108 {
109     auto success = reply.WriteUint32(status);
110     if (!success) {
111         return ERR_IPC_RET_PARCEL_ERR;
112     }
113     return SUCCESS;
114 }
115 
TimerProcessUnloadSystemAbility(const void * context)116 static void TimerProcessUnloadSystemAbility(const void *context)
117 {
118     (void)context;
119 
120     if (!JudgeListDeviceType()) {
121         return;
122     }
123 
124     auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
125     if (samgrProxy == nullptr) {
126         SECURITY_LOG_ERROR("get samgr failed");
127         return;
128     }
129 
130     int32_t ret = samgrProxy->UnloadSystemAbility(DEVICE_SECURITY_LEVEL_MANAGER_SA_ID);
131     if (ret != ERR_OK) {
132         SECURITY_LOG_ERROR("unload system ability failed");
133         return;
134     }
135     SECURITY_LOG_INFO("unload system ability succeed");
136 }
137 
SetSystemAbilityUnloadSchedule(TimerHandle & handle)138 static void SetSystemAbilityUnloadSchedule(TimerHandle &handle)
139 {
140     if (!JudgeListDeviceType()) {
141         return;
142     }
143 
144     if (handle != 0) {
145         DslmUtilsStopTimerTask(handle);
146     }
147 
148     handle = DslmUtilsStartOnceTimerTask(UNLOAD_TIMEOUT, TimerProcessUnloadSystemAbility, nullptr);
149 }
150 
DslmProcessGetDeviceSecurityLevel(MessageParcel & data,MessageParcel & reply)151 int32_t DslmIpcProcess::DslmProcessGetDeviceSecurityLevel(MessageParcel &data, MessageParcel &reply)
152 {
153     DeviceIdentify identity;
154     RequestOption option;
155     sptr<IRemoteObject> callback;
156     uint32_t cookie;
157 
158     SetSystemAbilityUnloadSchedule(unloadTimerHandle_);
159 
160     int32_t ret = DslmGetRequestFromParcel(data, identity, option, callback, cookie);
161     if (ret != SUCCESS) {
162         SECURITY_LOG_ERROR("DslmGetRequestFromParcel failed, ret = %{public}d", ret);
163         return ret;
164     }
165 
166     auto owner = IPCSkeleton::GetCallingPid();
167     Singleton<RemoteHolder>::GetInstance().Push(owner, cookie, callback);
168 
169     ret = OnRequestDeviceSecLevelInfo(&identity, &option, owner, cookie, ProcessCallback);
170     if (ret != SUCCESS) {
171         Singleton<RemoteHolder>::GetInstance().Pop(owner, cookie);
172         SECURITY_LOG_ERROR("OnRequestDeviceSecLevelInfo failed, ret = %{public}d", ret);
173         return ret;
174     }
175 
176     ret = DslmSetResponseToParcel(reply, cookie);
177     if (ret != SUCCESS) {
178         Singleton<RemoteHolder>::GetInstance().Pop(owner, cookie);
179         SECURITY_LOG_ERROR("DslmSetResponseToParcel failed, ret = %{public}d", ret);
180         return ret;
181     }
182     return SUCCESS;
183 }
184 
Push(uint32_t owner,uint32_t cookie,const sptr<IRemoteObject> & object)185 bool DslmIpcProcess::RemoteHolder::Push(uint32_t owner, uint32_t cookie, const sptr<IRemoteObject> &object)
186 {
187     std::lock_guard<std::mutex> lock(mutex_);
188     uint64_t key = (static_cast<uint64_t>(owner) << COOKIE_SHIFT) | cookie;
189     map_[key] = object;
190     if (map_.size() > WARNING_GATE) {
191         SECURITY_LOG_WARN("remote objects max warning");
192     }
193     return true;
194 }
195 
Pop(uint32_t owner,uint32_t cookie)196 sptr<IRemoteObject> DslmIpcProcess::RemoteHolder::Pop(uint32_t owner, uint32_t cookie)
197 {
198     std::lock_guard<std::mutex> lock(mutex_);
199     uint64_t key = (static_cast<uint64_t>(owner) << COOKIE_SHIFT) | cookie;
200     auto iter = map_.find(key);
201     if (iter == map_.end()) {
202         return nullptr;
203     }
204     auto obj = iter->second;
205     map_.erase(iter);
206     return obj;
207 }
208 } // namespace DeviceSecurityLevel
209 } // namespace Security
210 } // namespace OHOS
211