/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specic language governing permissions and * limitations under the License. */ #ifndef MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ #define MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ #include #include #include #include #include #include #include #include #include #include #include #include "libfuse_jni/ReaddirHelper.h" #include "libfuse_jni/RedactionInfo.h" namespace mediaprovider { namespace fuse { /** Represents file open result from MediaProvider */ struct FileOpenResult { FileOpenResult(const int status, const int uid, const uid_t transforms_uid, const int fd, const RedactionInfo* redaction_info) : status(status), uid(uid), transforms_uid(transforms_uid), fd(fd), redaction_info(redaction_info) {} const int status; const int uid; const uid_t transforms_uid; const int fd; std::unique_ptr redaction_info; }; /** * Represents transform info for a file, containing the transforms, the transforms completion * status and the ioPath. Provided by MediaProvider.java via a JNI call. */ struct FileLookupResult { FileLookupResult(int transforms, int transforms_reason, uid_t uid, bool transforms_complete, bool transforms_supported, const std::string& io_path) : transforms(transforms), transforms_reason(transforms_reason), uid(uid), transforms_complete(transforms_complete), transforms_supported(transforms_supported), io_path(io_path) { if (transforms != 0) { CHECK(transforms_supported); } } /** * These fields are not to be interpreted, they are determined and populated from MediaProvider * via a JNI call. */ const int transforms; const int transforms_reason; const uid_t uid; const bool transforms_complete; const bool transforms_supported; const std::string io_path; }; /** * Class that wraps MediaProvider.java and all of the needed JNI calls to make * interaction with MediaProvider easier. */ class MediaProviderWrapper final { public: MediaProviderWrapper(JNIEnv* env, jobject media_provider); ~MediaProviderWrapper(); /** * Computes and returns the RedactionInfo for a given file and UID. * * @param uid UID of the app requesting the read * @param path path of the requested file that will be used for database operations * @param io_path path of the requested file that will be used for IO * @return RedactionInfo on success, nullptr on failure to calculate * redaction ranges (e.g. exception was thrown in Java world) */ std::unique_ptr GetRedactionInfo(const std::string& path, const std::string& io_path, uid_t uid, pid_t tid); /** * Inserts a new entry for the given path and UID. * * @param path the path of the file to be created * @param uid UID of the calling app * @return 0 if the operation succeeded, * or errno error code if operation fails. */ int InsertFile(const std::string& path, uid_t uid); /** * Delete the file denoted by the given path on behalf of the given UID. * * @param path the path of the file to be deleted * @param uid UID of the calling app * @return 0 upon success, or errno error code if operation fails. */ int DeleteFile(const std::string& path, uid_t uid); /** * Gets directory entries for given path from MediaProvider database and lower file system * * @param uid UID of the calling app. * @param path Relative path of the directory. * @param dirp Pointer to directory stream, used to query lower file system. * @return DirectoryEntries with list of directory entries on success. * File names in a directory are obtained from MediaProvider. If a path is unknown to * MediaProvider, file names are obtained from lower file system. All directory names in the * given directory are obtained from lower file system. * An empty string in first directory entry name indicates the error occurred while obtaining * directory entries, directory entry type will hold the corresponding errno information. */ std::vector> GetDirectoryEntries(uid_t uid, const std::string& path, DIR* dirp); /** * Determines if the given UID is allowed to open the file denoted by the given path. * * Also computes and returns the RedactionInfo for a given file and |uid| * * @param path path of the requested file that will be used for database operations * @param io_path path of the requested file that will be used for IO * @param uid UID of the calling app * @param tid UID of the calling app * @param for_write specifies if the file is to be opened for write * @param redact specifies whether to attempt redaction * @return FileOpenResult containing status, uid and redaction_info */ std::unique_ptr OnFileOpen(const std::string& path, const std::string& io_path, uid_t uid, pid_t tid, int transforms_reason, bool for_write, bool redact, bool log_transforms_metrics); /** * Determines if the given UID is allowed to create a directory with the given path. * * @param path the path of the directory to be created * @param uid UID of the calling app * @return 0 if it's allowed, or errno error code if operation isn't allowed. */ int IsCreatingDirAllowed(const std::string& path, uid_t uid); /** * Determines if the given UID is allowed to delete the directory with the given path. * * @param path the path of the directory to be deleted * @param uid UID of the calling app * @return 0 if it's allowed, or errno error code if operation isn't allowed. */ int IsDeletingDirAllowed(const std::string& path, uid_t uid); /** * Determines if the given UID is allowed to open the directory with the given path. * * @param path the path of the directory to be opened * @param uid UID of the calling app * @param forWrite if it's a write access * @return 0 if it's allowed, or errno error code if operation isn't allowed. */ int IsOpendirAllowed(const std::string& path, uid_t uid, bool forWrite); /** * Determines if one of the follows is true: * 1. The package name of the given private path matches the given uid, then this uid has access to private-app directories for this package. * 2. The calling uid has special access to private-app directories: * * DownloadProvider and ExternalStorageProvider has access to private * app directories. * * Installer apps have access to Android/obb directories * * @param uid UID of the app * @param path the private path that the UID wants to access * @return true if it matches, otherwise return false. */ bool isUidAllowedAccessToDataOrObbPath(uid_t uid, const std::string& path); /** * Renames a file or directory to new path. * * @param old_path path of the file or directory to be renamed. * @param new_path new path of the file or directory to be renamed. * @param uid UID of the calling app. * @return 0 if rename is successful, errno if one of the rename fails. If return * value is 0, it's guaranteed that file/directory is moved to new_path. For any other errno * except EFAULT/EIO, it's guaranteed that file/directory is not renamed. */ int Rename(const std::string& old_path, const std::string& new_path, uid_t uid); /** * Called whenever a file has been created through FUSE. * * @param path path of the file that has been created. */ void OnFileCreated(const std::string& path); /** * Returns FileLookupResult to determine transform info for a path and uid. */ std::unique_ptr FileLookup(const std::string& path, uid_t uid, pid_t tid); /** Transforms from src to dst file */ bool Transform(const std::string& src, const std::string& dst, int transforms, int transforms_reason, uid_t read_uid, uid_t open_uid, uid_t transforms_uid); /** * Determines if to allow FUSE_LOOKUP for uid. Might allow uids that don't belong to the * MediaProvider user, depending on OEM configuration. * * @param uid linux uid to check */ bool ShouldAllowLookup(uid_t uid, int path_user_id); /** * Determines if the passed in user ID is an app clone user (paired with user 0) * * @param userId the user ID to check */ bool IsAppCloneUser(uid_t userId); /** * Initializes per-process static variables associated with the lifetime of * a managed runtime. */ static void OneTimeInit(JavaVM* vm); /** TLS Key to map a given thread to its JNIEnv. */ static pthread_key_t gJniEnvKey; private: jclass file_lookup_result_class_; jclass file_open_result_class_; jclass media_provider_class_; jobject media_provider_object_; /** Cached MediaProvider method IDs **/ jmethodID mid_insert_file_; jmethodID mid_delete_file_; jmethodID mid_on_file_open_; jmethodID mid_scan_file_; jmethodID mid_is_diraccess_allowed_; jmethodID mid_get_files_in_dir_; jmethodID mid_rename_; jmethodID mid_is_uid_allowed_access_to_data_or_obb_path_; jmethodID mid_on_file_created_; jmethodID mid_should_allow_lookup_; jmethodID mid_is_app_clone_user_; jmethodID mid_transform_; jmethodID mid_file_lookup_; /** Cached FileLookupResult field IDs **/ jfieldID fid_file_lookup_transforms_; jfieldID fid_file_lookup_transforms_reason_; jfieldID fid_file_lookup_uid_; jfieldID fid_file_lookup_transforms_complete_; jfieldID fid_file_lookup_transforms_supported_; jfieldID fid_file_lookup_io_path_; /** Cached FileOpenResult field IDs **/ jfieldID fid_file_open_status_; jfieldID fid_file_open_uid_; jfieldID fid_file_open_transforms_uid_; jfieldID fid_file_open_redaction_ranges_; jfieldID fid_file_open_fd_; /** * Auxiliary for caching MediaProvider methods. */ jmethodID CacheMethod(JNIEnv* env, const char method_name[], const char signature[]); // Attaches the current thread (if necessary) and returns the JNIEnv // associated with it. static JNIEnv* MaybeAttachCurrentThread(); // Destructor function for a given native thread. Called precisely once // by the pthreads library. static void DetachThreadFunction(void* unused); static JavaVM* gJavaVm; }; } // namespace fuse } // namespace mediaprovider #endif // MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_