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 "path_control.h"
17
18 #include <sstream>
19 #include <string>
20 #include <tuple>
21 #include <utility>
22
23 #include "log.h"
24 #include "storage_acl.h"
25
26 namespace OHOS::Request {
27
28 static constexpr int ACL_SUCC = 0;
29 static const std::string SA_PERMISSION_U_RW = "u:3815:rw";
30 static const std::string SA_PERMISSION_G_X = "g:3815:x";
31 static const std::string SA_PERMISSION_U_CLEAN = "u:3815:---";
32 static const std::string SA_PERMISSION_G_CLEAN = "g:3815:---";
33 static const std::string AREA1 = "/data/storage/el1/base";
34 static const std::string AREA2 = "/data/storage/el2/base";
35 static const std::string AREA5 = "/data/storage/el5/base";
36
37 static std::mutex pathMutex_;
38 static std::map<std::string, std::tuple<bool, uint32_t>> pathMap_;
39
40 static constexpr size_t TWO_OCTET = 2;
41 static constexpr size_t THREE_OCTET = 3;
42 static constexpr size_t FOUR_OCTET = 4;
43
CheckBelongAppBaseDir(const std::string & filepath)44 bool PathControl::CheckBelongAppBaseDir(const std::string &filepath)
45 {
46 return (filepath.find(AREA1) == 0) || filepath.find(AREA2) == 0 || filepath.find(AREA5) == 0;
47 }
48
49 // "/A/B/C" -> ["/A", "/A/B", "/A/B/C"]
SplitPath(const std::string & path)50 std::vector<std::string> SplitPath(const std::string &path)
51 {
52 std::vector<std::string> result;
53 if (path.empty() || path[0] != '/') {
54 return result;
55 }
56
57 result.reserve(std::count(path.begin(), path.end(), '/') + 1);
58 std::string currentPath = "";
59 size_t pos = 1;
60 while (pos < path.size()) {
61 size_t nextPos = path.find('/', pos);
62 if (nextPos == std::string::npos) {
63 nextPos = path.size();
64 }
65 if (nextPos > pos) {
66 currentPath += ("/" + path.substr(pos, nextPos - pos));
67 result.emplace_back(currentPath);
68 }
69 pos = nextPos + 1;
70 }
71 return result;
72 }
73
74 // ["/A", "/A/B", "/A/B/C"] -> [("/A", false), ("/A/B", false), ("/A/B/C", true)]
SelectPath(const std::vector<std::string> & paths)75 std::vector<std::pair<std::string, bool>> SelectPath(const std::vector<std::string> &paths)
76 {
77 std::vector<std::pair<std::string, bool>> result;
78 if (paths.empty())
79 return result;
80
81 for (const auto &elem : paths) {
82 if (!PathControl::CheckBelongAppBaseDir(elem)) {
83 continue;
84 }
85 result.emplace_back(elem, false);
86 }
87
88 if (!result.empty()) {
89 result.back().second = true;
90 }
91 return result;
92 }
93
AddAcl(const std::string & path,const bool isFile)94 bool AddAcl(const std::string &path, const bool isFile)
95 {
96 std::string entry;
97 if (isFile) {
98 entry = SA_PERMISSION_U_RW;
99 } else {
100 entry = SA_PERMISSION_G_X;
101 }
102 if (StorageDaemon::AclSetAccess(path, entry) != ACL_SUCC) {
103 REQUEST_HILOGE("Add Acl Failed, %{public}s", PathControl::ShieldPath(path).c_str());
104 return false;
105 };
106 return true;
107 }
108
SubAcl(const std::string & path,const bool isFile)109 bool SubAcl(const std::string &path, const bool isFile)
110 {
111 std::string entry;
112 if (isFile) {
113 entry = SA_PERMISSION_U_CLEAN;
114 } else {
115 entry = SA_PERMISSION_G_CLEAN;
116 }
117 if (StorageDaemon::AclSetAccess(path, entry) != ACL_SUCC) {
118 REQUEST_HILOGE("Sub Acl Failed, %{public}s", PathControl::ShieldPath(path).c_str());
119 return false;
120 };
121 return true;
122 }
123
AddOnePathToMap(const std::string & path,const bool isFile)124 bool AddOnePathToMap(const std::string &path, const bool isFile)
125 {
126 std::lock_guard<std::mutex> lockGuard(pathMutex_);
127 auto it = pathMap_.find(path);
128 if (it == pathMap_.end()) {
129 if (!AddAcl(path, isFile)) {
130 return false;
131 }
132 pathMap_.emplace(path, std::tuple(isFile, 1));
133 } else {
134 auto &[iFile, count] = it->second;
135 iFile = isFile;
136 count++;
137 }
138 return true;
139 }
140
SubOnePathToMap(const std::string & path,const bool isFile)141 bool SubOnePathToMap(const std::string &path, const bool isFile)
142 {
143 std::lock_guard<std::mutex> lockGuard(pathMutex_);
144 auto it = pathMap_.find(path);
145 if (it == pathMap_.end()) {
146 REQUEST_HILOGE("SubOnePathToMap no path, %{puiblic}s", PathControl::ShieldPath(path).c_str());
147 return false;
148 }
149 auto &[iFile, count] = it->second;
150 if (count > 1) {
151 count--;
152 return true;
153 }
154
155 if (iFile != isFile) {
156 REQUEST_HILOGE("SubOnePathToMap path changed, %{puiblic}s", PathControl::ShieldPath(path).c_str());
157 }
158 if (!SubAcl(path, isFile)) {
159 return false;
160 }
161 return true;
162 }
163
SubPathsVec(const std::vector<std::pair<std::string,bool>> & paths)164 bool SubPathsVec(const std::vector<std::pair<std::string, bool>> &paths)
165 {
166 for (auto &elem : paths) {
167 if (!SubOnePathToMap(elem.first, elem.second)) {
168 return false;
169 }
170 }
171 return true;
172 }
173
AddPathsToMap(const std::string & path)174 bool PathControl::AddPathsToMap(const std::string &path)
175 {
176 std::vector<std::pair<std::string, bool>> paths = SelectPath(SplitPath(path));
177 if (paths.empty()) {
178 return false;
179 }
180 std::vector<std::pair<std::string, bool>> completePaths;
181 completePaths.reserve(paths.size());
182 for (auto &elem : paths) {
183 if (!AddOnePathToMap(elem.first, elem.second)) {
184 SubPathsVec(completePaths);
185 return false;
186 }
187 completePaths.emplace_back(elem);
188 }
189 return true;
190 }
191
SubPathsToMap(const std::string & path)192 bool PathControl::SubPathsToMap(const std::string &path)
193 {
194 std::vector<std::pair<std::string, bool>> paths = SelectPath(SplitPath(path));
195 if (paths.empty()) {
196 return false;
197 }
198 return SubPathsVec(paths);
199 }
200
InsureMapAcl()201 void PathControl::InsureMapAcl()
202 {
203 std::lock_guard<std::mutex> lockGuard(pathMutex_);
204 for (const auto &[key, value] : pathMap_) {
205 auto [isFile, count] = value;
206 if (count > 0) {
207 AddAcl(key, isFile);
208 }
209 }
210 }
211
212 // "abcde" -> "**cde"
ShieldStr(const std::string & s)213 std::string ShieldStr(const std::string &s)
214 {
215 if (s.empty()) {
216 return "";
217 }
218 size_t n = s.length();
219 size_t halfLen = n / 2;
220 return std::string(halfLen, '*') + s.substr(halfLen);
221 }
222
223 // "/ab/abcde" -> "/*b/**cde"
ShieldPath(const std::string & path)224 std::string PathControl::ShieldPath(const std::string &path)
225 {
226 std::istringstream iss(path);
227 std::string token;
228 std::string result;
229
230 while (std::getline(iss, token, '/')) {
231 if (token.empty()) {
232 continue;
233 }
234 result += '/';
235 result += ShieldStr(token);
236 }
237
238 return result;
239 }
240 } // namespace OHOS::Request
241