lmkd: Fix UAF caused by calling pid_remove() from the watchdog thread am: ba9ea6e3d6 am: d5dbec8d23 am: 02af677a49
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/2235075 Change-Id: I166f3e4f03e886d5a6d9c684267ac46ec1f9d698 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
6057c60d5b
22
lmkd.cpp
22
lmkd.cpp
|
|
@ -510,6 +510,7 @@ struct proc {
|
|||
uid_t uid;
|
||||
int oomadj;
|
||||
pid_t reg_pid; /* PID of the process that registered this record */
|
||||
bool valid;
|
||||
struct proc *pidhash_next;
|
||||
};
|
||||
|
||||
|
|
@ -941,6 +942,7 @@ static void proc_insert(struct proc *procp) {
|
|||
proc_slot(procp);
|
||||
}
|
||||
|
||||
// Can be called only from the main thread.
|
||||
static int pid_remove(int pid) {
|
||||
int hval = pid_hashfn(pid);
|
||||
struct proc *procp;
|
||||
|
|
@ -970,6 +972,15 @@ static int pid_remove(int pid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pid_invalidate(int pid) {
|
||||
std::shared_lock lock(adjslot_list_lock);
|
||||
struct proc *procp = pid_lookup(pid);
|
||||
|
||||
if (procp) {
|
||||
procp->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a string to a file.
|
||||
* Returns false if the file does not exist.
|
||||
|
|
@ -1220,6 +1231,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred
|
|||
procp->uid = params.uid;
|
||||
procp->reg_pid = cred->pid;
|
||||
procp->oomadj = params.oomadj;
|
||||
procp->valid = true;
|
||||
proc_insert(procp);
|
||||
} else {
|
||||
if (!claim_record(procp, cred->pid)) {
|
||||
|
|
@ -2092,7 +2104,7 @@ static struct proc *proc_adj_prev(int oomadj, int pid) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// When called from a non-main thread, adjslot_list_lock read lock should be taken.
|
||||
// Can be called only from the main thread.
|
||||
static struct proc *proc_get_heaviest(int oomadj) {
|
||||
struct adjslot_list *head = &procadjslot_list[ADJTOSLOT(oomadj)];
|
||||
struct adjslot_list *curr = head->next;
|
||||
|
|
@ -2154,11 +2166,11 @@ static void watchdog_callback() {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (reaper.kill({ target.pidfd, target.pid, target.uid }, true) == 0) {
|
||||
if (target.valid && reaper.kill({ target.pidfd, target.pid, target.uid }, true) == 0) {
|
||||
ALOGW("lmkd watchdog killed process %d, oom_score_adj %d", target.pid, oom_score);
|
||||
killinfo_log(&target, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
|
||||
// WARNING: do not use target after pid_remove()
|
||||
pid_remove(target.pid);
|
||||
// Can't call pid_remove() from non-main thread, therefore just invalidate the record
|
||||
pid_invalidate(target.pid);
|
||||
break;
|
||||
}
|
||||
prev_pid = target.pid;
|
||||
|
|
@ -2296,7 +2308,7 @@ static int kill_one_process(struct proc* procp, int min_oom_score, struct kill_i
|
|||
char buf[PAGE_SIZE];
|
||||
char desc[LINE_MAX];
|
||||
|
||||
if (!read_proc_status(pid, buf, sizeof(buf))) {
|
||||
if (!procp->valid || !read_proc_status(pid, buf, sizeof(buf))) {
|
||||
goto out;
|
||||
}
|
||||
if (!parse_status_tag(buf, PROC_STATUS_TGID_FIELD, &tgid)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue