Loading cmds/installd/Android.bp +15 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,20 @@ package { default_applicable_licenses: ["frameworks_native_license"], } aconfig_declarations { name: "installd_flags", package: "android.installd.flags", container: "system", srcs: [ "installd_flags.aconfig", ], } cc_aconfig_library { name: "installd_flags_c_lib", aconfig_declarations: "installd_flags", } cc_defaults { name: "installd_defaults", Loading Loading @@ -50,6 +64,7 @@ cc_defaults { "server_configurable_flags", ], static_libs: [ "installd_flags_c_lib", "libasync_safe", "libext2_uuid", ], Loading cmds/installd/InstalldNativeService.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ #include "QuotaUtils.h" #include "SysTrace.h" #include <android_installd_flags.h> #ifndef LOG_TAG #define LOG_TAG "installd" #endif Loading @@ -89,6 +91,7 @@ using android::base::StringPrintf; using android::base::unique_fd; using android::os::ParcelFileDescriptor; using std::endl; namespace flags = android::installd::flags; namespace android { namespace installd { Loading Loading @@ -882,6 +885,11 @@ binder::Status InstalldNativeService::createAppDataLocked( chown_app_profile_dir(packageName, appId, userId); } if (flags::enable_set_inode_quotas() && !PrepareAppInodeQuota(uuid ? uuid->c_str() : "", uid)) { PLOG(ERROR) << "Failed to set hard quota " + path; } if (!prepare_app_profile_dir(packageName, appId, userId)) { return error("Failed to prepare profiles for " + packageName); } Loading cmds/installd/QuotaUtils.cpp +65 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <unordered_map> #include <sys/quota.h> #include <sys/statvfs.h> #include <android-base/logging.h> Loading Loading @@ -143,5 +144,69 @@ int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) { } bool PrepareAppInodeQuota(const std::string& uuid, uid_t uid) { const std::string device = FindQuotaDeviceForUuid(uuid); // Skip when device has no quotas present if (device.empty()) { return true; } #if APPLY_HARD_QUOTAS struct dqblk dq; if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) { PLOG(WARNING) << "Failed to find quota for " << uid; return false; } if (dq.dqb_ihardlimit == 0) { auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str()); struct statvfs stat; if (statvfs(path.c_str(), &stat) != 0) { PLOG(WARNING) << "Failed to statvfs " << path; return false; } dq.dqb_valid |= QIF_ILIMITS; // limiting the app to only 50% of the inodes available, // reducing the limit will be too restrictive especially for apps with valid use cases dq.dqb_ihardlimit = (stat.f_files / 2); if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) { PLOG(WARNING) << "Failed to set hard quota for " << uid; return false; } else { LOG(DEBUG) << "Applied hard quotas for " << uid; return true; } } else { // Hard quota already set; assume it's reasonable return true; } #else // Hard quotas disabled return true; #endif } int64_t GetInodesQuotaHardLimitsForUid(const std::string& uuid, uid_t uid) { const std::string device = FindQuotaDeviceForUuid(uuid); if (device.empty()) { return 0; } struct dqblk dq; if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) { if (errno != ESRCH) { PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid; } return -1; } else { return dq.dqb_ihardlimit; } } } // namespace installd } // namespace android cmds/installd/QuotaUtils.h +10 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,16 @@ int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid); /* Get the current occupied space in bytes for a project id or -1 if fails */ int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId); /** * Ensure that we have a hard-limit quota to protect against abusive apps; * they should never use more than 50% of inodes. */ bool PrepareAppInodeQuota(const std::string& uuid, uid_t uid); /* Get the inode quota hard limits for a uid or -1 if fails */ int64_t GetInodesQuotaHardLimitsForUid(const std::string& uuid, uid_t uid); } // namespace installd } // namespace android Loading cmds/installd/installd_flags.aconfig 0 → 100644 +10 −0 Original line number Diff line number Diff line package: "android.installd.flags" container: "system" flag { name: "enable_set_inode_quotas" namespace: "mediaprovider" description: "This flag controls setting inode quota limits for apps" bug: "293301664" is_fixed_read_only: true } No newline at end of file Loading
cmds/installd/Android.bp +15 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,20 @@ package { default_applicable_licenses: ["frameworks_native_license"], } aconfig_declarations { name: "installd_flags", package: "android.installd.flags", container: "system", srcs: [ "installd_flags.aconfig", ], } cc_aconfig_library { name: "installd_flags_c_lib", aconfig_declarations: "installd_flags", } cc_defaults { name: "installd_defaults", Loading Loading @@ -50,6 +64,7 @@ cc_defaults { "server_configurable_flags", ], static_libs: [ "installd_flags_c_lib", "libasync_safe", "libext2_uuid", ], Loading
cmds/installd/InstalldNativeService.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ #include "QuotaUtils.h" #include "SysTrace.h" #include <android_installd_flags.h> #ifndef LOG_TAG #define LOG_TAG "installd" #endif Loading @@ -89,6 +91,7 @@ using android::base::StringPrintf; using android::base::unique_fd; using android::os::ParcelFileDescriptor; using std::endl; namespace flags = android::installd::flags; namespace android { namespace installd { Loading Loading @@ -882,6 +885,11 @@ binder::Status InstalldNativeService::createAppDataLocked( chown_app_profile_dir(packageName, appId, userId); } if (flags::enable_set_inode_quotas() && !PrepareAppInodeQuota(uuid ? uuid->c_str() : "", uid)) { PLOG(ERROR) << "Failed to set hard quota " + path; } if (!prepare_app_profile_dir(packageName, appId, userId)) { return error("Failed to prepare profiles for " + packageName); } Loading
cmds/installd/QuotaUtils.cpp +65 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <unordered_map> #include <sys/quota.h> #include <sys/statvfs.h> #include <android-base/logging.h> Loading Loading @@ -143,5 +144,69 @@ int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) { } bool PrepareAppInodeQuota(const std::string& uuid, uid_t uid) { const std::string device = FindQuotaDeviceForUuid(uuid); // Skip when device has no quotas present if (device.empty()) { return true; } #if APPLY_HARD_QUOTAS struct dqblk dq; if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) { PLOG(WARNING) << "Failed to find quota for " << uid; return false; } if (dq.dqb_ihardlimit == 0) { auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str()); struct statvfs stat; if (statvfs(path.c_str(), &stat) != 0) { PLOG(WARNING) << "Failed to statvfs " << path; return false; } dq.dqb_valid |= QIF_ILIMITS; // limiting the app to only 50% of the inodes available, // reducing the limit will be too restrictive especially for apps with valid use cases dq.dqb_ihardlimit = (stat.f_files / 2); if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) { PLOG(WARNING) << "Failed to set hard quota for " << uid; return false; } else { LOG(DEBUG) << "Applied hard quotas for " << uid; return true; } } else { // Hard quota already set; assume it's reasonable return true; } #else // Hard quotas disabled return true; #endif } int64_t GetInodesQuotaHardLimitsForUid(const std::string& uuid, uid_t uid) { const std::string device = FindQuotaDeviceForUuid(uuid); if (device.empty()) { return 0; } struct dqblk dq; if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, reinterpret_cast<char*>(&dq)) != 0) { if (errno != ESRCH) { PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid; } return -1; } else { return dq.dqb_ihardlimit; } } } // namespace installd } // namespace android
cmds/installd/QuotaUtils.h +10 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,16 @@ int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid); /* Get the current occupied space in bytes for a project id or -1 if fails */ int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId); /** * Ensure that we have a hard-limit quota to protect against abusive apps; * they should never use more than 50% of inodes. */ bool PrepareAppInodeQuota(const std::string& uuid, uid_t uid); /* Get the inode quota hard limits for a uid or -1 if fails */ int64_t GetInodesQuotaHardLimitsForUid(const std::string& uuid, uid_t uid); } // namespace installd } // namespace android Loading
cmds/installd/installd_flags.aconfig 0 → 100644 +10 −0 Original line number Diff line number Diff line package: "android.installd.flags" container: "system" flag { name: "enable_set_inode_quotas" namespace: "mediaprovider" description: "This flag controls setting inode quota limits for apps" bug: "293301664" is_fixed_read_only: true } No newline at end of file