lmkd: Restrict process record modifications to the client that created it am: 12ab187885 am: 9de60e7c00
am: 0969160c36
Change-Id: Ic2982985fda224727cc9c8482e76f19c425bb2e4
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 9de7ff7..e7a23ef 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -45,6 +45,7 @@
#include <log/log.h>
#include <log/log_event_list.h>
#include <log/log_time.h>
+#include <private/android_filesystem_config.h>
#include <psi/psi.h>
#include <system/thread_defs.h>
@@ -240,6 +241,7 @@
/* data required to handle socket events */
struct sock_event_handler_info {
int sock;
+ pid_t pid;
struct event_handler_info handler_info;
};
@@ -490,6 +492,7 @@
int pidfd;
uid_t uid;
int oomadj;
+ pid_t reg_pid; /* PID of the process that registered this record */
struct proc *pidhash_next;
};
@@ -845,7 +848,35 @@
return buf;
}
-static void cmd_procprio(LMKD_CTRL_PACKET packet) {
+static bool claim_record(struct proc *procp, pid_t pid) {
+ if (procp->reg_pid == pid) {
+ /* Record already belongs to the registrant */
+ return true;
+ }
+ if (procp->reg_pid == 0) {
+ /* Old registrant is gone, claim the record */
+ procp->reg_pid = pid;
+ return true;
+ }
+ /* The record is owned by another registrant */
+ return false;
+}
+
+static void remove_claims(pid_t pid) {
+ int i;
+
+ for (i = 0; i < PIDHASH_SZ; i++) {
+ struct proc *procp = pidhash[i];
+ while (procp) {
+ if (procp->reg_pid == pid) {
+ procp->reg_pid = 0;
+ }
+ procp = procp->pidhash_next;
+ }
+ }
+}
+
+static void cmd_procprio(LMKD_CTRL_PACKET packet, struct ucred *cred) {
struct proc *procp;
char path[LINE_MAX];
char val[20];
@@ -954,24 +985,47 @@
procp->pid = params.pid;
procp->pidfd = pidfd;
procp->uid = params.uid;
+ procp->reg_pid = cred->pid;
procp->oomadj = params.oomadj;
proc_insert(procp);
} else {
+ if (!claim_record(procp, cred->pid)) {
+ char buf[LINE_MAX];
+ /* Only registrant of the record can remove it */
+ ALOGE("%s (%d, %d) attempts to modify a process registered by another client",
+ proc_get_name(cred->pid, buf, sizeof(buf)), cred->uid, cred->pid);
+ return;
+ }
proc_unslot(procp);
procp->oomadj = params.oomadj;
proc_slot(procp);
}
}
-static void cmd_procremove(LMKD_CTRL_PACKET packet) {
+static void cmd_procremove(LMKD_CTRL_PACKET packet, struct ucred *cred) {
struct lmk_procremove params;
+ struct proc *procp;
lmkd_pack_get_procremove(packet, ¶ms);
+
if (use_inkernel_interface) {
stats_remove_taskname(params.pid, kpoll_info.poll_fd);
return;
}
+ procp = pid_lookup(params.pid);
+ if (!procp) {
+ return;
+ }
+
+ if (!claim_record(procp, cred->pid)) {
+ char buf[LINE_MAX];
+ /* Only registrant of the record can remove it */
+ ALOGE("%s (%d, %d) attempts to unregister a process registered by another client",
+ proc_get_name(cred->pid, buf, sizeof(buf)), cred->uid, cred->pid);
+ return;
+ }
+
/*
* WARNING: After pid_remove() procp is freed and can't be used!
* Therefore placed at the end of the function.
@@ -979,7 +1033,7 @@
pid_remove(params.pid);
}
-static void cmd_procpurge() {
+static void cmd_procpurge(struct ucred *cred) {
int i;
struct proc *procp;
struct proc *next;
@@ -989,20 +1043,17 @@
return;
}
- for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
- procadjslot_list[i].next = &procadjslot_list[i];
- procadjslot_list[i].prev = &procadjslot_list[i];
- }
-
for (i = 0; i < PIDHASH_SZ; i++) {
procp = pidhash[i];
while (procp) {
next = procp->pidhash_next;
- free(procp);
+ /* Purge only records created by the requestor */
+ if (claim_record(procp, cred->pid)) {
+ pid_remove(procp->pid);
+ }
procp = next;
}
}
- memset(&pidhash[0], 0, sizeof(pidhash));
}
static void inc_killcnt(int oomadj) {
@@ -1153,19 +1204,50 @@
close(data_sock[dsock_idx].sock);
data_sock[dsock_idx].sock = -1;
+
+ /* Mark all records of the old registrant as unclaimed */
+ remove_claims(data_sock[dsock_idx].pid);
}
-static int ctrl_data_read(int dsock_idx, char *buf, size_t bufsz) {
- int ret = 0;
+static ssize_t ctrl_data_read(int dsock_idx, char *buf, size_t bufsz, struct ucred *sender_cred) {
+ struct iovec iov = { buf, bufsz };
+ char control[CMSG_SPACE(sizeof(struct ucred))];
+ struct msghdr hdr = {
+ NULL, 0, &iov, 1, control, sizeof(control), 0,
+ };
+ ssize_t ret;
- ret = TEMP_FAILURE_RETRY(read(data_sock[dsock_idx].sock, buf, bufsz));
-
+ ret = TEMP_FAILURE_RETRY(recvmsg(data_sock[dsock_idx].sock, &hdr, 0));
if (ret == -1) {
- ALOGE("control data socket read failed; errno=%d", errno);
- } else if (ret == 0) {
- ALOGE("Got EOF on control data socket");
- ret = -1;
+ ALOGE("control data socket read failed; %s", strerror(errno));
+ return -1;
}
+ if (ret == 0) {
+ ALOGE("Got EOF on control data socket");
+ return -1;
+ }
+
+ struct ucred* cred = NULL;
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
+ while (cmsg != NULL) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
+ cred = (struct ucred*)CMSG_DATA(cmsg);
+ break;
+ }
+ cmsg = CMSG_NXTHDR(&hdr, cmsg);
+ }
+
+ if (cred == NULL) {
+ ALOGE("Failed to retrieve sender credentials");
+ /* Close the connection */
+ ctrl_data_close(dsock_idx);
+ return -1;
+ }
+
+ memcpy(sender_cred, cred, sizeof(struct ucred));
+
+ /* Store PID of the peer */
+ data_sock[dsock_idx].pid = cred->pid;
return ret;
}
@@ -1187,13 +1269,14 @@
static void ctrl_command_handler(int dsock_idx) {
LMKD_CTRL_PACKET packet;
+ struct ucred cred;
int len;
enum lmk_cmd cmd;
int nargs;
int targets;
int kill_cnt;
- len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE);
+ len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE, &cred);
if (len <= 0)
return;
@@ -1217,17 +1300,17 @@
case LMK_PROCPRIO:
if (nargs != 3)
goto wronglen;
- cmd_procprio(packet);
+ cmd_procprio(packet, &cred);
break;
case LMK_PROCREMOVE:
if (nargs != 1)
goto wronglen;
- cmd_procremove(packet);
+ cmd_procremove(packet, &cred);
break;
case LMK_PROCPURGE:
if (nargs != 0)
goto wronglen;
- cmd_procpurge();
+ cmd_procpurge(&cred);
break;
case LMK_GETKILLCNT:
if (nargs != 2)
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 76b6055..982a188 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -4,5 +4,5 @@
group lmkd system readproc
capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
critical
- socket lmkd seqpacket 0660 system system
+ socket lmkd seqpacket+passcred 0660 system system
writepid /dev/cpuset/system-background/tasks