Loading llkd/README.md +7 −6 Original line number Original line Diff line number Diff line Loading @@ -86,7 +86,13 @@ kernel instead of deal with more graceful kill operation. Android Properties Android Properties ------------------ ------------------ Android Properties llkd respond to (*prop*_ms parms are in milliseconds): The following are the Android Properties llkd respond to. *prop*_ms named properties are in milliseconds. Properties that use comma (*,*) separator for lists, use a leading separator to preserve default and add or subtract entries with (*optional*) plus (*+*) and minus (*-*) prefixes respectively. For these lists, the string "*false*" is synonymous with an *empty* list, and *blank* or *missing* resorts to the specified *default* value. #### ro.config.low_ram #### ro.config.low_ram device is configured with limited memory. device is configured with limited memory. Loading Loading @@ -137,7 +143,6 @@ default 2 minutes samples of threads for D or Z. #### ro.llk.stack #### ro.llk.stack default cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable default cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable comma separated list of kernel symbols. comma separated list of kernel symbols. The string "*false*" is the equivalent to an *empty* list. Look for kernel stack symbols that if ever persistently present can Look for kernel stack symbols that if ever persistently present can indicate a subsystem is locked up. indicate a subsystem is locked up. Beware, check does not on purpose do forward scheduling ABA except by polling Beware, check does not on purpose do forward scheduling ABA except by polling Loading @@ -154,7 +159,6 @@ concerns on user builds prevents this checking. default 0,1,2 (kernel, init and [kthreadd]) plus process names default 0,1,2 (kernel, init and [kthreadd]) plus process names init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*]. [watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*]. The string "*false*" is the equivalent to an *empty* list. Do not watch these processes. A process can be comm, cmdline or pid reference. Do not watch these processes. A process can be comm, cmdline or pid reference. NB: automated default here can be larger than the current maximum property NB: automated default here can be larger than the current maximum property size of 92. size of 92. Loading @@ -162,18 +166,15 @@ NB: false is a very very very unlikely process to want to blacklist. #### ro.llk.blacklist.parent #### ro.llk.blacklist.parent default 0,2,adbd (kernel, [kthreadd] and adbd). default 0,2,adbd (kernel, [kthreadd] and adbd). The string "*false*" is the equivalent to an *empty* list. Do not watch processes that have this parent. Do not watch processes that have this parent. A parent process can be comm, cmdline or pid reference. A parent process can be comm, cmdline or pid reference. #### ro.llk.blacklist.uid #### ro.llk.blacklist.uid default *empty* or false, comma separated list of uid numbers or names. default *empty* or false, comma separated list of uid numbers or names. The string "*false*" is the equivalent to an *empty* list. Do not watch processes that match this uid. Do not watch processes that match this uid. #### ro.llk.blacklist.process.stack #### ro.llk.blacklist.process.stack default process names init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. default process names init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. The string "*false*" is the equivalent to an *empty* list. This subset of processes are not monitored for live lock stack signatures. This subset of processes are not monitored for live lock stack signatures. Also prevents the sepolicy violation associated with processes that block Also prevents the sepolicy violation associated with processes that block ptrace, as these can not be checked anyways. ptrace, as these can not be checked anyways. Loading llkd/libllkd.cpp +64 −44 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <pwd.h> // getpwuid() #include <pwd.h> // getpwuid() #include <signal.h> #include <signal.h> #include <stdint.h> #include <stdint.h> #include <string.h> #include <sys/cdefs.h> // ___STRING, __predict_true() and _predict_false() #include <sys/cdefs.h> // ___STRING, __predict_true() and _predict_false() #include <sys/mman.h> // mlockall() #include <sys/mman.h> // mlockall() #include <sys/prctl.h> #include <sys/prctl.h> Loading Loading @@ -617,17 +618,24 @@ std::string llkFormat(bool flag) { std::string llkFormat(const std::unordered_set<std::string>& blacklist) { std::string llkFormat(const std::unordered_set<std::string>& blacklist) { std::string ret; std::string ret; for (const auto& entry : blacklist) { for (const auto& entry : blacklist) { if (ret.size()) { if (!ret.empty()) ret += ","; ret += ","; } ret += entry; ret += entry; } } return ret; return ret; } } // This function parses the properties as a list, incorporating the supplied // default. A leading comma separator means preserve the defaults and add // entries (with an optional leading + sign), or removes entries with a leading // - sign. // // We only officially support comma separators, but wetware being what they // We only officially support comma separators, but wetware being what they // are will take some liberty and I do not believe they should be punished. // are will take some liberty and I do not believe they should be punished. std::unordered_set<std::string> llkSplit(const std::string& s) { std::unordered_set<std::string> llkSplit(const std::string& prop, const std::string& def) { auto s = android::base::GetProperty(prop, def); constexpr char separators[] = ", \t:;"; if (!s.empty() && (s != def) && strchr(separators, s[0])) s = def + s; std::unordered_set<std::string> result; std::unordered_set<std::string> result; // Special case, allow boolean false to empty the list, otherwise expected // Special case, allow boolean false to empty the list, otherwise expected Loading @@ -637,9 +645,29 @@ std::unordered_set<std::string> llkSplit(const std::string& s) { size_t base = 0; size_t base = 0; while (s.size() > base) { while (s.size() > base) { auto found = s.find_first_of(", \t:", base); auto found = s.find_first_of(separators, base); // Only emplace content, empty entries are not an option // Only emplace unique content, empty entries are not an option if (found != base) result.emplace(s.substr(base, found - base)); if (found != base) { switch (s[base]) { case '-': ++base; if (base >= s.size()) break; if (base != found) { auto have = result.find(s.substr(base, found - base)); if (have != result.end()) result.erase(have); } break; case '+': ++base; if (base >= s.size()) break; if (base == found) break; // FALLTHRU (for gcc, lint, pcc, etc; following for clang) FALLTHROUGH_INTENDED; default: result.emplace(s.substr(base, found - base)); break; } } if (found == s.npos) break; if (found == s.npos) break; base = found + 1; base = found + 1; } } Loading @@ -648,13 +676,21 @@ std::unordered_set<std::string> llkSplit(const std::string& s) { bool llkSkipName(const std::string& name, bool llkSkipName(const std::string& name, const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) { const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) { if ((name.size() == 0) || (blacklist.size() == 0)) { if (name.empty() || blacklist.empty()) return false; return false; } return blacklist.find(name) != blacklist.end(); return blacklist.find(name) != blacklist.end(); } } bool llkSkipProc(proc* procp, const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) { if (!procp) return false; if (llkSkipName(std::to_string(procp->pid), blacklist)) return true; if (llkSkipName(procp->getComm(), blacklist)) return true; if (llkSkipName(procp->getCmdline(), blacklist)) return true; if (llkSkipName(android::base::Basename(procp->getCmdline()), blacklist)) return true; return false; } bool llkSkipPid(pid_t pid) { bool llkSkipPid(pid_t pid) { return llkSkipName(std::to_string(pid), llkBlacklistProcess); return llkSkipName(std::to_string(pid), llkBlacklistProcess); } } Loading Loading @@ -730,11 +766,7 @@ bool llkCheckStack(proc* procp, const std::string& piddir) { } } // Don't check process that are known to block ptrace, save sepolicy noise. // Don't check process that are known to block ptrace, save sepolicy noise. if (llkSkipName(std::to_string(procp->pid), llkBlacklistStack)) return false; if (llkSkipProc(procp, llkBlacklistStack)) return false; if (llkSkipName(procp->getComm(), llkBlacklistStack)) return false; if (llkSkipName(procp->getCmdline(), llkBlacklistStack)) return false; if (llkSkipName(android::base::Basename(procp->getCmdline()), llkBlacklistStack)) return false; auto kernel_stack = ReadFile(piddir + "/stack"); auto kernel_stack = ReadFile(piddir + "/stack"); if (kernel_stack.empty()) { if (kernel_stack.empty()) { LOG(VERBOSE) << piddir << "/stack empty comm=" << procp->getComm() LOG(VERBOSE) << piddir << "/stack empty comm=" << procp->getComm() Loading Loading @@ -780,12 +812,12 @@ void llkCheckSchedUpdate(proc* procp, const std::string& piddir) { // but if there are problems we assume at least a few // but if there are problems we assume at least a few // samples of reads occur before we take any real action. // samples of reads occur before we take any real action. std::string schedString = ReadFile(piddir + "/sched"); std::string schedString = ReadFile(piddir + "/sched"); if (schedString.size() == 0) { if (schedString.empty()) { // /schedstat is not as standardized, but in 3.1+ // /schedstat is not as standardized, but in 3.1+ // Android devices, the third field is nr_switches // Android devices, the third field is nr_switches // from /sched: // from /sched: schedString = ReadFile(piddir + "/schedstat"); schedString = ReadFile(piddir + "/schedstat"); if (schedString.size() == 0) { if (schedString.empty()) { return; return; } } auto val = static_cast<unsigned long long>(-1); auto val = static_cast<unsigned long long>(-1); Loading Loading @@ -943,7 +975,7 @@ milliseconds llkCheck(bool checkRunning) { // Get the process stat // Get the process stat std::string stat = ReadFile(piddir + "/stat"); std::string stat = ReadFile(piddir + "/stat"); if (stat.size() == 0) { if (stat.empty()) { continue; continue; } } unsigned tid = -1; unsigned tid = -1; Loading Loading @@ -1032,11 +1064,10 @@ milliseconds llkCheck(bool checkRunning) { if (pprocp == nullptr) { if (pprocp == nullptr) { pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?'); pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?'); } } if ((pprocp != nullptr) && if (pprocp) { (llkSkipName(pprocp->getComm(), llkBlacklistParent) || if (llkSkipProc(pprocp, llkBlacklistParent)) break; llkSkipName(pprocp->getCmdline(), llkBlacklistParent) || } else { llkSkipName(android::base::Basename(pprocp->getCmdline()), llkBlacklistParent))) { if (llkSkipName(std::to_string(ppid), llkBlacklistParent)) break; break; } } if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) { if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) { Loading Loading @@ -1135,21 +1166,15 @@ milliseconds llkCheck(bool checkRunning) { if (!p->second.updated) { if (!p->second.updated) { IF_ALOG(LOG_VERBOSE, LOG_TAG) { IF_ALOG(LOG_VERBOSE, LOG_TAG) { std::string ppidCmdline = llkProcGetName(p->second.ppid, nullptr, nullptr); std::string ppidCmdline = llkProcGetName(p->second.ppid, nullptr, nullptr); if (ppidCmdline.size()) { if (!ppidCmdline.empty()) ppidCmdline = "(" + ppidCmdline + ")"; ppidCmdline = "(" + ppidCmdline + ")"; } std::string pidCmdline; std::string pidCmdline; if (p->second.pid != p->second.tid) { if (p->second.pid != p->second.tid) { pidCmdline = llkProcGetName(p->second.pid, nullptr, p->second.getCmdline()); pidCmdline = llkProcGetName(p->second.pid, nullptr, p->second.getCmdline()); if (pidCmdline.size()) { if (!pidCmdline.empty()) pidCmdline = "(" + pidCmdline + ")"; pidCmdline = "(" + pidCmdline + ")"; } } } std::string tidCmdline = std::string tidCmdline = llkProcGetName(p->second.tid, p->second.getComm(), p->second.getCmdline()); llkProcGetName(p->second.tid, p->second.getComm(), p->second.getCmdline()); if (tidCmdline.size()) { if (!tidCmdline.empty()) tidCmdline = "(" + tidCmdline + ")"; tidCmdline = "(" + tidCmdline + ")"; } LOG(VERBOSE) << "thread " << p->second.ppid << ppidCmdline << "->" << p->second.pid LOG(VERBOSE) << "thread " << p->second.ppid << ppidCmdline << "->" << p->second.pid << pidCmdline << "->" << p->second.tid << tidCmdline << " removed"; << pidCmdline << "->" << p->second.tid << tidCmdline << " removed"; } } Loading Loading @@ -1226,13 +1251,11 @@ bool llkInit(const char* threadname) { llkValidate(); // validate all (effectively minus llkTimeoutMs) llkValidate(); // validate all (effectively minus llkTimeoutMs) #ifdef __PTRACE_ENABLED__ #ifdef __PTRACE_ENABLED__ if (debuggable) { if (debuggable) { llkCheckStackSymbols = llkSplit( llkCheckStackSymbols = llkSplit(LLK_CHECK_STACK_PROPERTY, LLK_CHECK_STACK_DEFAULT); android::base::GetProperty(LLK_CHECK_STACK_PROPERTY, LLK_CHECK_STACK_DEFAULT)); } } std::string defaultBlacklistStack(LLK_BLACKLIST_STACK_DEFAULT); std::string defaultBlacklistStack(LLK_BLACKLIST_STACK_DEFAULT); if (!debuggable) defaultBlacklistStack += ",logd,/system/bin/logd"; if (!debuggable) defaultBlacklistStack += ",logd,/system/bin/logd"; llkBlacklistStack = llkSplit( llkBlacklistStack = llkSplit(LLK_BLACKLIST_STACK_PROPERTY, defaultBlacklistStack); android::base::GetProperty(LLK_BLACKLIST_STACK_PROPERTY, defaultBlacklistStack)); #endif #endif std::string defaultBlacklistProcess( std::string defaultBlacklistProcess( std::to_string(kernelPid) + "," + std::to_string(initPid) + "," + std::to_string(kernelPid) + "," + std::to_string(initPid) + "," + Loading @@ -1244,17 +1267,14 @@ bool llkInit(const char* threadname) { for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) { for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) { defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]"; defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]"; } } defaultBlacklistProcess = llkBlacklistProcess = llkSplit(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess); android::base::GetProperty(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess); llkBlacklistProcess = llkSplit(defaultBlacklistProcess); if (!llkSkipName("[khungtaskd]")) { // ALWAYS ignore as special if (!llkSkipName("[khungtaskd]")) { // ALWAYS ignore as special llkBlacklistProcess.emplace("[khungtaskd]"); llkBlacklistProcess.emplace("[khungtaskd]"); } } llkBlacklistParent = llkSplit(android::base::GetProperty( llkBlacklistParent = llkSplit(LLK_BLACKLIST_PARENT_PROPERTY, LLK_BLACKLIST_PARENT_PROPERTY, std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) + std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) + "," LLK_BLACKLIST_PARENT_DEFAULT)); "," LLK_BLACKLIST_PARENT_DEFAULT); llkBlacklistUid = llkBlacklistUid = llkSplit(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT); llkSplit(android::base::GetProperty(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT)); // internal watchdog // internal watchdog ::signal(SIGALRM, llkAlarmHandler); ::signal(SIGALRM, llkAlarmHandler); Loading llkd/tests/llkd_test.cpp +2 −1 Original line number Original line Diff line number Diff line Loading @@ -87,7 +87,8 @@ seconds llkdSleepPeriod(char state) { execute("stop llkd-1"); execute("stop llkd-1"); rest(); rest(); std::string setprop("setprop "); std::string setprop("setprop "); execute((setprop + LLK_CHECK_STACK_PROPERTY + " SyS_openat").c_str()); // Manually check that SyS_openat is _added_ to the list when restarted execute((setprop + LLK_CHECK_STACK_PROPERTY + " ,SyS_openat").c_str()); rest(); rest(); execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str()); execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str()); rest(); rest(); Loading Loading
llkd/README.md +7 −6 Original line number Original line Diff line number Diff line Loading @@ -86,7 +86,13 @@ kernel instead of deal with more graceful kill operation. Android Properties Android Properties ------------------ ------------------ Android Properties llkd respond to (*prop*_ms parms are in milliseconds): The following are the Android Properties llkd respond to. *prop*_ms named properties are in milliseconds. Properties that use comma (*,*) separator for lists, use a leading separator to preserve default and add or subtract entries with (*optional*) plus (*+*) and minus (*-*) prefixes respectively. For these lists, the string "*false*" is synonymous with an *empty* list, and *blank* or *missing* resorts to the specified *default* value. #### ro.config.low_ram #### ro.config.low_ram device is configured with limited memory. device is configured with limited memory. Loading Loading @@ -137,7 +143,6 @@ default 2 minutes samples of threads for D or Z. #### ro.llk.stack #### ro.llk.stack default cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable default cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable comma separated list of kernel symbols. comma separated list of kernel symbols. The string "*false*" is the equivalent to an *empty* list. Look for kernel stack symbols that if ever persistently present can Look for kernel stack symbols that if ever persistently present can indicate a subsystem is locked up. indicate a subsystem is locked up. Beware, check does not on purpose do forward scheduling ABA except by polling Beware, check does not on purpose do forward scheduling ABA except by polling Loading @@ -154,7 +159,6 @@ concerns on user builds prevents this checking. default 0,1,2 (kernel, init and [kthreadd]) plus process names default 0,1,2 (kernel, init and [kthreadd]) plus process names init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*]. [watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*]. The string "*false*" is the equivalent to an *empty* list. Do not watch these processes. A process can be comm, cmdline or pid reference. Do not watch these processes. A process can be comm, cmdline or pid reference. NB: automated default here can be larger than the current maximum property NB: automated default here can be larger than the current maximum property size of 92. size of 92. Loading @@ -162,18 +166,15 @@ NB: false is a very very very unlikely process to want to blacklist. #### ro.llk.blacklist.parent #### ro.llk.blacklist.parent default 0,2,adbd (kernel, [kthreadd] and adbd). default 0,2,adbd (kernel, [kthreadd] and adbd). The string "*false*" is the equivalent to an *empty* list. Do not watch processes that have this parent. Do not watch processes that have this parent. A parent process can be comm, cmdline or pid reference. A parent process can be comm, cmdline or pid reference. #### ro.llk.blacklist.uid #### ro.llk.blacklist.uid default *empty* or false, comma separated list of uid numbers or names. default *empty* or false, comma separated list of uid numbers or names. The string "*false*" is the equivalent to an *empty* list. Do not watch processes that match this uid. Do not watch processes that match this uid. #### ro.llk.blacklist.process.stack #### ro.llk.blacklist.process.stack default process names init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. default process names init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. The string "*false*" is the equivalent to an *empty* list. This subset of processes are not monitored for live lock stack signatures. This subset of processes are not monitored for live lock stack signatures. Also prevents the sepolicy violation associated with processes that block Also prevents the sepolicy violation associated with processes that block ptrace, as these can not be checked anyways. ptrace, as these can not be checked anyways. Loading
llkd/libllkd.cpp +64 −44 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <pwd.h> // getpwuid() #include <pwd.h> // getpwuid() #include <signal.h> #include <signal.h> #include <stdint.h> #include <stdint.h> #include <string.h> #include <sys/cdefs.h> // ___STRING, __predict_true() and _predict_false() #include <sys/cdefs.h> // ___STRING, __predict_true() and _predict_false() #include <sys/mman.h> // mlockall() #include <sys/mman.h> // mlockall() #include <sys/prctl.h> #include <sys/prctl.h> Loading Loading @@ -617,17 +618,24 @@ std::string llkFormat(bool flag) { std::string llkFormat(const std::unordered_set<std::string>& blacklist) { std::string llkFormat(const std::unordered_set<std::string>& blacklist) { std::string ret; std::string ret; for (const auto& entry : blacklist) { for (const auto& entry : blacklist) { if (ret.size()) { if (!ret.empty()) ret += ","; ret += ","; } ret += entry; ret += entry; } } return ret; return ret; } } // This function parses the properties as a list, incorporating the supplied // default. A leading comma separator means preserve the defaults and add // entries (with an optional leading + sign), or removes entries with a leading // - sign. // // We only officially support comma separators, but wetware being what they // We only officially support comma separators, but wetware being what they // are will take some liberty and I do not believe they should be punished. // are will take some liberty and I do not believe they should be punished. std::unordered_set<std::string> llkSplit(const std::string& s) { std::unordered_set<std::string> llkSplit(const std::string& prop, const std::string& def) { auto s = android::base::GetProperty(prop, def); constexpr char separators[] = ", \t:;"; if (!s.empty() && (s != def) && strchr(separators, s[0])) s = def + s; std::unordered_set<std::string> result; std::unordered_set<std::string> result; // Special case, allow boolean false to empty the list, otherwise expected // Special case, allow boolean false to empty the list, otherwise expected Loading @@ -637,9 +645,29 @@ std::unordered_set<std::string> llkSplit(const std::string& s) { size_t base = 0; size_t base = 0; while (s.size() > base) { while (s.size() > base) { auto found = s.find_first_of(", \t:", base); auto found = s.find_first_of(separators, base); // Only emplace content, empty entries are not an option // Only emplace unique content, empty entries are not an option if (found != base) result.emplace(s.substr(base, found - base)); if (found != base) { switch (s[base]) { case '-': ++base; if (base >= s.size()) break; if (base != found) { auto have = result.find(s.substr(base, found - base)); if (have != result.end()) result.erase(have); } break; case '+': ++base; if (base >= s.size()) break; if (base == found) break; // FALLTHRU (for gcc, lint, pcc, etc; following for clang) FALLTHROUGH_INTENDED; default: result.emplace(s.substr(base, found - base)); break; } } if (found == s.npos) break; if (found == s.npos) break; base = found + 1; base = found + 1; } } Loading @@ -648,13 +676,21 @@ std::unordered_set<std::string> llkSplit(const std::string& s) { bool llkSkipName(const std::string& name, bool llkSkipName(const std::string& name, const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) { const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) { if ((name.size() == 0) || (blacklist.size() == 0)) { if (name.empty() || blacklist.empty()) return false; return false; } return blacklist.find(name) != blacklist.end(); return blacklist.find(name) != blacklist.end(); } } bool llkSkipProc(proc* procp, const std::unordered_set<std::string>& blacklist = llkBlacklistProcess) { if (!procp) return false; if (llkSkipName(std::to_string(procp->pid), blacklist)) return true; if (llkSkipName(procp->getComm(), blacklist)) return true; if (llkSkipName(procp->getCmdline(), blacklist)) return true; if (llkSkipName(android::base::Basename(procp->getCmdline()), blacklist)) return true; return false; } bool llkSkipPid(pid_t pid) { bool llkSkipPid(pid_t pid) { return llkSkipName(std::to_string(pid), llkBlacklistProcess); return llkSkipName(std::to_string(pid), llkBlacklistProcess); } } Loading Loading @@ -730,11 +766,7 @@ bool llkCheckStack(proc* procp, const std::string& piddir) { } } // Don't check process that are known to block ptrace, save sepolicy noise. // Don't check process that are known to block ptrace, save sepolicy noise. if (llkSkipName(std::to_string(procp->pid), llkBlacklistStack)) return false; if (llkSkipProc(procp, llkBlacklistStack)) return false; if (llkSkipName(procp->getComm(), llkBlacklistStack)) return false; if (llkSkipName(procp->getCmdline(), llkBlacklistStack)) return false; if (llkSkipName(android::base::Basename(procp->getCmdline()), llkBlacklistStack)) return false; auto kernel_stack = ReadFile(piddir + "/stack"); auto kernel_stack = ReadFile(piddir + "/stack"); if (kernel_stack.empty()) { if (kernel_stack.empty()) { LOG(VERBOSE) << piddir << "/stack empty comm=" << procp->getComm() LOG(VERBOSE) << piddir << "/stack empty comm=" << procp->getComm() Loading Loading @@ -780,12 +812,12 @@ void llkCheckSchedUpdate(proc* procp, const std::string& piddir) { // but if there are problems we assume at least a few // but if there are problems we assume at least a few // samples of reads occur before we take any real action. // samples of reads occur before we take any real action. std::string schedString = ReadFile(piddir + "/sched"); std::string schedString = ReadFile(piddir + "/sched"); if (schedString.size() == 0) { if (schedString.empty()) { // /schedstat is not as standardized, but in 3.1+ // /schedstat is not as standardized, but in 3.1+ // Android devices, the third field is nr_switches // Android devices, the third field is nr_switches // from /sched: // from /sched: schedString = ReadFile(piddir + "/schedstat"); schedString = ReadFile(piddir + "/schedstat"); if (schedString.size() == 0) { if (schedString.empty()) { return; return; } } auto val = static_cast<unsigned long long>(-1); auto val = static_cast<unsigned long long>(-1); Loading Loading @@ -943,7 +975,7 @@ milliseconds llkCheck(bool checkRunning) { // Get the process stat // Get the process stat std::string stat = ReadFile(piddir + "/stat"); std::string stat = ReadFile(piddir + "/stat"); if (stat.size() == 0) { if (stat.empty()) { continue; continue; } } unsigned tid = -1; unsigned tid = -1; Loading Loading @@ -1032,11 +1064,10 @@ milliseconds llkCheck(bool checkRunning) { if (pprocp == nullptr) { if (pprocp == nullptr) { pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?'); pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?'); } } if ((pprocp != nullptr) && if (pprocp) { (llkSkipName(pprocp->getComm(), llkBlacklistParent) || if (llkSkipProc(pprocp, llkBlacklistParent)) break; llkSkipName(pprocp->getCmdline(), llkBlacklistParent) || } else { llkSkipName(android::base::Basename(pprocp->getCmdline()), llkBlacklistParent))) { if (llkSkipName(std::to_string(ppid), llkBlacklistParent)) break; break; } } if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) { if ((llkBlacklistUid.size() != 0) && llkSkipUid(procp->getUid())) { Loading Loading @@ -1135,21 +1166,15 @@ milliseconds llkCheck(bool checkRunning) { if (!p->second.updated) { if (!p->second.updated) { IF_ALOG(LOG_VERBOSE, LOG_TAG) { IF_ALOG(LOG_VERBOSE, LOG_TAG) { std::string ppidCmdline = llkProcGetName(p->second.ppid, nullptr, nullptr); std::string ppidCmdline = llkProcGetName(p->second.ppid, nullptr, nullptr); if (ppidCmdline.size()) { if (!ppidCmdline.empty()) ppidCmdline = "(" + ppidCmdline + ")"; ppidCmdline = "(" + ppidCmdline + ")"; } std::string pidCmdline; std::string pidCmdline; if (p->second.pid != p->second.tid) { if (p->second.pid != p->second.tid) { pidCmdline = llkProcGetName(p->second.pid, nullptr, p->second.getCmdline()); pidCmdline = llkProcGetName(p->second.pid, nullptr, p->second.getCmdline()); if (pidCmdline.size()) { if (!pidCmdline.empty()) pidCmdline = "(" + pidCmdline + ")"; pidCmdline = "(" + pidCmdline + ")"; } } } std::string tidCmdline = std::string tidCmdline = llkProcGetName(p->second.tid, p->second.getComm(), p->second.getCmdline()); llkProcGetName(p->second.tid, p->second.getComm(), p->second.getCmdline()); if (tidCmdline.size()) { if (!tidCmdline.empty()) tidCmdline = "(" + tidCmdline + ")"; tidCmdline = "(" + tidCmdline + ")"; } LOG(VERBOSE) << "thread " << p->second.ppid << ppidCmdline << "->" << p->second.pid LOG(VERBOSE) << "thread " << p->second.ppid << ppidCmdline << "->" << p->second.pid << pidCmdline << "->" << p->second.tid << tidCmdline << " removed"; << pidCmdline << "->" << p->second.tid << tidCmdline << " removed"; } } Loading Loading @@ -1226,13 +1251,11 @@ bool llkInit(const char* threadname) { llkValidate(); // validate all (effectively minus llkTimeoutMs) llkValidate(); // validate all (effectively minus llkTimeoutMs) #ifdef __PTRACE_ENABLED__ #ifdef __PTRACE_ENABLED__ if (debuggable) { if (debuggable) { llkCheckStackSymbols = llkSplit( llkCheckStackSymbols = llkSplit(LLK_CHECK_STACK_PROPERTY, LLK_CHECK_STACK_DEFAULT); android::base::GetProperty(LLK_CHECK_STACK_PROPERTY, LLK_CHECK_STACK_DEFAULT)); } } std::string defaultBlacklistStack(LLK_BLACKLIST_STACK_DEFAULT); std::string defaultBlacklistStack(LLK_BLACKLIST_STACK_DEFAULT); if (!debuggable) defaultBlacklistStack += ",logd,/system/bin/logd"; if (!debuggable) defaultBlacklistStack += ",logd,/system/bin/logd"; llkBlacklistStack = llkSplit( llkBlacklistStack = llkSplit(LLK_BLACKLIST_STACK_PROPERTY, defaultBlacklistStack); android::base::GetProperty(LLK_BLACKLIST_STACK_PROPERTY, defaultBlacklistStack)); #endif #endif std::string defaultBlacklistProcess( std::string defaultBlacklistProcess( std::to_string(kernelPid) + "," + std::to_string(initPid) + "," + std::to_string(kernelPid) + "," + std::to_string(initPid) + "," + Loading @@ -1244,17 +1267,14 @@ bool llkInit(const char* threadname) { for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) { for (int cpu = 1; cpu < get_nprocs_conf(); ++cpu) { defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]"; defaultBlacklistProcess += ",[watchdog/" + std::to_string(cpu) + "]"; } } defaultBlacklistProcess = llkBlacklistProcess = llkSplit(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess); android::base::GetProperty(LLK_BLACKLIST_PROCESS_PROPERTY, defaultBlacklistProcess); llkBlacklistProcess = llkSplit(defaultBlacklistProcess); if (!llkSkipName("[khungtaskd]")) { // ALWAYS ignore as special if (!llkSkipName("[khungtaskd]")) { // ALWAYS ignore as special llkBlacklistProcess.emplace("[khungtaskd]"); llkBlacklistProcess.emplace("[khungtaskd]"); } } llkBlacklistParent = llkSplit(android::base::GetProperty( llkBlacklistParent = llkSplit(LLK_BLACKLIST_PARENT_PROPERTY, LLK_BLACKLIST_PARENT_PROPERTY, std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) + std::to_string(kernelPid) + "," + std::to_string(kthreaddPid) + "," LLK_BLACKLIST_PARENT_DEFAULT)); "," LLK_BLACKLIST_PARENT_DEFAULT); llkBlacklistUid = llkBlacklistUid = llkSplit(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT); llkSplit(android::base::GetProperty(LLK_BLACKLIST_UID_PROPERTY, LLK_BLACKLIST_UID_DEFAULT)); // internal watchdog // internal watchdog ::signal(SIGALRM, llkAlarmHandler); ::signal(SIGALRM, llkAlarmHandler); Loading
llkd/tests/llkd_test.cpp +2 −1 Original line number Original line Diff line number Diff line Loading @@ -87,7 +87,8 @@ seconds llkdSleepPeriod(char state) { execute("stop llkd-1"); execute("stop llkd-1"); rest(); rest(); std::string setprop("setprop "); std::string setprop("setprop "); execute((setprop + LLK_CHECK_STACK_PROPERTY + " SyS_openat").c_str()); // Manually check that SyS_openat is _added_ to the list when restarted execute((setprop + LLK_CHECK_STACK_PROPERTY + " ,SyS_openat").c_str()); rest(); rest(); execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str()); execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str()); rest(); rest(); Loading