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