Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0adcd7cf authored by Connor O'Brien's avatar Connor O'Brien
Browse files

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: default avatarConnor O'Brien <connoro@google.com>
Change-Id: I30138f95a1c56366a79eec27bbc476c9ea5773ae
parent c9083aa8
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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);
			}
+7 −6
Original line number Diff line number Diff line
@@ -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);