diff --git a/services/cloudfiledaemon.cfg b/services/cloudfiledaemon.cfg index b485ba99734efa41d849ee17658b7e4d9642787b..78b157a3e896072a6552a1309393190bf6af4148 100644 --- a/services/cloudfiledaemon.cfg +++ b/services/cloudfiledaemon.cfg @@ -4,6 +4,7 @@ "path": ["/system/bin/sa_main", "/system/profile/cloudfiledaemon.json"], "uid": "1009", "gid": ["dfs", "user_data_rw", "ddms", "dfs_share", "readproc"], + "caps": ["CHOWN"], "sandbox": 0, "secon": "u:r:cloudfiledaemon:s0", "apl": "system_basic", diff --git a/services/cloudfiledaemon/include/cloud_disk/cloud_disk_inode.h b/services/cloudfiledaemon/include/cloud_disk/cloud_disk_inode.h index f037ebc509d1832a90fccf8f2950b6b8f0f22b37..bf10fac0482e8ffc15ee660d13f8186195deedbc 100644 --- a/services/cloudfiledaemon/include/cloud_disk/cloud_disk_inode.h +++ b/services/cloudfiledaemon/include/cloud_disk/cloud_disk_inode.h @@ -100,6 +100,7 @@ struct CloudDiskFuseData { std::shared_mutex fileIdLock; std::shared_mutex localIdLock; struct fuse_session *se; + std::string fileMgrBundle {""}; }; } // namespace CloudDisk } // namespace FileManagement diff --git a/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp b/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp index 7440e3851e8cbacac36d853923597c59c8ec4b12..7f7cc0340a0d2296cdb503a5a9d728f0ca86a6c2 100644 --- a/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp +++ b/services/cloudfiledaemon/src/cloud_disk/file_operations_cloud.cpp @@ -379,10 +379,11 @@ static unsigned int GetFileOpenFlags(int32_t fileFlags) return flags; } -static int32_t CheckBucketPath(string cloudId, string bundleName, int32_t userId, string tmpPath) +static int32_t CheckBucketPath(const string &cloudId, const string &bundleName, + struct CloudDiskFuseData *data, string tmpPath) { - string baseDir = CloudFileUtils::GetLocalBaseDir(bundleName, userId); - string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, userId); + string baseDir = CloudFileUtils::GetLocalBaseDir(bundleName, data->userId); + string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, data->userId); if (access(baseDir.c_str(), F_OK) != 0) { LOGE("bucket path's parent directory not exits, errno=%{public}d", errno); auto accessErrno = errno; @@ -403,6 +404,7 @@ static int32_t CheckBucketPath(string cloudId, string bundleName, int32_t userId return mkdirErrno; } LOGW("mkdir bucketPath success"); + CloudFileUtils::ChangeUid(data->userId, bundleName, data->fileMgrBundle, STAT_MODE_DIR, bucketPath); } return EOK; } @@ -416,7 +418,7 @@ static int32_t HandleCloudOpenSuccess(struct fuse_file_info *fi, struct CloudDis if (metaBase.fileType != FILE_TYPE_CONTENT) { string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId); string tmpPath = CloudFileUtils::GetLocalDKCachePath(inoPtr->cloudId, inoPtr->bundleName, data->userId); - auto ret = CheckBucketPath(inoPtr->cloudId, inoPtr->bundleName, data->userId, tmpPath); + auto ret = CheckBucketPath(inoPtr->cloudId, inoPtr->bundleName, data, tmpPath); if (ret != EOK) { LOGE("check bucketPath failed, ret = %{public}d", ret); return ret; @@ -432,6 +434,7 @@ static int32_t HandleCloudOpenSuccess(struct fuse_file_info *fi, struct CloudDis GetAnonyString(tmpPath).c_str(), errno); return errno; } + CloudFileUtils::ChangeUid(data->userId, inoPtr->bundleName, data->fileMgrBundle, STAT_MODE_REG, path); } unsigned int flags = GetFileOpenFlags(fi->flags); int32_t fd = open(path.c_str(), flags); @@ -699,11 +702,12 @@ void FileOperationsCloud::Open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_ } } -static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, int32_t userId, mode_t mode) +static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, + struct CloudDiskFuseData *data, mode_t mode) { HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__); - string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, userId); - string path = CloudFileUtils::GetLocalFilePath(cloudId, bundleName, userId); + string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, data->userId); + string path = CloudFileUtils::GetLocalFilePath(cloudId, bundleName, data->userId); if (access(bucketPath.c_str(), F_OK) != 0) { if (mkdir(bucketPath.c_str(), STAT_MODE_DIR) != 0) { CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD, @@ -711,6 +715,7 @@ static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, " err: " + std::to_string(errno)}); return -errno; } + CloudFileUtils::ChangeUid(data->userId, bundleName, data->fileMgrBundle, STAT_MODE_DIR, bucketPath); } int32_t fd = open(path.c_str(), (mode & O_NOFOLLOW) | O_CREAT | O_RDWR, STAT_MODE_REG); if (fd < 0) { @@ -719,6 +724,7 @@ static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, " err: " + std::to_string(errno)}); return -errno; } + CloudFileUtils::ChangeUid(data->userId, bundleName, data->fileMgrBundle, STAT_MODE_REG, path); return fd; } @@ -791,7 +797,7 @@ int32_t DoCreatFile(fuse_req_t req, fuse_ino_t parent, const char *name, CloudFile::FaultType::FILE, err, "Failed to generate cloud id"}); return -err; } - int32_t fd = CreateLocalFile(cloudId, parentInode->bundleName, data->userId, mode); + int32_t fd = CreateLocalFile(cloudId, parentInode->bundleName, data, mode); if (fd < 0) { LOGD("Create local file failed error:%{public}d", fd); return fd; diff --git a/services/cloudfiledaemon/src/fuse_manager/fuse_manager.cpp b/services/cloudfiledaemon/src/fuse_manager/fuse_manager.cpp index cb3bc373f254c803cd81a76fde486f8f54c93a84..2795949692475c407f94b34f6f016833f5ad2f26 100644 --- a/services/cloudfiledaemon/src/fuse_manager/fuse_manager.cpp +++ b/services/cloudfiledaemon/src/fuse_manager/fuse_manager.cpp @@ -78,6 +78,7 @@ static const string LOCAL_PATH_HMDFS_CLOUD_CACHE = "/hmdfs/cache/cloud_cache"; static const string DEVICE_VIEW_PHOTOS_PATH = "/account/device_view/local/data/"; static const string CLOUD_CACHE_DIR = "/.video_cache"; static const string PHOTOS_KEY = "persist.kernel.bundle_name.photos"; +static const string FILEMGR_KEY = "persist.kernel.bundle_name.filemanager"; static const string CLOUD_CACHE_XATTR_NAME = "user.cloud.cacheMap"; static const string VIDEO_TYPE_PREFIX = "VID_"; static const string HMDFS_PATH_PREFIX = "/mnt/hmdfs/"; @@ -1909,6 +1910,7 @@ int32_t FuseManager::StartFuse(int32_t userId, int32_t devFd, const string &path } cloudDiskData.userId = userId; cloudDiskData.se = se; + cloudDiskData.fileMgrBundle = system::GetParameter(FILEMGR_KEY, ""); config.max_idle_threads = 1; std::lock_guard lock(sessionMutex_); sessions_[path] = se; diff --git a/services/distributedfile.cfg b/services/distributedfile.cfg index 959fa75cc39a60540874ad5b3f0bf4034758b091..ec0393dc1e349919a3f31e2229ecf9401fd0ccbc 100644 --- a/services/distributedfile.cfg +++ b/services/distributedfile.cfg @@ -38,6 +38,7 @@ "path": ["/system/bin/sa_main", "/system/profile/cloudfileservice.json"], "uid": "dfs", "gid": ["dfs", "user_data_rw", "ddms", "dfs_share"], + "caps": ["CHOWN"], "sandbox": 0, "jobs" : { "on-start" : "services:cloudfileservice" diff --git a/test/unittests/services_daemon/mock/system_function_mock.cpp b/test/unittests/services_daemon/mock/system_function_mock.cpp index 8a73cc7d0ba156f59e4e502e0ece763251699b7c..3b8caa81d657c0b86db7413be66d13c233786c4f 100644 --- a/test/unittests/services_daemon/mock/system_function_mock.cpp +++ b/test/unittests/services_daemon/mock/system_function_mock.cpp @@ -18,7 +18,6 @@ #include #include -#include "file_operations_base.h" #include "fuse_assistant.h" #include "securec.h" diff --git a/test/unittests/utils/BUILD.gn b/test/unittests/utils/BUILD.gn index f7ca27ce5d672719f9a3a5bc75ae4b258d4d438b..7388cf317684cc48f174c6dc4a926eb307df0368 100644 --- a/test/unittests/utils/BUILD.gn +++ b/test/unittests/utils/BUILD.gn @@ -86,9 +86,14 @@ ohos_unittest("utils_directory_test") { ohos_unittest("cloud_file_utils_test") { module_out_path = "dfs_service/dfs_service" - sources = [ "./cloud_disk/cloud_file_utils_test.cpp" ] + sources = [ + "./cloud_disk/cloud_file_utils_test.cpp", + "${distributedfile_path}/test/unittests/services_daemon/mock/fuse_assistant.cpp", + "${distributedfile_path}/test/unittests/services_daemon/mock/system_function_mock.cpp", + ] include_dirs = [ + "${distributedfile_path}/test/unittests/services_daemon/mock", "${utils_path}/cloud_disk/include", "${utils_path}/log/include", ] @@ -100,6 +105,7 @@ ohos_unittest("cloud_file_utils_test") { external_deps = [ "c_utils:utils", + "libfuse:libfuse", "googletest:gmock_main", "googletest:gtest_main", "hilog:libhilog", diff --git a/test/unittests/utils/cloud_disk/cloud_file_utils_test.cpp b/test/unittests/utils/cloud_disk/cloud_file_utils_test.cpp index 53a11922f32b3bd1a5d0c1bc3fd7e1e6f5478aae..fd703343183271d5d60d7a01777953f504d6be01 100644 --- a/test/unittests/utils/cloud_disk/cloud_file_utils_test.cpp +++ b/test/unittests/utils/cloud_disk/cloud_file_utils_test.cpp @@ -16,11 +16,14 @@ #include #include "cloud_file_utils.h" +#include "fuse_assistant.h" #include "parameters.h" namespace OHOS::FileManagement::CloudDisk::Test { using namespace std; +using namespace CloudFile; using namespace OHOS; +using namespace testing; using namespace testing::ext; static const std::string FILEMANAGER_KEY = "persist.kernel.bundle_name.filemanager"; @@ -31,15 +34,26 @@ public: static void TearDownTestCase(void); void SetUp(); void TearDown(); + static inline shared_ptr insMock_ = nullptr; }; void CloudFileUtilsTest::SetUpTestCase(void) {} void CloudFileUtilsTest::TearDownTestCase(void) {} -void CloudFileUtilsTest::SetUp(void) {} +void CloudFileUtilsTest::SetUp(void) +{ + insMock_ = make_shared(); + FuseAssistantMock::ins = insMock_; + insMock_->EnableMock(); +} -void CloudFileUtilsTest::TearDown(void) {} +void CloudFileUtilsTest::TearDown(void) +{ + insMock_->DisableMock(); + FuseAssistantMock::ins = nullptr; + insMock_ = nullptr; +} /** * @tc.name: DfsService_CloudDisk_GetCloudId_001 @@ -220,4 +234,113 @@ HWTEST_F(CloudFileUtilsTest, DfsService_CloudDisk_ClearCache_04, TestSize.Level1 bool res = CloudFileUtils::ClearCache(dfsPath, cloudPath); EXPECT_EQ(res, false); } + +/** + * @tc.name: CloudFileUtils_ChangeUid + * @tc.desc: Verify ChangeUid for bundle name. + * @tc.type: FUNC + * @tc.require: ICTBV2 + */ +HWTEST_F(CloudFileUtilsTest, CloudFileUtils_ChangeUid, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CloudFileUtils_ChangeUid Start."; + try { + int32_t userId = 100; + string bundleName = ""; + uint32_t mode = 0771; + string path = ""; + string fileMgrBundle = ""; + string tempBundle = system::GetParameter(FILEMANAGER_KEY, ""); + CloudFileUtils::ChangeUid(userId, bundleName, fileMgrBundle, mode, path); + + bundleName = "com.ohos.camera"; + fileMgrBundle = system::GetParameter(FILEMANAGER_KEY, ""); + CloudFileUtils::ChangeUid(userId, bundleName, fileMgrBundle, mode, path); + + bundleName = system::GetParameter(FILEMANAGER_KEY, ""); + CloudFileUtils::ChangeUid(userId, bundleName, fileMgrBundle, mode, path); + + fileMgrBundle = ""; + CloudFileUtils::ChangeUid(userId, bundleName, fileMgrBundle, mode, path); + + fileMgrBundle = ""; + system::SetParameter(FILEMANAGER_KEY, ""); + CloudFileUtils::ChangeUid(userId, bundleName, fileMgrBundle, mode, path); + system::SetParameter(FILEMANAGER_KEY, tempBundle); + EXPECT_TRUE(true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "CloudFileUtils_ChangeUid ERROR."; + } +} + +/** + * @tc.name: CloudFileUtils_ChangeUidByCloudId + * @tc.desc: Verify ChangeUidByCloudId for path. + * @tc.type: FUNC + * @tc.require: ICTBV2 + */ +HWTEST_F(CloudFileUtilsTest, CloudFileUtils_ChangeUidByCloudId, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CloudFileUtils_ChangeUidByCloudId Start."; + try { + int32_t userId = 100; + string bundleName = "com.ohos.camera"; + uint32_t mode = 0771; + string cloudId = ""; + uid_t uid = 0; + CloudFileUtils::ChangeUidByCloudId(userId, bundleName, cloudId, mode, uid); + + cloudId = "testCloudId"; + CloudFileUtils::ChangeUidByCloudId(userId, bundleName, cloudId, mode, uid); + + userId = 0; + bundleName = ""; + CloudFileUtils::ChangeUidByCloudId(userId, bundleName, cloudId, mode, uid); + EXPECT_TRUE(true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "CloudFileUtils_ChangeUidByCloudId ERROR."; + } +} + +/** + * @tc.name: CloudFileUtils_ChangeUidByPath + * @tc.desc: Verify ChangeUidByPath for path. + * @tc.type: FUNC + * @tc.require: ICTBV2 + */ +HWTEST_F(CloudFileUtilsTest, CloudFileUtils_ChangeUidByPath, TestSize.Level1) +{ + GTEST_LOG_(INFO) << "CloudFileUtils_ChangeUidByPath Start."; + try { + mode_t mode = 0; + string path = "/data/testdir"; + uid_t uid = 0; + CloudFileUtils::ChangeUidByPath(path, mode, uid); + + uid = 1; + CloudFileUtils::ChangeUidByPath(path, mode, uid); + + path = "/data/test"; + EXPECT_CALL(*insMock_, chmod(_, _)).WillOnce(Return(-1)); + CloudFileUtils::ChangeUidByPath(path, mode, uid); + + EXPECT_CALL(*insMock_, chmod(_, _)).Times(3).WillOnce(Return(0)); + EXPECT_CALL(*insMock_, chown(_, _, _)).WillOnce(Return(-1)); + CloudFileUtils::ChangeUidByPath(path, mode, uid); + + mode = 0755; + EXPECT_CALL(*insMock_, chown(_, _, _)).Times(2).WillOnce(Return(0)); + CloudFileUtils::ChangeUidByPath(path, mode, uid); + + uid = 1000; + CloudFileUtils::ChangeUidByPath(path, mode, uid); + + EXPECT_TRUE(true); + } catch (...) { + EXPECT_TRUE(false); + GTEST_LOG_(INFO) << "CloudFileUtils_ChangeUidByPath ERROR."; + } +} } // OHOS \ No newline at end of file diff --git a/utils/BUILD.gn b/utils/BUILD.gn index abb87cfe6cb346797143db61e41e2e9559466b9c..42549d7852fb791a6e5343100dc435e465aa0356 100755 --- a/utils/BUILD.gn +++ b/utils/BUILD.gn @@ -127,6 +127,7 @@ ohos_shared_library("libdistributedfileutils") { "file_api:filemgmt_libn", "hilog:libhilog", "hisysevent:libhisysevent", + "init:libbegetutil", "ipc:ipc_core", "json:nlohmann_json_static", "napi:ace_napi", @@ -258,6 +259,7 @@ ohos_shared_library("libdistributedfileutils_lite") { "ffrt:libffrt", "hilog:libhilog", "hisysevent:libhisysevent", + "init:libbegetutil", "json:nlohmann_json_static", ] diff --git a/utils/cloud_disk/src/cloud_file_utils.cpp b/utils/cloud_disk/src/cloud_file_utils.cpp index 64539f19f42e800fe6940c26e578a955a34f4357..991c7bcb5a43c499dd657da786e2318721a83566 100644 --- a/utils/cloud_disk/src/cloud_file_utils.cpp +++ b/utils/cloud_disk/src/cloud_file_utils.cpp @@ -21,6 +21,7 @@ #include #include "fuse_ioctl.h" +#include "parameters.h" #include "utils_log.h" namespace OHOS { @@ -41,6 +42,9 @@ namespace { static const int64_t MILLISECOND_TO_NANOSECOND = 1e6; static const uint64_t DELTA_DISK = 0x9E3779B9; static const uint64_t HMDFS_HASH_COL_BIT_DISK = (0x1ULL) << 63; + static const int32_t OID_DFS = 1009; + static const int32_t UID_BASE = 200000; + static const string FILEMGR_KEY = "persist.kernel.bundle_name.filemanager"; } const string CloudFileUtils::TMP_SUFFIX = ".temp.download"; @@ -399,6 +403,64 @@ string CloudFileUtils::GetRealPath(const string &path) } return realPath.string(); } + +void CloudFileUtils::ChangeUid(int32_t userId, const string &bundleName, string fileMgrBundle, + uint32_t mode, const string &path) +{ + string baseDir = GetLocalBaseDir(bundleName, userId); + struct stat baseInfo{}; + if (stat(baseDir.c_str(), &baseInfo) != 0) { + LOGE("chmod and chown stat failed, err is %{public}d", errno); + return; + } + uid_t bundleUid = baseInfo.st_uid; + + if (fileMgrBundle == "") { + fileMgrBundle = system::GetParameter(FILEMGR_KEY, ""); + if (fileMgrBundle == "") { + LOGE("chmod and chown faild, get fileMgr bundle faild."); + return; + } + } + if (bundleName == fileMgrBundle) { + bundleUid = UID_BASE * userId + OID_DFS % UID_BASE; + } + ChangeUidByPath(path, mode, bundleUid); +} + +void CloudFileUtils::ChangeUidByCloudId(int32_t userId, const std::string &bundleName, + const std::string &cloudId, uint32_t mode, uid_t uid) +{ + string path = GetLocalFilePath(cloudId, bundleName, userId); + ChangeUidByPath(path, mode, uid); +} + +void CloudFileUtils::ChangeUidByPath(const std::string &path, mode_t mode, uid_t uid) +{ + if (uid == 0) { + LOGE("uid is not allowed."); + return; + } + + struct stat baseInfo{}; + if (stat(path.c_str(), &baseInfo) != 0) { + LOGE("chmod and chown stat failed, err is %{public}d", errno); + return; + } + + if (baseInfo.st_mode != mode) { + if (chmod(path.c_str(), mode) != 0) { + LOGE("chmod failed, err is %{public}d", errno); + return; + } + } + + if (baseInfo.st_uid != uid) { + if (chown(path.c_str(), uid, OID_DFS) != 0) { + LOGE("chown failed, err is %{public}d", errno); + } + } +} } // namespace CloudDisk } // namespace FileManagement } // namespace OHOS diff --git a/utils/inner_api/cloud_file_utils.h b/utils/inner_api/cloud_file_utils.h index 0dc5b9ae28f2470109f1a854afa37371719ed550..d35b1a8bc1797d50a30bab2b3920f9aad1d0582d 100644 --- a/utils/inner_api/cloud_file_utils.h +++ b/utils/inner_api/cloud_file_utils.h @@ -79,6 +79,11 @@ public: static void TeaTransform(uint32_t buf[4], uint32_t const in[]); static void Str2HashBuf(const char *msg, size_t len, uint32_t *buf, int num); static bool IsDotDotdot(const std::string &name); + static void ChangeUid(int32_t userId, const std::string &bundleName, std::string fileMgrBundle, + uint32_t mode, const std::string &path); + static void ChangeUidByCloudId(int32_t userId, const std::string &bundleName, + const std::string &cloudId, uint32_t mode, uid_t uid); + static void ChangeUidByPath(const std::string &path, mode_t mode, uid_t uid); static const std::string TMP_SUFFIX; private: static bool EndsWith(const std::string &fullString, const std::string &ending);