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 "fscrypt_key_v1_ext.h"
17
18 #include <filesystem>
19 #include <vector>
20
21 #include "fbex.h"
22 #include "storage_service_log.h"
23 #include "string_ex.h"
24
25 namespace OHOS {
26 namespace StorageDaemon {
27 static const std::string NEED_RESTORE_PATH = "/data/service/el0/storage_daemon/sd/latest/need_restore";
28 static const uint32_t DEFAULT_SINGLE_FIRST_USER_ID = 100;
29 static const uint32_t USER_ID_DIFF = 91;
30
31 /* sec_fbe_drv module saved userId, type and IV in ioctl FBEX_IOC_ADD_IV process.
32 * In Upgrade Scenario, before upgrade user id 0 and after upgrade user id 100, ioctl
33 * FBEX_IOC_ADD_IV will return error.
34 * so, to solve this problem, when el3/el4 ioctl FBEX_IOC_ADD_IV, userId need be mapped
35 * in Upgrade Scenario.
36 * user id mapped as:
37 * src-userId mapped-userId diff
38 * 0 100 100
39 * 10 101 91
40 * 11 102 91
41 * 12 103 91
42 * ... ... 91
43 * 128 219 91
44 * 129 220 91
45 * ... ... 91
46 */
GetMappedUserId(uint32_t userId,uint32_t type)47 uint32_t FscryptKeyV1Ext::GetMappedUserId(uint32_t userId, uint32_t type)
48 {
49 if (std::filesystem::exists(NEED_RESTORE_PATH) &&
50 (type == TYPE_EL2 || type == TYPE_EL3 || type == TYPE_EL4)) {
51 if (userId == DEFAULT_SINGLE_FIRST_USER_ID) {
52 return 0;
53 }
54
55 if (userId > DEFAULT_SINGLE_FIRST_USER_ID) {
56 return userId - USER_ID_DIFF;
57 }
58 }
59
60 return userId;
61 }
62
ActiveKeyExt(uint32_t flag,uint8_t * iv,uint32_t size,uint32_t & elType)63 bool FscryptKeyV1Ext::ActiveKeyExt(uint32_t flag, uint8_t *iv, uint32_t size, uint32_t &elType)
64 {
65 if (!FBEX::IsFBEXSupported()) {
66 return true;
67 }
68
69 LOGD("enter");
70 uint32_t user = GetMappedUserId(userId_, type_);
71 LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
72 // iv buffer returns derived keys
73 if (FBEX::InstallKeyToKernel(user, type_, iv, size, static_cast<uint8_t>(flag)) != 0) {
74 LOGE("InstallKeyToKernel failed, user %{public}d, type %{public}d, flag %{public}u", user, type_, flag);
75 return false;
76 }
77
78 //Used to associate el3 and el4 kernels.
79 elType = type_;
80 return true;
81 }
82
UnlockUserScreenExt(uint32_t flag,uint8_t * iv,uint32_t size)83 bool FscryptKeyV1Ext::UnlockUserScreenExt(uint32_t flag, uint8_t *iv, uint32_t size)
84 {
85 if (!FBEX::IsFBEXSupported()) {
86 return true;
87 }
88 LOGD("enter");
89 uint32_t user = GetMappedUserId(userId_, type_);
90 LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
91 if (FBEX::UnlockScreenToKernel(user, type_, iv, size)) {
92 LOGE("UnlockScreenToKernel failed, userId %{public}d, %{public}d", userId_, flag);
93 return false;
94 }
95 return true;
96 }
97
InactiveKeyExt(uint32_t flag)98 bool FscryptKeyV1Ext::InactiveKeyExt(uint32_t flag)
99 {
100 if (!FBEX::IsFBEXSupported()) {
101 return true;
102 }
103
104 LOGD("enter");
105 bool destroy = !!flag;
106 if ((type_ != TYPE_EL2) && !destroy) {
107 LOGD("not el2, no need to inactive");
108 return true;
109 }
110 uint8_t buf[FBEX_IV_SIZE] = {0};
111 buf[0] = 0xfb; // fitst byte const to kernel
112 buf[1] = 0x30; // second byte const to kernel
113
114 uint32_t user = GetMappedUserId(userId_, type_);
115 LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
116 if (FBEX::UninstallOrLockUserKeyToKernel(user, type_, buf, FBEX_IV_SIZE, destroy) != 0) {
117 LOGE("UninstallOrLockUserKeyToKernel failed, userId %{public}d, type %{public}d, destroy %{public}u", userId_,
118 type_, destroy);
119 return false;
120 }
121 return true;
122 }
123
LockUserScreenExt(uint32_t flag,uint32_t & elType)124 bool FscryptKeyV1Ext::LockUserScreenExt(uint32_t flag, uint32_t &elType)
125 {
126 if (!FBEX::IsFBEXSupported()) {
127 return true;
128 }
129 LOGD("enter");
130 uint32_t user = GetMappedUserId(userId_, type_);
131 LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
132 if (FBEX::LockScreenToKernel(user)) {
133 LOGE("LockScreenToKernel failed, userId %{public}d", flag);
134 return false;
135 }
136 //Used to associate el3 and el4 kernels.
137 elType = type_;
138 return true;
139 }
140
GetUserIdFromDir()141 uint32_t FscryptKeyV1Ext::GetUserIdFromDir()
142 {
143 int userId = USERID_GLOBAL_EL1; // default to global el1
144
145 // fscrypt key dir is like `/data/foo/bar/el1/100`
146 auto slashIndex = dir_.rfind('/');
147 if (slashIndex != std::string::npos) {
148 std::string last = dir_.substr(slashIndex + 1);
149 (void)OHOS::StrToInt(last, userId);
150 }
151
152 LOGI("dir_: %{public}s, get userId is %{public}d", dir_.c_str(), userId);
153 return static_cast<uint32_t>(userId);
154 }
155
GetTypeFromDir()156 uint32_t FscryptKeyV1Ext::GetTypeFromDir()
157 {
158 static const std::vector<std::pair<std::string, uint32_t>> typeStrs = {
159 {"el1", TYPE_EL1},
160 {"el2", TYPE_EL2},
161 {"el3", TYPE_EL3},
162 {"el4", TYPE_EL4},
163 };
164 uint32_t type = TYPE_GLOBAL_EL1; // default to global el1
165
166 // fscrypt key dir is like `/data/foo/bar/el1/100`
167 auto slashIndex = dir_.rfind('/');
168 if (slashIndex == std::string::npos) {
169 LOGE("bad dir %{public}s", dir_.c_str());
170 return type;
171 }
172 slashIndex = dir_.rfind('/', slashIndex - 1);
173 if (slashIndex == std::string::npos) {
174 LOGE("bad dir %{public}s", dir_.c_str());
175 return type;
176 }
177
178 std::string el = dir_.substr(slashIndex + 1); // el string is like `el1/100`
179 for (const auto &it : typeStrs) {
180 if (el.find(it.first) != std::string::npos) {
181 type = it.second;
182 break;
183 }
184 }
185 LOGI("el string is %{public}s, parse type %{public}d", el.c_str(), type);
186 return type;
187 }
188 } // namespace StorageDaemon
189 } // namespace OHOS
190