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 <android-base/logging.h> 21 #include <jni.h> 22 #include <sys/types.h> 23 24 #include <dirent.h> 25 #include <atomic> 26 #include <condition_variable> 27 #include <functional> 28 #include <mutex> 29 #include <queue> 30 #include <string> 31 #include <thread> 32 33 #include "libfuse_jni/ReaddirHelper.h" 34 #include "libfuse_jni/RedactionInfo.h" 35 36 namespace mediaprovider { 37 namespace fuse { 38 39 /** Represents file open result from MediaProvider */ 40 struct FileOpenResult { FileOpenResultFileOpenResult41 FileOpenResult(const int status, const int uid, const uid_t transforms_uid, const int fd, 42 const RedactionInfo* redaction_info) 43 : status(status), 44 uid(uid), 45 transforms_uid(transforms_uid), 46 fd(fd), 47 redaction_info(redaction_info) {} 48 49 const int status; 50 const int uid; 51 const uid_t transforms_uid; 52 const int fd; 53 std::unique_ptr<const RedactionInfo> redaction_info; 54 }; 55 56 /** 57 * Represents transform info for a file, containing the transforms, the transforms completion 58 * status and the ioPath. Provided by MediaProvider.java via a JNI call. 59 */ 60 struct FileLookupResult { FileLookupResultFileLookupResult61 FileLookupResult(int transforms, int transforms_reason, uid_t uid, bool transforms_complete, 62 bool transforms_supported, const std::string& io_path) 63 : transforms(transforms), 64 transforms_reason(transforms_reason), 65 uid(uid), 66 transforms_complete(transforms_complete), 67 transforms_supported(transforms_supported), 68 io_path(io_path) { 69 if (transforms != 0) { 70 CHECK(transforms_supported); 71 } 72 } 73 74 /** 75 * These fields are not to be interpreted, they are determined and populated from MediaProvider 76 * via a JNI call. 77 */ 78 const int transforms; 79 const int transforms_reason; 80 const uid_t uid; 81 const bool transforms_complete; 82 const bool transforms_supported; 83 const std::string io_path; 84 }; 85 86 /** 87 * Class that wraps MediaProvider.java and all of the needed JNI calls to make 88 * interaction with MediaProvider easier. 89 */ 90 class MediaProviderWrapper final { 91 public: 92 MediaProviderWrapper(JNIEnv* env, jobject media_provider); 93 ~MediaProviderWrapper(); 94 95 /** 96 * Computes and returns the RedactionInfo for a given file and UID. 97 * 98 * @param uid UID of the app requesting the read 99 * @param path path of the requested file that will be used for database operations 100 * @param io_path path of the requested file that will be used for IO 101 * @return RedactionInfo on success, nullptr on failure to calculate 102 * redaction ranges (e.g. exception was thrown in Java world) 103 */ 104 std::unique_ptr<RedactionInfo> GetRedactionInfo(const std::string& path, 105 const std::string& io_path, uid_t uid, 106 pid_t tid); 107 108 /** 109 * Inserts a new entry for the given path and UID. 110 * 111 * @param path the path of the file to be created 112 * @param uid UID of the calling app 113 * @return 0 if the operation succeeded, 114 * or errno error code if operation fails. 115 */ 116 int InsertFile(const std::string& path, uid_t uid); 117 118 /** 119 * Delete the file denoted by the given path on behalf of the given UID. 120 * 121 * @param path the path of the file to be deleted 122 * @param uid UID of the calling app 123 * @return 0 upon success, or errno error code if operation fails. 124 */ 125 int DeleteFile(const std::string& path, uid_t uid); 126 127 /** 128 * Gets directory entries for given path from MediaProvider database and lower file system 129 * 130 * @param uid UID of the calling app. 131 * @param path Relative path of the directory. 132 * @param dirp Pointer to directory stream, used to query lower file system. 133 * @return DirectoryEntries with list of directory entries on success. 134 * File names in a directory are obtained from MediaProvider. If a path is unknown to 135 * MediaProvider, file names are obtained from lower file system. All directory names in the 136 * given directory are obtained from lower file system. 137 * An empty string in first directory entry name indicates the error occurred while obtaining 138 * directory entries, directory entry type will hold the corresponding errno information. 139 */ 140 std::vector<std::shared_ptr<DirectoryEntry>> GetDirectoryEntries(uid_t uid, 141 const std::string& path, 142 DIR* dirp); 143 144 /** 145 * Determines if the given UID is allowed to open the file denoted by the given path. 146 * 147 * Also computes and returns the RedactionInfo for a given file and |uid| 148 * 149 * @param path path of the requested file that will be used for database operations 150 * @param io_path path of the requested file that will be used for IO 151 * @param uid UID of the calling app 152 * @param tid UID of the calling app 153 * @param for_write specifies if the file is to be opened for write 154 * @param redact specifies whether to attempt redaction 155 * @return FileOpenResult containing status, uid and redaction_info 156 */ 157 std::unique_ptr<FileOpenResult> OnFileOpen(const std::string& path, const std::string& io_path, 158 uid_t uid, pid_t tid, int transforms_reason, 159 bool for_write, bool redact, 160 bool log_transforms_metrics); 161 162 /** 163 * Determines if the given UID is allowed to create a directory with the given path. 164 * 165 * @param path the path of the directory to be created 166 * @param uid UID of the calling app 167 * @return 0 if it's allowed, or errno error code if operation isn't allowed. 168 */ 169 int IsCreatingDirAllowed(const std::string& path, uid_t uid); 170 171 /** 172 * Determines if the given UID is allowed to delete the directory with the given path. 173 * 174 * @param path the path of the directory to be deleted 175 * @param uid UID of the calling app 176 * @return 0 if it's allowed, or errno error code if operation isn't allowed. 177 */ 178 int IsDeletingDirAllowed(const std::string& path, uid_t uid); 179 180 /** 181 * Determines if the given UID is allowed to open the directory with the given path. 182 * 183 * @param path the path of the directory to be opened 184 * @param uid UID of the calling app 185 * @param forWrite if it's a write access 186 * @return 0 if it's allowed, or errno error code if operation isn't allowed. 187 */ 188 int IsOpendirAllowed(const std::string& path, uid_t uid, bool forWrite); 189 190 /** 191 * Determines if one of the follows is true: 192 * 1. The package name of the given private path matches the given uid, 193 then this uid has access to private-app directories for this package. 194 * 2. The calling uid has special access to private-app directories: 195 * * DownloadProvider and ExternalStorageProvider has access to private 196 * app directories. 197 * * Installer apps have access to Android/obb directories 198 * 199 * @param uid UID of the app 200 * @param path the private path that the UID wants to access 201 * @return true if it matches, otherwise return false. 202 */ 203 bool isUidAllowedAccessToDataOrObbPath(uid_t uid, const std::string& path); 204 205 /** 206 * Renames a file or directory to new path. 207 * 208 * @param old_path path of the file or directory to be renamed. 209 * @param new_path new path of the file or directory to be renamed. 210 * @param uid UID of the calling app. 211 * @return 0 if rename is successful, errno if one of the rename fails. If return 212 * value is 0, it's guaranteed that file/directory is moved to new_path. For any other errno 213 * except EFAULT/EIO, it's guaranteed that file/directory is not renamed. 214 */ 215 int Rename(const std::string& old_path, const std::string& new_path, uid_t uid); 216 217 /** 218 * Called whenever a file has been created through FUSE. 219 * 220 * @param path path of the file that has been created. 221 */ 222 void OnFileCreated(const std::string& path); 223 224 /** 225 * Returns FileLookupResult to determine transform info for a path and uid. 226 */ 227 std::unique_ptr<FileLookupResult> FileLookup(const std::string& path, uid_t uid, pid_t tid); 228 229 /** Transforms from src to dst file */ 230 bool Transform(const std::string& src, const std::string& dst, int transforms, 231 int transforms_reason, uid_t read_uid, uid_t open_uid, uid_t transforms_uid); 232 233 /** 234 * Determines if to allow FUSE_LOOKUP for uid. Might allow uids that don't belong to the 235 * MediaProvider user, depending on OEM configuration. 236 * 237 * @param uid linux uid to check 238 */ 239 bool ShouldAllowLookup(uid_t uid, int path_user_id); 240 241 /** 242 * Determines if the passed in user ID is an app clone user (paired with user 0) 243 * 244 * @param userId the user ID to check 245 */ 246 bool IsAppCloneUser(uid_t userId); 247 248 /** 249 * Initializes per-process static variables associated with the lifetime of 250 * a managed runtime. 251 */ 252 static void OneTimeInit(JavaVM* vm); 253 254 /** TLS Key to map a given thread to its JNIEnv. */ 255 static pthread_key_t gJniEnvKey; 256 257 private: 258 jclass file_lookup_result_class_; 259 jclass file_open_result_class_; 260 jclass media_provider_class_; 261 jobject media_provider_object_; 262 /** Cached MediaProvider method IDs **/ 263 jmethodID mid_insert_file_; 264 jmethodID mid_delete_file_; 265 jmethodID mid_on_file_open_; 266 jmethodID mid_scan_file_; 267 jmethodID mid_is_diraccess_allowed_; 268 jmethodID mid_get_files_in_dir_; 269 jmethodID mid_rename_; 270 jmethodID mid_is_uid_allowed_access_to_data_or_obb_path_; 271 jmethodID mid_on_file_created_; 272 jmethodID mid_should_allow_lookup_; 273 jmethodID mid_is_app_clone_user_; 274 jmethodID mid_transform_; 275 jmethodID mid_file_lookup_; 276 /** Cached FileLookupResult field IDs **/ 277 jfieldID fid_file_lookup_transforms_; 278 jfieldID fid_file_lookup_transforms_reason_; 279 jfieldID fid_file_lookup_uid_; 280 jfieldID fid_file_lookup_transforms_complete_; 281 jfieldID fid_file_lookup_transforms_supported_; 282 jfieldID fid_file_lookup_io_path_; 283 /** Cached FileOpenResult field IDs **/ 284 jfieldID fid_file_open_status_; 285 jfieldID fid_file_open_uid_; 286 jfieldID fid_file_open_transforms_uid_; 287 jfieldID fid_file_open_redaction_ranges_; 288 jfieldID fid_file_open_fd_; 289 290 /** 291 * Auxiliary for caching MediaProvider methods. 292 */ 293 jmethodID CacheMethod(JNIEnv* env, const char method_name[], const char signature[]); 294 295 // Attaches the current thread (if necessary) and returns the JNIEnv 296 // associated with it. 297 static JNIEnv* MaybeAttachCurrentThread(); 298 // Destructor function for a given native thread. Called precisely once 299 // by the pthreads library. 300 static void DetachThreadFunction(void* unused); 301 302 static JavaVM* gJavaVm; 303 }; 304 305 } // namespace fuse 306 } // namespace mediaprovider 307 308 #endif // MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ 309