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 <connoro@google.com>
Change-Id: I30138f95a1c56366a79eec27bbc476c9ea5773ae
This commit is contained in:
Connor O'Brien 2019-09-18 13:50:15 -07:00
parent c9083aa80b
commit 0adcd7cfd0
2 changed files with 11 additions and 9 deletions

View file

@ -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);
}

View file

@ -401,7 +401,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;
@ -416,8 +417,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;
}
@ -426,10 +427,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);