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 #define MLOG_TAG "MediaPrivacyManager"
16
17 #include "media_privacy_manager.h"
18
19 #include <algorithm>
20 #include <cerrno>
21 #include <mntent.h>
22 #include <securec.h>
23 #include <unistd.h>
24 #include <unordered_map>
25 #include <fcntl.h>
26
27 #include "epfs.h"
28 #include "image_source.h"
29 #include "media_container_types.h"
30 #include "media_file_utils.h"
31 #include "media_log.h"
32 #include "medialibrary_bundle_manager.h"
33 #include "medialibrary_errno.h"
34 #include "medialibrary_type_const.h"
35 #include "permission_utils.h"
36 #include "media_exif.h"
37 #include "media_library_manager.h"
38 #include "medialibrary_bundle_manager.h"
39 #include "medialibrary_urisensitive_operations.h"
40 #include "medialibrary_tracer.h"
41 #include "parameters.h"
42
43 using namespace std;
44 using PrivacyRanges = vector<pair<uint32_t, uint32_t>>;
45
46 namespace OHOS {
47 namespace Media {
48 constexpr uint32_t E_NO_EXIF = 1;
49 constexpr uint32_t E_NO_PRIVACY_EXIF_TAG = 2;
50 constexpr int32_t DEFAULT_TYPE = -1;
51 const std::vector<std::string> ALL_SENSITIVE_EXIF = {
52 PHOTO_DATA_IMAGE_GPS_LATITUDE,
53 PHOTO_DATA_IMAGE_GPS_LONGITUDE,
54 PHOTO_DATA_IMAGE_GPS_TIME_STAMP,
55 PHOTO_DATA_IMAGE_GPS_DATE_STAMP,
56 PHOTO_DATA_IMAGE_GPS_ALTITUDE,
57 PHOTO_DATA_IMAGE_GPS_VERSION_ID,
58 PHOTO_DATA_IMAGE_MAKE,
59 PHOTO_DATA_IMAGE_MODEL,
60 PHOTO_DATA_IMAGE_SOFTWARE,
61 PHOTO_DATA_IMAGE_DATE_TIME,
62 PHOTO_DATA_IMAGE_EXPOSURE_TIME,
63 PHOTO_DATA_IMAGE_F_NUMBER,
64 PHOTO_DATA_IMAGE_EXPOSURE_PROGRAM,
65 PHOTO_DATA_IMAGE_STANDARD_OUTPUT_SENSITIVITY,
66 PHOTO_DATA_IMAGE_PHOTOGRAPHIC_SENSITIVITY,
67 PHOTO_DATA_IMAGE_DATE_TIME_ORIGINAL,
68 PHOTO_DATA_IMAGE_DATE_TIME_ORIGINAL_FOR_MEDIA,
69 PHOTO_DATA_IMAGE_DATE_TIME_DIGITIZED,
70 PHOTO_DATA_IMAGE_EXPOSURE_BIAS_VALUE,
71 PHOTO_DATA_IMAGE_METERING_MODE,
72 PHOTO_DATA_IMAGE_LIGHT_SOURCE,
73 PHOTO_DATA_IMAGE_FLASH,
74 PHOTO_DATA_IMAGE_FOCAL_LENGTH,
75 PHOTO_DATA_IMAGE_EXPOSURE_MODE,
76 PHOTO_DATA_IMAGE_WHITE_BALANCE,
77 PHOTO_DATA_IMAGE_DIGITAL_ZOOM_RATIO,
78 PHOTO_DATA_IMAGE_FOCAL_LENGTH_IN_35_MM_FILM
79 };
80 const std::vector<std::string> GEOGRAPHIC_LOCATION_EXIF = {
81 PHOTO_DATA_IMAGE_GPS_LATITUDE,
82 PHOTO_DATA_IMAGE_GPS_LONGITUDE,
83 PHOTO_DATA_IMAGE_GPS_TIME_STAMP,
84 PHOTO_DATA_IMAGE_GPS_DATE_STAMP,
85 PHOTO_DATA_IMAGE_GPS_ALTITUDE,
86 PHOTO_DATA_IMAGE_GPS_VERSION_ID
87 };
88 const std::vector<std::string> SHOOTING_PARAM_EXIF = {
89 PHOTO_DATA_IMAGE_MAKE,
90 PHOTO_DATA_IMAGE_MODEL,
91 PHOTO_DATA_IMAGE_SOFTWARE,
92 PHOTO_DATA_IMAGE_DATE_TIME,
93 PHOTO_DATA_IMAGE_EXPOSURE_TIME,
94 PHOTO_DATA_IMAGE_F_NUMBER,
95 PHOTO_DATA_IMAGE_EXPOSURE_PROGRAM,
96 PHOTO_DATA_IMAGE_PHOTOGRAPHIC_SENSITIVITY,
97 PHOTO_DATA_IMAGE_DATE_TIME_ORIGINAL,
98 PHOTO_DATA_IMAGE_DATE_TIME_DIGITIZED,
99 PHOTO_DATA_IMAGE_EXPOSURE_BIAS_VALUE,
100 PHOTO_DATA_IMAGE_METERING_MODE,
101 PHOTO_DATA_IMAGE_LIGHT_SOURCE,
102 PHOTO_DATA_IMAGE_FLASH,
103 PHOTO_DATA_IMAGE_FOCAL_LENGTH,
104 PHOTO_DATA_IMAGE_EXPOSURE_MODE,
105 PHOTO_DATA_IMAGE_WHITE_BALANCE,
106 PHOTO_DATA_IMAGE_DIGITAL_ZOOM_RATIO,
107 PHOTO_DATA_IMAGE_FOCAL_LENGTH_IN_35_MM_FILM
108 };
109
MediaPrivacyManager(const string & path,const string & mode,const string & fileId,const int32_t type)110 MediaPrivacyManager::MediaPrivacyManager(const string &path, const string &mode, const string &fileId,
111 const int32_t type)
112 : path_(path), mode_(mode), fileId_(fileId), type_(type), uid_(0), tokenId_(0), fuseFlag_(false)
113 {}
114
MediaPrivacyManager(const string & path,const string & mode,const string & fileId,const string & appId,const string & clientBundle,const int32_t & uid,const uint32_t & tokenId)115 MediaPrivacyManager::MediaPrivacyManager(const string &path, const string &mode, const string &fileId,
116 const string &appId, const string &clientBundle, const int32_t &uid, const uint32_t &tokenId)
117 : path_(path), mode_(mode), fileId_(fileId), type_(DEFAULT_TYPE),
118 appId_(appId), clientBundle_(clientBundle), uid_(uid), tokenId_(tokenId), fuseFlag_(true)
119 {}
120
~MediaPrivacyManager()121 MediaPrivacyManager::~MediaPrivacyManager()
122 {}
123
124 const unordered_map<PrivacyType, string> PRIVACY_PERMISSION_MAP = {
125 { PrivacyType::PRIVACY_LOCATION, PERMISSION_NAME_MEDIA_LOCATION },
126 };
127
128 const vector<string> EXIF_SUPPORTED_EXTENSION = {
129 IMAGE_CONTAINER_TYPE_JPG,
130 IMAGE_CONTAINER_TYPE_JPEG,
131 IMAGE_CONTAINER_TYPE_JPE,
132 IMAGE_CONTAINER_TYPE_PNG,
133 IMAGE_CONTAINER_TYPE_WEBP,
134 IMAGE_CONTAINER_TYPE_DNG,
135 IMAGE_CONTAINER_TYPE_HEIC,
136 };
137
IsTargetExtension(const string & path)138 static bool IsTargetExtension(const string &path)
139 {
140 const string ext = MediaFileUtils::GetExtensionFromPath(path);
141 return find(EXIF_SUPPORTED_EXTENSION.begin(), EXIF_SUPPORTED_EXTENSION.end(), ext) !=
142 EXIF_SUPPORTED_EXTENSION.end();
143 }
144
IsWriteMode(const string & mode)145 static bool IsWriteMode(const string &mode)
146 {
147 return mode.find(MEDIA_FILEMODE_WRITEONLY) != string::npos;
148 }
149
CheckFsMounted(const string & fsType,const string & mountPoint)150 static bool CheckFsMounted(const string &fsType, const string &mountPoint)
151 {
152 struct mntent mountEntry;
153 constexpr uint32_t mntEntrySize = 1024;
154 char entryStr[mntEntrySize] = {0};
155 FILE *mountTable = setmntent("/proc/mounts", "r");
156 CHECK_AND_RETURN_RET_LOG(mountTable != nullptr, false, "Failed to get mount table, errno:%{public}d", errno);
157
158 do {
159 struct mntent *mnt = getmntent_r(mountTable, &mountEntry, entryStr, sizeof(entryStr));
160 if (mnt == nullptr) {
161 endmntent(mountTable);
162 break;
163 }
164 if ((mountEntry.mnt_type != nullptr) &&
165 (mountEntry.mnt_dir != nullptr) &&
166 (strcmp(mountEntry.mnt_type, fsType.c_str()) == 0) &&
167 (strcmp(mountEntry.mnt_dir, mountPoint.c_str()) == 0)) {
168 endmntent(mountTable);
169 return true;
170 }
171 } while (true);
172 return false;
173 }
174
BindFilterProxyFdToOrigin(const int32_t originFd,int32_t & proxyFd)175 static int32_t BindFilterProxyFdToOrigin(const int32_t originFd, int32_t &proxyFd)
176 {
177 int ret = ioctl(proxyFd, IOC_SET_ORIGIN_FD, &originFd);
178 CHECK_AND_RETURN_RET_LOG(ret >= 0, ret,
179 "Failed to set origin fd: %{public}d to filter proxy fd: %{public}d, error: %{public}d",
180 originFd, proxyFd, errno);
181 return ret;
182 }
183
SendRangesToIoctl(const int32_t originFd,const int32_t proxyFd,const PrivacyRanges & rans)184 static int32_t SendRangesToIoctl(const int32_t originFd, const int32_t proxyFd, const PrivacyRanges &rans)
185 {
186 FilterProxyRanges *ranges = (FilterProxyRanges *)malloc(sizeof(*ranges) + sizeof(ranges->range[0]) * rans.size());
187 CHECK_AND_RETURN_RET_LOG(ranges != nullptr, -ENOMEM, "Failed to malloc ranges, errno: %{public}d", errno);
188 ranges->size = static_cast<uint64_t>(rans.size());
189 ranges->reserved = 0;
190 for (size_t i = 0; i < rans.size(); i++) {
191 // first: offset, second: end
192 ranges->range[i].begin = static_cast<uint64_t>(rans[i].first);
193 ranges->range[i].end = static_cast<uint64_t>(rans[i].second);
194 }
195 int err = ioctl(proxyFd, IOC_SET_FILTER_PROXY_RANGE, ranges);
196 CHECK_AND_PRINT_LOG(err >= 0, "Failed to set ranges to fd: %{public}d, error: %{public}d", proxyFd, errno);
197 free(ranges);
198 return err;
199 }
200
201 /* Caller is responsible to close the returned fd */
OpenOriginFd(const string & path,const string & mode,string & clientBundle,const bool fuseFlag)202 static int32_t OpenOriginFd(const string &path, const string &mode, string &clientBundle, const bool fuseFlag)
203 {
204 MediaLibraryTracer tracer;
205 tracer.Start("MediaPrivacyManager::OpenOriginFd");
206 if (fuseFlag == false) {
207 clientBundle = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
208 }
209 if (clientBundle.empty()) {
210 MEDIA_DEBUG_LOG("clientBundleName is empty");
211 }
212 return MediaFileUtils::OpenFile(path, mode, clientBundle);
213 }
214
215 /*
216 * Read to the returned @filterProxyFd will redirect to the file specified by @path, but the privacy ranges(@ranges) in
217 * read buffer will be filtered out and filled with 0.
218 *
219 * Caller is responsible to close the returned @filterProxyFd.
220 */
OpenFilterProxyFd(const string & path,const string & mode,const PrivacyRanges & ranges,string & clientBundle,const bool & fuseFlag)221 static int32_t OpenFilterProxyFd(const string &path, const string &mode, const PrivacyRanges &ranges,
222 string &clientBundle, const bool &fuseFlag)
223 {
224 MediaLibraryTracer tracer;
225 tracer.Start("MediaPrivacyManager::OpenFilterProxyFd");
226 CHECK_AND_RETURN_RET_LOG(CheckFsMounted(FS_TYPE_EPFS, EPFS_MOUNT_POINT),
227 OpenOriginFd(path, mode, clientBundle, fuseFlag),
228 "Epfs is currently not supported yet");
229 int32_t originFd = open(path.c_str(), O_RDONLY);
230 CHECK_AND_RETURN_RET_LOG(originFd >= 0, originFd,
231 "Failed to open file, errno: %{public}d, path: %{private}s", errno, path.c_str());
232
233 constexpr mode_t epfsFileMode = 0400;
234 // filterProxyFd_ will be returned to user, so there is no need to close it here.
235 int32_t filterProxyFd = open(EPFS_MOUNT_POINT.c_str(), O_TMPFILE | O_RDWR, epfsFileMode);
236 if (filterProxyFd < 0) {
237 MEDIA_ERR_LOG("Failed to open epfs, error: %{public}d", errno);
238 close(originFd);
239 return filterProxyFd;
240 }
241 int32_t ret = BindFilterProxyFdToOrigin(originFd, filterProxyFd);
242 if (ret < 0) {
243 close(originFd);
244 close(filterProxyFd);
245 return ret;
246 }
247 ret = SendRangesToIoctl(originFd, filterProxyFd, ranges);
248 if (ret < 0) {
249 close(originFd);
250 close(filterProxyFd);
251 return ret;
252 }
253 close(originFd);
254 MEDIA_INFO_LOG("FilterProxyFd will be returned: %{private}d", filterProxyFd);
255 return filterProxyFd;
256 }
257
ShowRanges(const PrivacyRanges & ranges)258 static void ShowRanges(const PrivacyRanges &ranges)
259 {
260 for (auto range : ranges) {
261 MEDIA_DEBUG_LOG("Range: [%{public}u, %{public}u)", range.first, range.second);
262 }
263 }
264
CmpMode(pair<uint32_t,uint32_t> pairA,pair<uint32_t,uint32_t> pairB)265 static bool CmpMode(pair<uint32_t, uint32_t> pairA, pair<uint32_t, uint32_t> pairB)
266 {
267 return pairA.first < pairB.first;
268 }
269
SortRangesAndCheck(PrivacyRanges & ranges)270 static int32_t SortRangesAndCheck(PrivacyRanges &ranges)
271 {
272 if (ranges.empty()) {
273 return E_SUCCESS;
274 }
275 uint32_t size = ranges.size();
276 if (size > PRIVACY_MAX_RANGES) {
277 MEDIA_ERR_LOG("Privacy ranges size invalid: %{public}d", size);
278 return -EINVAL;
279 }
280 sort(ranges.begin(), ranges.end(), CmpMode);
281 const auto u_idx = unique(ranges.begin(), ranges.end());
282 ranges.erase(u_idx, ranges.end());
283 size = ranges.size();
284
285 if (ranges[0].first >= ranges[0].second) {
286 MEDIA_ERR_LOG("Incorrect fileter ranges: begin(%{public}u) is not less than end(%{public}u)",
287 ranges[0].first, ranges[0].second);
288 return -EINVAL;
289 }
290
291 for (uint32_t i = 1; i < size; i++) {
292 if ((ranges[i].first >= ranges[i].second) || (ranges[i].first < ranges[i - 1].second)) {
293 MEDIA_ERR_LOG("Invalid ranges: [%{public}u, %{public}u), last range is [%{public}u, %{public}u)",
294 ranges[i].first, ranges[i].second, ranges[i - 1].first, ranges[i - 1].second);
295 return -EINVAL;
296 }
297 }
298 ShowRanges(ranges);
299 return E_SUCCESS;
300 }
301
CollectRanges(const string & path,const HideSensitiveType & sensitiveType,PrivacyRanges & ranges)302 static int32_t CollectRanges(const string &path, const HideSensitiveType &sensitiveType, PrivacyRanges &ranges)
303 {
304 if (sensitiveType == HideSensitiveType::NO_DESENSITIZE) {
305 return E_SUCCESS;
306 }
307
308 SourceOptions opts;
309 opts.formatHint = "image/jpeg";
310 uint32_t err = -1;
311 auto imageSource = ImageSource::CreateImageSource(path, opts, err);
312 if (imageSource == nullptr) {
313 MEDIA_ERR_LOG("Failed to create image source, err: %{public}u", err);
314 return -ENOMEM;
315 }
316
317 PrivacyRanges areas;
318 std::vector<std::string> exifKeys;
319 switch (sensitiveType) {
320 case HideSensitiveType::ALL_DESENSITIZE:
321 err = imageSource->GetFilterArea(ALL_SENSITIVE_EXIF, areas);
322 break;
323 case HideSensitiveType::GEOGRAPHIC_LOCATION_DESENSITIZE:
324 err = imageSource->GetFilterArea(GEOGRAPHIC_LOCATION_EXIF, areas);
325 break;
326 case HideSensitiveType::SHOOTING_PARAM_DESENSITIZE:
327 err = imageSource->GetFilterArea(SHOOTING_PARAM_EXIF, areas);
328 break;
329 default:
330 MEDIA_ERR_LOG("Invaild hide sensitive type %{public}d", sensitiveType);
331 return E_SUCCESS;
332 }
333 CHECK_AND_WARN_LOG(err == E_SUCCESS,
334 "Failed to get privacy area with type %{public}d, err: %{public}u", sensitiveType, err);
335 for (auto &range : areas) {
336 ranges.insert(ranges.end(), std::make_pair(range.first, range.first + range.second));
337 }
338 return E_SUCCESS;
339 }
340
341 /*
342 * @path: [Input], the real path of the target file
343 * @mode: [Input], the mode specified by user
344 * @ranges: [Output], the privacy ranges of the target file
345 *
346 * The return value is listed below:
347 * o Not a jpeg file: return success with empty ranges
348 * o Write jpeg with no MEDIA_LOCATION: return permission denied
349 * o Write jpeg with MEDIA_LOCATION: return success with empty ranges
350 * o Read jpeg with no MEDIA_LOCATION: return success with privacy ranges if have any
351 * o Read jpeg with MEDIA_LOCATION: return success with empty ranges
352 * o Other cases: return negative error code.
353 */
GetPrivacyRanges()354 int32_t MediaPrivacyManager::GetPrivacyRanges()
355 {
356 MediaLibraryTracer tracer;
357 tracer.Start("MediaPrivacyManager::GetPrivacyRanges");
358 if (!IsTargetExtension(path_)) {
359 return E_SUCCESS;
360 }
361 if (fileId_.empty()) {
362 return E_SUCCESS;
363 }
364 if (mode_.find('w') != string::npos) {
365 return E_SUCCESS;
366 }
367 if (fuseFlag_ == false) {
368 string bundleName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
369 appId_ = PermissionUtils::GetAppIdByBundleName(bundleName);
370 tokenId_ = PermissionUtils::GetTokenId();
371 }
372 bool result;
373 for (auto &item : PRIVACY_PERMISSION_MAP) {
374 const string &perm = item.second;
375 if (fuseFlag_ == false) {
376 result = PermissionUtils::CheckCallerPermission(perm);
377 } else {
378 result = PermissionUtils::CheckCallerPermission(perm, uid_);
379 }
380 if ((result == false) && (perm == PERMISSION_NAME_MEDIA_LOCATION) && IsWriteMode(mode_)) {
381 return E_PERMISSION_DENIED;
382 }
383 int32_t err = -1;
384 if (type_ != DEFAULT_TYPE) {
385 MEDIA_DEBUG_LOG("force type");
386 err = CollectRanges(path_, (HideSensitiveType)type_, ranges_);
387 } else {
388 //collect ranges by hideSensitiveType
389 bool isForceSensitive = UriSensitiveOperations::QueryForceSensitive(tokenId_, fileId_);
390 if (!isForceSensitive && result) {
391 continue;
392 }
393 HideSensitiveType sensitiveType =
394 static_cast<HideSensitiveType>(UriSensitiveOperations::QuerySensitiveType(tokenId_, fileId_));
395 err = CollectRanges(path_, sensitiveType, ranges_);
396 }
397 if (err < 0) {
398 return err;
399 }
400 }
401 return SortRangesAndCheck(ranges_);
402 }
403
IsDeveloperMediaTool()404 static bool IsDeveloperMediaTool()
405 {
406 if (!PermissionUtils::IsRootShell() && !PermissionUtils::IsHdcShell()) {
407 MEDIA_DEBUG_LOG("Mediatool permission check failed: target is not root");
408 return false;
409 }
410 CHECK_AND_RETURN_RET_LOG(OHOS::system::GetBoolParameter("const.security.developermode.state", true),
411 false, "Mediatool permission check failed: target is not in developer mode");
412 return true;
413 }
414
Open()415 int32_t MediaPrivacyManager::Open()
416 {
417 int err = GetPrivacyRanges();
418 if (err < 0) {
419 return err;
420 }
421 if (ranges_.size() > 0 && !IsDeveloperMediaTool()) {
422 return OpenFilterProxyFd(path_, mode_, ranges_, clientBundle_, fuseFlag_);
423 }
424 return OpenOriginFd(path_, mode_, clientBundle_, fuseFlag_);
425 }
426 } // namespace Media
427 } // namespace OHOS
428