• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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