int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli, int argc, char **argv) { setname(); uid_t uid = cli->getUid(); if (clientHasLogCredentials(cli)) { uid = AID_ROOT; } unsigned int logMask = -1; if (argc > 1) { logMask = 0; for (int i = 1; i < argc; ++i) { int id = atoi(argv[i]); if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) { cli->sendMsg("Range Error"); return 0; } logMask |= 1 << id; } } char *buf = NULL; mBuf.formatStatistics(&buf, uid, logMask); if (!buf) { cli->sendMsg("Failed"); } else { package_string(&buf); cli->sendMsg(buf); free(buf); } return 0; }
int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli, int argc, char **argv) { setname(); if (!clientHasLogCredentials(cli)) { cli->sendMsg("Permission Denied"); return 0; } char *cp = NULL; for (int i = 1; i < argc; ++i) { char *p = cp; if (p) { cp = NULL; asprintf(&cp, "%s %s", p, argv[i]); free(p); } else { asprintf(&cp, "%s", argv[i]); } } int ret = mBuf.initPrune(cp); free(cp); if (ret) { cli->sendMsg("Invalid"); return 0; } cli->sendMsg("success"); return 0; }
int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli, int argc, char **argv) { setname(); if (!clientHasLogCredentials(cli)) { cli->sendMsg("Permission Denied"); return 0; } if (argc < 3) { cli->sendMsg("Missing Argument"); return 0; } int id = atoi(argv[1]); if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) { cli->sendMsg("Range Error"); return 0; } unsigned long size = atol(argv[2]); if (mBuf.setSize((log_id_t) id, size)) { cli->sendMsg("Range Error"); return 0; } cli->sendMsg("success"); return 0; }
int CommandListener::ClearCmd::runCommand(SocketClient *cli, int argc, char **argv) { if (!clientHasLogCredentials(cli)) { cli->sendMsg("Permission Denied"); return 0; } if (argc < 2) { cli->sendMsg("Missing Argument"); return 0; } int id = atoi(argv[1]); if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) { cli->sendMsg("Range Error"); return 0; } mBuf.clear((log_id_t) id); cli->sendMsg("success"); return 0; }
int CommandListener::ClearCmd::runCommand(SocketClient *cli, int argc, char **argv) { setname(); uid_t uid = cli->getUid(); if (clientHasLogCredentials(cli)) { uid = AID_ROOT; } if (argc < 2) { cli->sendMsg("Missing Argument"); return 0; } int id = atoi(argv[1]); if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) { cli->sendMsg("Range Error"); return 0; } mBuf.clear((log_id_t) id, uid); cli->sendMsg("success"); return 0; }
bool FlushCommand::hasReadLogs(SocketClient *client) { return clientHasLogCredentials(client); }
bool clientHasLogCredentials(SocketClient* cli) { return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid()); }
bool LogListener::onDataAvailable(SocketClient *cli) { static bool name_set; if (!name_set) { prctl(PR_SET_NAME, "logd.writer"); name_set = true; } char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) + LOGGER_ENTRY_MAX_PAYLOAD]; struct iovec iov = { buffer, sizeof(buffer) }; char control[CMSG_SPACE(sizeof(struct ucred))] __aligned(4); struct msghdr hdr = { NULL, 0, &iov, 1, control, sizeof(control), 0, }; int socket = cli->getSocket(); // To clear the entire buffer is secure/safe, but this contributes to 1.68% // overhead under logging load. We are safe because we check counts. // memset(buffer, 0, sizeof(buffer)); ssize_t n = recvmsg(socket, &hdr, 0); if (n <= (ssize_t)(sizeof(android_log_header_t))) { return false; } 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) { return false; } if (cred->uid == AID_LOGD) { // ignore log messages we send to ourself. // Such log messages are often generated by libraries we depend on // which use standard Android logging. return false; } android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer); if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) { return false; } if ((header->id == LOG_ID_SECURITY) && (!__android_log_security() || !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) { return false; } char *msg = ((char *)buffer) + sizeof(android_log_header_t); n -= sizeof(android_log_header_t); // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a // truncated message to the logs. if (logbuf->log((log_id_t)header->id, header->realtime, cred->uid, cred->pid, header->tid, msg, ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) { reader->notifyNewLog(); } return true; }