shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specic language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ |
| 18 | #define MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ |
| 19 | |
| 20 | #include <jni.h> |
| 21 | #include <sys/types.h> |
| 22 | |
Sahana Rao | 7169344 | 2019-11-13 13:48:07 +0000 | [diff] [blame] | 23 | #include <dirent.h> |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 24 | #include <atomic> |
| 25 | #include <condition_variable> |
| 26 | #include <functional> |
| 27 | #include <mutex> |
| 28 | #include <queue> |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 29 | #include <string> |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 30 | #include <thread> |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 31 | |
Sahana Rao | a82bd6a | 2019-10-10 18:10:37 +0100 | [diff] [blame] | 32 | #include "libfuse_jni/ReaddirHelper.h" |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 33 | #include "libfuse_jni/RedactionInfo.h" |
| 34 | |
| 35 | namespace mediaprovider { |
| 36 | namespace fuse { |
| 37 | |
| 38 | /** |
Biswarup Pal | 63901f3 | 2021-01-07 14:57:23 +0000 | [diff] [blame^] | 39 | * Represents transform info for a file, containing the transforms, the transforms completion |
| 40 | * status and the ioPath. Provided by MediaProvider.java via a JNI call. |
| 41 | */ |
| 42 | struct FileLookupResult { |
| 43 | FileLookupResult(int transforms, bool transforms_complete, const std::string& io_path) |
| 44 | : transforms(transforms), transforms_complete(transforms_complete), io_path(io_path) {} |
| 45 | |
| 46 | /** |
| 47 | * This field is not to be interpreted, it is determined and populated from MediaProvider |
| 48 | * via a JNI call. |
| 49 | */ |
| 50 | const int transforms; |
| 51 | const bool transforms_complete; |
| 52 | const std::string io_path; |
| 53 | }; |
| 54 | |
| 55 | /** |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 56 | * Class that wraps MediaProvider.java and all of the needed JNI calls to make |
| 57 | * interaction with MediaProvider easier. |
| 58 | */ |
| 59 | class MediaProviderWrapper final { |
| 60 | public: |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 61 | MediaProviderWrapper(JNIEnv* env, jobject media_provider); |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 62 | ~MediaProviderWrapper(); |
| 63 | |
| 64 | /** |
shafik | c580b6d | 2019-12-10 18:45:17 +0000 | [diff] [blame] | 65 | * Computes and returns the RedactionInfo for a given file and UID. |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 66 | * |
| 67 | * @param uid UID of the app requesting the read |
Zim | e9ae6ee | 2020-11-26 15:38:13 +0000 | [diff] [blame] | 68 | * @param path path of the requested file that will be used for database operations |
| 69 | * @param io_path path of the requested file that will be used for IO |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 70 | * @return RedactionInfo on success, nullptr on failure to calculate |
| 71 | * redaction ranges (e.g. exception was thrown in Java world) |
| 72 | */ |
Zim | e9ae6ee | 2020-11-26 15:38:13 +0000 | [diff] [blame] | 73 | std::unique_ptr<RedactionInfo> GetRedactionInfo(const std::string& path, |
| 74 | const std::string& io_path, uid_t uid, |
| 75 | pid_t tid); |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 76 | |
shafik | a51f3ce | 2019-10-10 17:06:41 +0100 | [diff] [blame] | 77 | /** |
shafik | 9edfb14 | 2019-11-06 11:01:40 +0000 | [diff] [blame] | 78 | * Inserts a new entry for the given path and UID. |
shafik | a51f3ce | 2019-10-10 17:06:41 +0100 | [diff] [blame] | 79 | * |
| 80 | * @param path the path of the file to be created |
| 81 | * @param uid UID of the calling app |
shafik | 9edfb14 | 2019-11-06 11:01:40 +0000 | [diff] [blame] | 82 | * @return 0 if the operation succeeded, |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 83 | * or errno error code if operation fails. |
shafik | a51f3ce | 2019-10-10 17:06:41 +0100 | [diff] [blame] | 84 | */ |
shafik | 9edfb14 | 2019-11-06 11:01:40 +0000 | [diff] [blame] | 85 | int InsertFile(const std::string& path, uid_t uid); |
shafik | a51f3ce | 2019-10-10 17:06:41 +0100 | [diff] [blame] | 86 | |
shafik | 0c0e0d7 | 2019-10-16 17:34:17 +0100 | [diff] [blame] | 87 | /** |
| 88 | * Delete the file denoted by the given path on behalf of the given UID. |
| 89 | * |
| 90 | * @param path the path of the file to be deleted |
| 91 | * @param uid UID of the calling app |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 92 | * @return 0 upon success, or errno error code if operation fails. |
shafik | 0c0e0d7 | 2019-10-16 17:34:17 +0100 | [diff] [blame] | 93 | */ |
| 94 | int DeleteFile(const std::string& path, uid_t uid); |
| 95 | |
shafik | 15e2d61 | 2019-10-31 20:10:25 +0000 | [diff] [blame] | 96 | /** |
Sahana Rao | 8a588e7 | 2019-12-06 11:32:56 +0000 | [diff] [blame] | 97 | * Gets directory entries for given path from MediaProvider database and lower file system |
Sahana Rao | a82bd6a | 2019-10-10 18:10:37 +0100 | [diff] [blame] | 98 | * |
| 99 | * @param uid UID of the calling app. |
| 100 | * @param path Relative path of the directory. |
Sahana Rao | 7169344 | 2019-11-13 13:48:07 +0000 | [diff] [blame] | 101 | * @param dirp Pointer to directory stream, used to query lower file system. |
Sahana Rao | 8a588e7 | 2019-12-06 11:32:56 +0000 | [diff] [blame] | 102 | * @return DirectoryEntries with list of directory entries on success. |
| 103 | * File names in a directory are obtained from MediaProvider. If a path is unknown to |
| 104 | * MediaProvider, file names are obtained from lower file system. All directory names in the |
| 105 | * given directory are obtained from lower file system. |
Sahana Rao | 7169344 | 2019-11-13 13:48:07 +0000 | [diff] [blame] | 106 | * An empty string in first directory entry name indicates the error occurred while obtaining |
| 107 | * directory entries, directory entry type will hold the corresponding errno information. |
Sahana Rao | a82bd6a | 2019-10-10 18:10:37 +0100 | [diff] [blame] | 108 | */ |
| 109 | std::vector<std::shared_ptr<DirectoryEntry>> GetDirectoryEntries(uid_t uid, |
| 110 | const std::string& path, |
| 111 | DIR* dirp); |
| 112 | |
| 113 | /** |
shafik | 15e2d61 | 2019-10-31 20:10:25 +0000 | [diff] [blame] | 114 | * Determines if the given UID is allowed to open the file denoted by the given path. |
| 115 | * |
| 116 | * @param path the path of the file to be opened |
| 117 | * @param uid UID of the calling app |
| 118 | * @param for_write specifies if the file is to be opened for write |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 119 | * @return 0 upon success or errno value upon failure. |
shafik | 15e2d61 | 2019-10-31 20:10:25 +0000 | [diff] [blame] | 120 | */ |
| 121 | int IsOpenAllowed(const std::string& path, uid_t uid, bool for_write); |
| 122 | |
| 123 | /** |
| 124 | * Potentially triggers a scan of the file before closing it and reconciles it with the |
| 125 | * MediaProvider database. |
| 126 | * |
| 127 | * @param path the path of the file to be scanned |
| 128 | */ |
Sahana Rao | ee32136 | 2020-03-05 19:27:37 +0000 | [diff] [blame] | 129 | void ScanFile(const std::string& path); |
shafik | 15e2d61 | 2019-10-31 20:10:25 +0000 | [diff] [blame] | 130 | |
shafik | bba5b67 | 2019-11-15 16:52:51 +0000 | [diff] [blame] | 131 | /** |
| 132 | * Determines if the given UID is allowed to create a directory with the given path. |
| 133 | * |
| 134 | * @param path the path of the directory to be created |
| 135 | * @param uid UID of the calling app |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 136 | * @return 0 if it's allowed, or errno error code if operation isn't allowed. |
shafik | bba5b67 | 2019-11-15 16:52:51 +0000 | [diff] [blame] | 137 | */ |
| 138 | int IsCreatingDirAllowed(const std::string& path, uid_t uid); |
| 139 | |
| 140 | /** |
| 141 | * Determines if the given UID is allowed to delete the directory with the given path. |
| 142 | * |
| 143 | * @param path the path of the directory to be deleted |
| 144 | * @param uid UID of the calling app |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 145 | * @return 0 if it's allowed, or errno error code if operation isn't allowed. |
shafik | bba5b67 | 2019-11-15 16:52:51 +0000 | [diff] [blame] | 146 | */ |
| 147 | int IsDeletingDirAllowed(const std::string& path, uid_t uid); |
| 148 | |
shafik | 824c108 | 2019-11-22 12:00:52 +0000 | [diff] [blame] | 149 | /** |
| 150 | * Determines if the given UID is allowed to open the directory with the given path. |
| 151 | * |
| 152 | * @param path the path of the directory to be opened |
| 153 | * @param uid UID of the calling app |
Nandana Dutt | 5fc3201 | 2020-06-25 10:55:52 +0100 | [diff] [blame] | 154 | * @param forWrite if it's a write access |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 155 | * @return 0 if it's allowed, or errno error code if operation isn't allowed. |
shafik | 824c108 | 2019-11-22 12:00:52 +0000 | [diff] [blame] | 156 | */ |
Nandana Dutt | 5fc3201 | 2020-06-25 10:55:52 +0100 | [diff] [blame] | 157 | int IsOpendirAllowed(const std::string& path, uid_t uid, bool forWrite); |
shafik | 824c108 | 2019-11-22 12:00:52 +0000 | [diff] [blame] | 158 | |
Sahana Rao | 2c41603 | 2019-12-31 13:41:00 +0000 | [diff] [blame] | 159 | /** |
Abhijeet Kaur | b3ac280 | 2020-10-07 16:42:42 +0100 | [diff] [blame] | 160 | * Determines if one of the follows is true: |
| 161 | * 1. The package name of the given private path matches the given uid, |
| 162 | then this uid has access to private-app directories for this package. |
| 163 | * 2. The calling uid has special access to private-app directories: |
| 164 | * * DownloadProvider and ExternalStorageProvider has access to private |
| 165 | * app directories. |
| 166 | * * Installer apps have access to Android/obb directories |
Ricky Wai | f40c402 | 2020-04-15 19:00:06 +0100 | [diff] [blame] | 167 | * |
Ricky Wai | f40c402 | 2020-04-15 19:00:06 +0100 | [diff] [blame] | 168 | * @param uid UID of the app |
Abhijeet Kaur | b3ac280 | 2020-10-07 16:42:42 +0100 | [diff] [blame] | 169 | * @param path the private path that the UID wants to access |
Ricky Wai | f40c402 | 2020-04-15 19:00:06 +0100 | [diff] [blame] | 170 | * @return true if it matches, otherwise return false. |
| 171 | */ |
Abhijeet Kaur | b3ac280 | 2020-10-07 16:42:42 +0100 | [diff] [blame] | 172 | bool isUidAllowedAccessToDataOrObbPath(uid_t uid, const std::string& path); |
Ricky Wai | f40c402 | 2020-04-15 19:00:06 +0100 | [diff] [blame] | 173 | |
| 174 | /** |
Sahana Rao | 2c41603 | 2019-12-31 13:41:00 +0000 | [diff] [blame] | 175 | * Renames a file or directory to new path. |
| 176 | * |
| 177 | * @param old_path path of the file or directory to be renamed. |
| 178 | * @param new_path new path of the file or directory to be renamed. |
| 179 | * @param uid UID of the calling app. |
shafik | e4fb146 | 2020-01-29 16:25:23 +0000 | [diff] [blame] | 180 | * @return 0 if rename is successful, errno if one of the rename fails. If return |
Sahana Rao | 2c41603 | 2019-12-31 13:41:00 +0000 | [diff] [blame] | 181 | * value is 0, it's guaranteed that file/directory is moved to new_path. For any other errno |
| 182 | * except EFAULT/EIO, it's guaranteed that file/directory is not renamed. |
| 183 | */ |
| 184 | int Rename(const std::string& old_path, const std::string& new_path, uid_t uid); |
| 185 | |
Narayan Kamath | de3fe17 | 2020-02-18 12:14:51 +0000 | [diff] [blame] | 186 | /** |
Martijn Coenen | af2d34d | 2020-06-19 12:52:20 +0200 | [diff] [blame] | 187 | * Called whenever a file has been created through FUSE. |
| 188 | * |
| 189 | * @param path path of the file that has been created. |
| 190 | */ |
| 191 | void OnFileCreated(const std::string& path); |
| 192 | |
Biswarup Pal | 63901f3 | 2021-01-07 14:57:23 +0000 | [diff] [blame^] | 193 | /** |
| 194 | * Returns FileLookupResult to determine transform info for a path and uid. |
| 195 | */ |
| 196 | std::unique_ptr<FileLookupResult> FileLookup(const std::string& path, uid_t uid); |
Zim | bb91fef | 2020-09-23 14:32:27 +0100 | [diff] [blame] | 197 | |
| 198 | /** Transforms from src to dst file */ |
| 199 | bool Transform(const std::string& src, const std::string& dst, int transforms, uid_t uid); |
| 200 | |
Martijn Coenen | af2d34d | 2020-06-19 12:52:20 +0200 | [diff] [blame] | 201 | /** |
Zim | 5077a89 | 2020-09-08 12:55:12 +0100 | [diff] [blame] | 202 | * Determines if to allow FUSE_LOOKUP for uid. Might allow uids that don't belong to the |
| 203 | * MediaProvider user, depending on OEM configuration. |
| 204 | * |
| 205 | * @param uid linux uid to check |
| 206 | */ |
| 207 | bool ShouldAllowLookup(uid_t uid, int path_user_id); |
| 208 | |
| 209 | /** |
Martijn Coenen | 8713309 | 2020-10-14 17:00:28 +0200 | [diff] [blame] | 210 | * Determines if the passed in user ID is an app clone user (paired with user 0) |
| 211 | * |
| 212 | * @param userId the user ID to check |
| 213 | */ |
| 214 | bool IsAppCloneUser(uid_t userId); |
| 215 | |
| 216 | /** |
Narayan Kamath | de3fe17 | 2020-02-18 12:14:51 +0000 | [diff] [blame] | 217 | * Initializes per-process static variables associated with the lifetime of |
| 218 | * a managed runtime. |
| 219 | */ |
| 220 | static void OneTimeInit(JavaVM* vm); |
| 221 | |
Zim | c0e65bd | 2020-03-09 15:22:59 +0000 | [diff] [blame] | 222 | /** TLS Key to map a given thread to its JNIEnv. */ |
| 223 | static pthread_key_t gJniEnvKey; |
| 224 | |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 225 | private: |
Biswarup Pal | 63901f3 | 2021-01-07 14:57:23 +0000 | [diff] [blame^] | 226 | jclass file_lookup_result_class_; |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 227 | jclass media_provider_class_; |
| 228 | jobject media_provider_object_; |
shafik | 0c0e0d7 | 2019-10-16 17:34:17 +0100 | [diff] [blame] | 229 | /** Cached MediaProvider method IDs **/ |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 230 | jmethodID mid_get_redaction_ranges_; |
shafik | 9edfb14 | 2019-11-06 11:01:40 +0000 | [diff] [blame] | 231 | jmethodID mid_insert_file_; |
shafik | 0c0e0d7 | 2019-10-16 17:34:17 +0100 | [diff] [blame] | 232 | jmethodID mid_delete_file_; |
shafik | 15e2d61 | 2019-10-31 20:10:25 +0000 | [diff] [blame] | 233 | jmethodID mid_is_open_allowed_; |
| 234 | jmethodID mid_scan_file_; |
shafik | f0fea69 | 2020-02-14 15:49:17 +0000 | [diff] [blame] | 235 | jmethodID mid_is_mkdir_or_rmdir_allowed_; |
shafik | 824c108 | 2019-11-22 12:00:52 +0000 | [diff] [blame] | 236 | jmethodID mid_is_opendir_allowed_; |
Sahana Rao | 8a588e7 | 2019-12-06 11:32:56 +0000 | [diff] [blame] | 237 | jmethodID mid_get_files_in_dir_; |
Sahana Rao | 2c41603 | 2019-12-31 13:41:00 +0000 | [diff] [blame] | 238 | jmethodID mid_rename_; |
Abhijeet Kaur | b3ac280 | 2020-10-07 16:42:42 +0100 | [diff] [blame] | 239 | jmethodID mid_is_uid_allowed_access_to_data_or_obb_path_; |
Martijn Coenen | af2d34d | 2020-06-19 12:52:20 +0200 | [diff] [blame] | 240 | jmethodID mid_on_file_created_; |
Zim | 5077a89 | 2020-09-08 12:55:12 +0100 | [diff] [blame] | 241 | jmethodID mid_should_allow_lookup_; |
Martijn Coenen | 8713309 | 2020-10-14 17:00:28 +0200 | [diff] [blame] | 242 | jmethodID mid_is_app_clone_user_; |
Zim | bb91fef | 2020-09-23 14:32:27 +0100 | [diff] [blame] | 243 | jmethodID mid_transform_; |
Biswarup Pal | 63901f3 | 2021-01-07 14:57:23 +0000 | [diff] [blame^] | 244 | jmethodID mid_file_lookup_; |
| 245 | /** Cached FileLookupResult field IDs **/ |
| 246 | jfieldID fid_file_lookup_transforms_; |
| 247 | jfieldID fid_file_lookup_transforms_complete_; |
| 248 | jfieldID fid_file_lookup_io_path_; |
Sahana Rao | 2c41603 | 2019-12-31 13:41:00 +0000 | [diff] [blame] | 249 | |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 250 | /** |
shafik | 15e2d61 | 2019-10-31 20:10:25 +0000 | [diff] [blame] | 251 | * Auxiliary for caching MediaProvider methods. |
shafik | cdb6b2b | 2019-09-30 12:49:26 +0100 | [diff] [blame] | 252 | */ |
| 253 | jmethodID CacheMethod(JNIEnv* env, const char method_name[], const char signature[], |
| 254 | bool is_static); |
Narayan Kamath | de3fe17 | 2020-02-18 12:14:51 +0000 | [diff] [blame] | 255 | |
Biswarup Pal | 63901f3 | 2021-01-07 14:57:23 +0000 | [diff] [blame^] | 256 | /** |
| 257 | * Auxiliary for caching FileLookupResult fields. |
| 258 | */ |
| 259 | jfieldID CacheFileLookupField(JNIEnv* env, const char field_name[], const char type[]); |
| 260 | |
Narayan Kamath | de3fe17 | 2020-02-18 12:14:51 +0000 | [diff] [blame] | 261 | // Attaches the current thread (if necessary) and returns the JNIEnv |
| 262 | // associated with it. |
| 263 | static JNIEnv* MaybeAttachCurrentThread(); |
| 264 | // Destructor function for a given native thread. Called precisely once |
| 265 | // by the pthreads library. |
| 266 | static void DetachThreadFunction(void* unused); |
| 267 | |
| 268 | static JavaVM* gJavaVm; |
shafik | c3f6267 | 2019-08-30 11:15:48 +0100 | [diff] [blame] | 269 | }; |
| 270 | |
| 271 | } // namespace fuse |
| 272 | } // namespace mediaprovider |
| 273 | |
| 274 | #endif // MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ |