From e69f30025a6740d90a18bb058d53e288555c0e3e Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 18 Sep 2019 13:50:15 -0700 Subject: [PATCH] ANDROID: fix overflow in /proc/uid_cputime/remove_uid_range Writing large values to remove_uid_range can cause an overflow & system hang. To prevent this, read in the start and end of the range using kstrtouint to ensure the full range can fit in a uid_t, and use a u64 for our loop counters to avoid overflow when the range ends at UINT_MAX. Test: "echo '9223372036854775807-9223372036854775807' > \ /proc/uid_cputime/remove_uid_range" now returns error instead of hanging Bug: 139902843 Signed-off-by: Connor O'Brien Change-Id: I30138f95a1c56366a79eec27bbc476c9ea5773ae --- drivers/cpufreq/cpufreq_times.c | 7 ++++--- drivers/misc/uid_sys_stats.c | 13 +++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 5b5248a7c87c..210742e963e0 100755 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -523,13 +523,14 @@ void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end) struct uid_entry *uid_entry; struct hlist_node *tmp; unsigned long flags; + u64 uid; spin_lock_irqsave(&uid_lock, flags); - for (; uid_start <= uid_end; uid_start++) { + for (uid = uid_start; uid <= uid_end; uid++) { hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp, - hash, uid_start) { - if (uid_start == uid_entry->uid) { + hash, uid) { + if (uid == uid_entry->uid) { hash_del_rcu(&uid_entry->hash); call_rcu(&uid_entry->rcu, uid_entry_reclaim); } diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 34733dd39971..43785f94bca5 100755 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -407,7 +407,8 @@ static ssize_t uid_remove_write(struct file *file, struct hlist_node *tmp; char uids[128]; char *start_uid, *end_uid = NULL; - long int uid_start = 0, uid_end = 0; + uid_t uid_start = 0, uid_end = 0; + u64 uid; if (count >= sizeof(uids)) count = sizeof(uids) - 1; @@ -422,8 +423,8 @@ static ssize_t uid_remove_write(struct file *file, if (!start_uid || !end_uid) return -EINVAL; - if (kstrtol(start_uid, 10, &uid_start) != 0 || - kstrtol(end_uid, 10, &uid_end) != 0) { + if (kstrtouint(start_uid, 10, &uid_start) != 0 || + kstrtouint(end_uid, 10, &uid_end) != 0) { return -EINVAL; } @@ -432,10 +433,10 @@ static ssize_t uid_remove_write(struct file *file, rt_mutex_lock(&uid_lock); - for (; uid_start <= uid_end; uid_start++) { + for (uid = uid_start; uid <= uid_end; uid++) { hash_for_each_possible_safe(hash_table, uid_entry, tmp, - hash, (uid_t)uid_start) { - if (uid_start == uid_entry->uid) { + hash, uid) { + if (uid == uid_entry->uid) { remove_uid_tasks(uid_entry); hash_del(&uid_entry->hash); kfree(uid_entry);