Skip to content

Commit

Permalink
ANDROID: fix overflow in /proc/uid_cputime/remove_uid_range
Browse files Browse the repository at this point in the history
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
  • Loading branch information
cobrien7 authored and ananjaser1211 committed Aug 31, 2024
1 parent 35e6223 commit e69f300
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 9 deletions.
7 changes: 4 additions & 3 deletions drivers/cpufreq/cpufreq_times.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
13 changes: 7 additions & 6 deletions drivers/misc/uid_sys_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);
Expand Down

0 comments on commit e69f300

Please sign in to comment.