TEST_F(SQLTests, test_sql_sha1) { QueryData d; query("select sha1('test') as test;", d); EXPECT_EQ(d.size(), 1U); EXPECT_EQ(d[0]["test"], "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"); }
QueryData genUsbDevices() { QueryData results; io_service_t device; char vendor[256]; char product[256]; auto matchingDict = IOServiceMatching(kIOUSBDeviceClassName); if (matchingDict == nullptr) { return results; } kern_return_t kr; io_iterator_t iter; kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); if (kr != KERN_SUCCESS) { return results; } memset(vendor, 0, 256); memset(product, 0, 256); while ((device = IOIteratorNext(iter))) { Row r; // Get the vendor of the device; CFMutableDictionaryRef vendor_dict; IORegistryEntryCreateCFProperties( device, &vendor_dict, kCFAllocatorDefault, kNilOptions); CFTypeRef vendor_obj = CFDictionaryGetValue(vendor_dict, CFSTR("USB Vendor Name")); if (vendor_obj) { CFStringRef cf_vendor = CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)vendor_obj); CFStringGetCString(cf_vendor, vendor, 255, CFStringGetSystemEncoding()); r["manufacturer"] = vendor; CFRelease(cf_vendor); } CFRelease(vendor_dict); // Get the product name of the device CFMutableDictionaryRef product_dict; IORegistryEntryCreateCFProperties( device, &product_dict, kCFAllocatorDefault, kNilOptions); CFTypeRef product_obj = CFDictionaryGetValue(product_dict, CFSTR("USB Product Name")); if (product_obj) { CFStringRef cf_product = CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)product_obj); CFStringGetCString(cf_product, product, 255, CFStringGetSystemEncoding()); r["product"] = product; CFRelease(cf_product); } CFRelease(product_dict); // Lets make sure we don't have an empty product & manufacturer if (r["product"].size() > 0 || r["manufacturer"].size() > 0) { results.push_back(r); } IOObjectRelease(device); } IOObjectRelease(iter); return results; }
TEST_F(SQLTests, test_sql_base64_decode) { QueryData d; query("select from_base64('dGVzdA==') as test;", d); EXPECT_EQ(d.size(), 1U); EXPECT_EQ(d[0]["test"], "test"); }
TEST_F(SQLTests, test_sql_md5) { QueryData d; query("select md5('test') as test;", d); EXPECT_EQ(d.size(), 1U); EXPECT_EQ(d[0]["test"], "098f6bcd4621d373cade4e832627b4f6"); }
QueryData genKernelInfo(QueryContext& context) { QueryData results; mach_port_t master_port; auto kr = IOMasterPort(bootstrap_port, &master_port); if (kr != KERN_SUCCESS) { VLOG(1) << "Could not get the IOMaster port"; return {}; } // NVRAM registry entry is :/options. auto chosen = IORegistryEntryFromPath(master_port, kIODTChosenPath_); if (chosen == 0) { VLOG(1) << "Could not get IOKit boot device"; return {}; } // Parse the boot arguments, usually none. CFMutableDictionaryRef properties; kr = IORegistryEntryCreateCFProperties( chosen, &properties, kCFAllocatorDefault, 0); IOObjectRelease(chosen); if (kr != KERN_SUCCESS) { VLOG(1) << "Could not get IOKit boot device properties"; return {}; } Row r; CFTypeRef property; if (CFDictionaryGetValueIfPresent( properties, CFSTR("boot-args"), &property)) { r["arguments"] = stringFromCFData((CFDataRef)property); } if (CFDictionaryGetValueIfPresent( properties, CFSTR("boot-device-path"), &property)) { r["device"] = getCanonicalEfiDevicePath((CFDataRef)property); } if (CFDictionaryGetValueIfPresent( properties, CFSTR("boot-file"), &property)) { r["path"] = stringFromCFData((CFDataRef)property); boost::trim(r["path"]); } // No longer need chosen properties. CFRelease(properties); // The kernel version, signature, and build information is stored in Root. auto root = IORegistryGetRootEntry(master_port); if (root != 0) { property = (CFDataRef)IORegistryEntryCreateCFProperty( root, CFSTR(kIOKitBuildVersionKey), kCFAllocatorDefault, 0); if (property != nullptr) { // The version is in the form: // Darwin Kernel Version VERSION: DATE; root:BUILD/TAG auto signature = stringFromCFString((CFStringRef)property); CFRelease(property); r["version"] = signature.substr(22, signature.find(":") - 22); } } // With the path and device, try to locate the on-disk kernel if (r.count("path") > 0) { // This does not use the device path, potential invalidation. r["md5"] = hashFromFile(HASH_TYPE_MD5, "/" + r["path"]); } results.push_back(r); return results; }
TEST_F(SQLTests, test_sql_base64_encode) { QueryData d; query("select to_base64('test') as test;", d); EXPECT_EQ(d.size(), 1U); EXPECT_EQ(d[0]["test"], "dGVzdA=="); }
void genMemoryRegion(int pid, const vm_address_t& address, const vm_size_t& size, struct vm_region_submap_info_64& info, const std::map<vm_address_t, std::string>& libraries, QueryData& results) { Row r; r["pid"] = INTEGER(pid); char addr_str[17] = {0}; sprintf(addr_str, "%016lx", address); r["start"] = "0x" + std::string(addr_str); sprintf(addr_str, "%016lx", address + size); r["end"] = "0x" + std::string(addr_str); char perms[5] = {0}; sprintf(perms, "%c%c%c", (info.protection & VM_PROT_READ) ? 'r' : '-', (info.protection & VM_PROT_WRITE) ? 'w' : '-', (info.protection & VM_PROT_EXECUTE) ? 'x' : '-'); // Mimic Linux permissions reporting. r["permissions"] = std::string(perms) + 'p'; char filename[PATH_MAX] = {0}; // Eventually we'll arrive at dynamic memory COW regions. // OS X will return a dyld_shared_cache[...] substitute alias. int bytes = proc_regionfilename(pid, address, filename, sizeof(filename)); if (info.share_mode == SM_COW && info.ref_count == 1) { // (psutil) Treat single reference SM_COW as SM_PRIVATE info.share_mode = SM_PRIVATE; } if (bytes == 0 || filename[0] == 0) { switch (info.share_mode) { case SM_COW: r["path"] = "[cow]"; break; case SM_PRIVATE: r["path"] = "[private]"; break; case SM_EMPTY: r["path"] = "[null]"; break; case SM_SHARED: case SM_TRUESHARED: r["path"] = "[shared]"; break; case SM_PRIVATE_ALIASED: r["path"] = "[private_aliased]"; break; case SM_SHARED_ALIASED: r["path"] = "[shared_aliased]"; break; default: r["path"] = "[unknown]"; } // Labeling all non-path regions pseudo is not 100% appropriate. // Practically, pivoting on non-meta (actual) paths is helpful. r["pseudo"] = "1"; } else { // The share mode is not a mutex for having a filled-in path. r["path"] = std::string(filename); r["pseudo"] = "0"; } r["offset"] = INTEGER(info.offset); r["device"] = INTEGER(info.object_id); // Fields not applicable to OS X maps. r["inode"] = "0"; // Increment the address/region request offset. results.push_back(r); // Submaps or offsets into regions may contain libraries mapped from the // dyld cache. for (const auto& library : libraries) { if (library.first > address && library.first < (address + size)) { r["offset"] = INTEGER(info.offset + (library.first - address)); r["path"] = library.second; r["pseudo"] = "0"; results.push_back(r); } } }
/// Given a pid, enumerates all loaded modules and memory pages for that process Status genMemoryMap(unsigned long pid, QueryData& results) { auto proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (proc == INVALID_HANDLE_VALUE) { Row r; r["pid"] = INTEGER(pid); r["start"] = INTEGER(-1); r["end"] = INTEGER(-1); r["permissions"] = ""; r["offset"] = INTEGER(-1); r["device"] = "-1"; r["inode"] = INTEGER(-1); r["path"] = ""; r["pseudo"] = INTEGER(-1); results.push_back(r); return Status(1, "Failed to open handle to process " + std::to_string(pid)); } auto modSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); if (modSnap == INVALID_HANDLE_VALUE) { CloseHandle(proc); return Status(1, "Failed to enumerate modules for " + std::to_string(pid)); } auto formatMemPerms = [](unsigned long perm) { std::vector<std::string> perms; for (const auto& kv : kMemoryConstants) { if (kv.first & perm) { perms.push_back(kv.second); } } return osquery::join(perms, " | "); }; MODULEENTRY32 me; MEMORY_BASIC_INFORMATION mInfo; me.dwSize = sizeof(MODULEENTRY32); auto ret = Module32First(modSnap, &me); while (ret != FALSE) { for (auto p = me.modBaseAddr; VirtualQueryEx(proc, p, &mInfo, sizeof(mInfo)) == sizeof(mInfo) && p < (me.modBaseAddr + me.modBaseSize); p += mInfo.RegionSize) { Row r; r["pid"] = INTEGER(pid); std::stringstream ssStart; ssStart << std::hex << mInfo.BaseAddress; r["start"] = "0x" + ssStart.str(); std::stringstream ssEnd; ssEnd << std::hex << std::setfill('0') << std::setw(16) << reinterpret_cast<unsigned long long>(mInfo.BaseAddress) + mInfo.RegionSize; r["end"] = "0x" + ssEnd.str(); r["permissions"] = formatMemPerms(mInfo.Protect); r["offset"] = BIGINT(reinterpret_cast<unsigned long long>(mInfo.AllocationBase)); r["device"] = "-1"; r["inode"] = INTEGER(-1); r["path"] = me.szExePath; r["pseudo"] = INTEGER(-1); results.push_back(r); } ret = Module32Next(modSnap, &me); } CloseHandle(proc); CloseHandle(modSnap); return Status(0, "Ok"); }
void genControlInfo(int* oid, size_t oid_size, QueryData& results, const std::map<std::string, std::string>& config) { Row r; if (oid_size == 0) { return; } r["oid"] = stringFromMIB(oid, oid_size); // Request the description (the canonical name) for the MIB. char response[CTL_MAX_VALUE] = {0}; size_t response_size = CTL_MAX_VALUE; int request[CTL_MAXNAME + 2] = {0, CTL_DEBUG_DESCRIPTION}; memcpy(request + 2, oid, oid_size * sizeof(int)); if (sysctl(request, oid_size + 2, response, &response_size, 0, 0) != 0) { return; } r["name"] = std::string(response); if (oid[0] > 0 && oid[0] < static_cast<int>(kControlNames.size())) { r["subsystem"] = kControlNames[oid[0]]; } // Now request structure type. response_size = CTL_MAX_VALUE; request[1] = CTL_DEBUG_TYPE; if (sysctl(request, oid_size + 2, response, &response_size, 0, 0) != 0) { // Cannot request MIB type (int, string, struct, etc). return; } size_t oid_type = 0; if (response_size > 0) { oid_type = ((size_t)response[0] & CTLTYPE); if ((oid_type == 0 || oid_type == CTLTYPE_INT) && response_size > 4) { // For whatever reason, macOS defines fewer CTLTYPE's than BSD, and // sometimes uses the format character instead of (or in addition to) // the CTLTYPE to specify the type. Here we detect a few such cases and // map them to CTLTYPE's. // TODO: Both CTLTYPE_INT and CTLTYPE_QUAD can be specified as unsigned // using a similar method. char type_char = response[4]; switch (type_char) { case 'I': oid_type = CTLTYPE_INT; break; case 'L': if (sizeof(long) == sizeof(long long)) { oid_type = CTLTYPE_QUAD; } else if (sizeof(long) == sizeof(int)) { oid_type = CTLTYPE_INT; } break; case 'S': oid_type = CTLTYPE_STRUCT; break; case 'Q': oid_type = CTLTYPE_QUAD; break; // Otherwise leave the type as it was; we have no additional knowledge } } if (oid_type < kControlTypes.size()) { r["type"] = kControlTypes[oid_type]; } } // Finally request MIB value. if (oid_type > CTLTYPE_NODE && oid_type < CTLTYPE_OPAQUE) { size_t value_size = 0; sysctl(oid, oid_size, 0, &value_size, 0, 0); if (value_size > CTL_MAX_VALUE) { // If the value size is larger than the max value, limit. value_size = CTL_MAX_VALUE; } sysctl(oid, oid_size, response, &value_size, 0, 0); if (oid_type == CTLTYPE_INT) { unsigned int value; memcpy(&value, response, sizeof(int)); r["current_value"] = INTEGER(value); } else if (oid_type == CTLTYPE_STRING) { r["current_value"] = std::string(response); } else if (oid_type == CTLTYPE_QUAD) { unsigned long long value; memcpy(&value, response, sizeof(unsigned long long)); r["current_value"] = INTEGER(value); } } // If this MIB was set using sysctl.conf add the value. if (config.count(r.at("name")) > 0) { r["config_value"] = config.at(r["name"]); } results.push_back(r); }
QueryData genProcesses(QueryContext& context) { QueryData results; // Initialize time conversions. static mach_timebase_info_data_t time_base; if (time_base.denom == 0) { mach_timebase_info(&time_base); } auto pidlist = getProcList(context); int argmax = genMaxArgs(); for (auto& pid : pidlist) { Row r; r["pid"] = INTEGER(pid); { // The command line invocation including arguments. auto args = getProcRawArgs(pid, argmax); std::string cmdline = boost::algorithm::join(args.args, " "); r["cmdline"] = cmdline; } // The process relative root and current working directory. genProcRootAndCWD(pid, r); proc_cred cred; if (getProcCred(pid, cred)) { r["parent"] = BIGINT(cred.parent); r["pgroup"] = BIGINT(cred.group); // check if process state is one of the expected ones r["state"] = (1 <= cred.status && cred.status <= 5) ? TEXT(kProcessStateMapping[cred.status]) : TEXT('?'); r["nice"] = INTEGER(cred.nice); r["uid"] = BIGINT(cred.real.uid); r["gid"] = BIGINT(cred.real.gid); r["euid"] = BIGINT(cred.effective.uid); r["egid"] = BIGINT(cred.effective.gid); r["suid"] = BIGINT(cred.saved.uid); r["sgid"] = BIGINT(cred.saved.gid); } else { continue; } // If the process is not a Zombie, try to find the path and name. if (cred.status != 5) { r["path"] = getProcPath(pid); // OS X proc_name only returns 16 bytes, use the basename of the path. r["name"] = fs::path(r["path"]).filename().string(); } else { r["path"] = ""; std::vector<char> name(17); proc_name(pid, name.data(), 16); r["name"] = std::string(name.data()); } // If the path of the executable that started the process is available and // the path exists on disk, set on_disk to 1. If the path is not // available, set on_disk to -1. If, and only if, the path of the // executable is available and the file does NOT exist on disk, set on_disk // to 0. if (r["path"].empty()) { r["on_disk"] = INTEGER(-1); } else if (pathExists(r["path"])) { r["on_disk"] = INTEGER(1); } else { r["on_disk"] = INTEGER(0); } // systems usage and time information struct rusage_info_v2 rusage_info_data; int status = proc_pid_rusage(pid, RUSAGE_INFO_V2, (rusage_info_t*)&rusage_info_data); // proc_pid_rusage returns -1 if it was unable to gather information if (status == 0) { // size/memory information r["wired_size"] = TEXT(rusage_info_data.ri_wired_size); r["resident_size"] = TEXT(rusage_info_data.ri_resident_size); r["total_size"] = TEXT(rusage_info_data.ri_phys_footprint); // time information r["user_time"] = TEXT(rusage_info_data.ri_user_time / CPU_TIME_RATIO); r["system_time"] = TEXT(rusage_info_data.ri_system_time / CPU_TIME_RATIO); // Convert the time in CPU ticks since boot to seconds. // This is relative to time not-sleeping since boot. r["start_time"] = TEXT((rusage_info_data.ri_proc_start_abstime / START_TIME_RATIO) * time_base.numer / time_base.denom); } else { r["wired_size"] = "-1"; r["resident_size"] = "-1"; r["total_size"] = "-1"; r["user_time"] = "-1"; r["system_time"] = "-1"; r["start_time"] = "-1"; } struct proc_taskinfo task_info; status = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &task_info, sizeof(task_info)); if (status == sizeof(task_info)) { r["threads"] = INTEGER(task_info.pti_threadnum); } else { r["threads"] = "-1"; } results.push_back(r); } return results; }
QueryData genProcesses(QueryContext &context) { QueryData results; auto pidlist = getProcList(context); auto parent_pid = getParentMap(pidlist); int argmax = genMaxArgs(); for (auto &pid : pidlist) { if (!context.constraints["pid"].matches<int>(pid)) { // Optimize by not searching when a pid is a constraint. continue; } Row r; r["pid"] = INTEGER(pid); r["path"] = getProcPath(pid); // OS X proc_name only returns 16 bytes, use the basename of the path. r["name"] = boost::filesystem::path(r["path"]).filename().string(); // The command line invocation including arguments. std::string cmdline = boost::algorithm::join(getProcArgs(pid, argmax), " "); boost::algorithm::trim(cmdline); r["cmdline"] = cmdline; genProcRootAndCWD(pid, r); proc_cred cred; if (getProcCred(pid, cred)) { r["uid"] = BIGINT(cred.real.uid); r["gid"] = BIGINT(cred.real.gid); r["euid"] = BIGINT(cred.effective.uid); r["egid"] = BIGINT(cred.effective.gid); } else { r["uid"] = "-1"; r["gid"] = "-1"; r["euid"] = "-1"; r["egid"] = "-1"; } // Find the parent process. const auto parent_it = parent_pid.find(pid); if (parent_it != parent_pid.end()) { r["parent"] = INTEGER(parent_it->second); } else { r["parent"] = "-1"; } // If the path of the executable that started the process is available and // the path exists on disk, set on_disk to 1. If the path is not // available, set on_disk to -1. If, and only if, the path of the // executable is available and the file does NOT exist on disk, set on_disk // to 0. r["on_disk"] = osquery::pathExists(r["path"]).toString(); // systems usage and time information struct rusage_info_v2 rusage_info_data; int rusage_status = proc_pid_rusage( pid, RUSAGE_INFO_V2, (rusage_info_t *)&rusage_info_data); // proc_pid_rusage returns -1 if it was unable to gather information if (rusage_status == 0) { // size/memory information r["wired_size"] = TEXT(rusage_info_data.ri_wired_size); r["resident_size"] = TEXT(rusage_info_data.ri_resident_size); r["phys_footprint"] = TEXT(rusage_info_data.ri_phys_footprint); // time information r["user_time"] = TEXT(rusage_info_data.ri_user_time / 1000000); r["system_time"] = TEXT(rusage_info_data.ri_system_time / 1000000); r["start_time"] = TEXT(rusage_info_data.ri_proc_start_abstime); } else { r["wired_size"] = "-1"; r["resident_size"] = "-1"; r["phys_footprint"] = "-1"; r["user_time"] = "-1"; r["system_time"] = "-1"; r["start_time"] = "-1"; } results.push_back(r); } return results; }
TEST_F(RegistryTablesTest, test_registry_non_existing_key) { QueryData results; auto ret = queryKey(kInvalidTestKey, results); EXPECT_TRUE(ret.ok()); EXPECT_TRUE(results.size() == 0); }
SVAPI_API bool PutValueIntoChildren(const NodeData & ndata, string pid, string addr) { if(pid.empty()||addr.empty()) return false; if(pid.find(".")==std::string::npos) return false; if(ndata.empty()) return false; NodeData & ndata1= const_cast< NodeData & >( ndata ); unsigned int tlen= GetNodeDataRawDataSize(ndata1); svutil::buffer tbuf; if(!tbuf.checksize(tlen)) return false; const char *data= GetNodeDataRawData(ndata1,tbuf,tlen); if(data==NULL) return false; QueryData qd; char *pdata=NULL; S_UINT rlen=0; S_UINT len=0; SVDBQUERY querybuf={0}; querybuf.len = sizeof(SVDBQUERY); querybuf.querytype=QUERY_PUT_VALUE; querybuf.datatype=S_SVSE; strcpy(querybuf.qstr,pid.c_str()); INIQUERY iquery={0}; iquery.len=sizeof(INIQUERY); iquery.datatype=D_STRING; iquery.datalen=tlen; len+=sizeof(INIQUERY); len+=tlen; querybuf.datalen=len; buffer buf; if(!buf.checksize(len)) return false; char *pt=buf.getbuffer(); memcpy(pt,&iquery,sizeof(INIQUERY)); pt+=sizeof(INIQUERY); memmove(pt,data,tlen); if(qd.Query(&querybuf,buf,len,(void **)&pdata,rlen,addr)) { if(pdata!=NULL && rlen>0) { int *pret=(int*)pdata; if(*pret==SVDB_OK) { delete [] pdata; return true; } } } if(pdata!=NULL) delete [] pdata; return false; }
QueryData genCPUID(QueryContext& context) { QueryData results; if (!genStrings(results).ok()) { return results; } // Get the CPU meta-data about the model, stepping, family. genFamily(results); int regs[4] = {-1}; for (const auto& feature_set : kCPUFeatures) { auto eax = feature_set.first; cpuid(eax, 0, regs); for (const auto& feature : feature_set.second) { Row r; r["feature"] = feature.first; // Get the return register holding the feature bit. auto feature_register = 0; if (feature.second.first == "edx") { feature_register = 3; } else if (feature.second.first == "ebx") { feature_register = 1; } else if (feature.second.first == "ecx") { feature_register = 2; } auto feature_bit = feature.second.second; r["value"] = isBitSet(feature_bit, regs[feature_register]) ? "1" : "0"; r["output_register"] = feature.second.first; r["output_bit"] = INTEGER(feature_bit); r["input_eax"] = std::to_string(eax); results.push_back(r); } } { Row r; r["output_register"] = "eax,ebx,ecx,edx"; r["output_bit"] = INTEGER(0); cpuid(0x12, 0, regs); std::stringstream sgx0; sgx0 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[0]); sgx0 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[1]); sgx0 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[2]); sgx0 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[3]); r["feature"] = "sgx0"; r["value"] = sgx0.str(); r["input_eax"] = std::to_string(0x12); results.push_back(r); cpuid(0x12, 1, regs); std::stringstream sgx1; sgx1 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[0]); sgx1 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[1]); sgx1 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[2]); sgx1 << std::hex << std::setw(8) << std::setfill('0') << static_cast<int>(regs[3]); r["feature"] = "sgx1"; r["value"] = sgx1.str(); r["input_eax"] = std::to_string(0x12) + ",1"; results.push_back(r); } return results; }
void genDetailsFromAddr(const struct ifaddrs *addr, QueryData &results) { Row r; if (addr->ifa_name != nullptr) { r["interface"] = std::string(addr->ifa_name); } else { r["interface"] = ""; } r["mac"] = macAsString(addr); if (addr->ifa_data != nullptr) { #ifdef __linux__ // Linux/Netlink interface details parsing. auto ifd = (struct rtnl_link_stats *)addr->ifa_data; r["mtu"] = "0"; r["metric"] = "0"; r["type"] = "0"; r["ipackets"] = BIGINT_FROM_UINT32(ifd->rx_packets); r["opackets"] = BIGINT_FROM_UINT32(ifd->tx_packets); r["ibytes"] = BIGINT_FROM_UINT32(ifd->rx_bytes); r["obytes"] = BIGINT_FROM_UINT32(ifd->tx_bytes); r["ierrors"] = BIGINT_FROM_UINT32(ifd->rx_errors); r["oerrors"] = BIGINT_FROM_UINT32(ifd->tx_errors); // Get Linux physical properties for the AF_PACKET entry. int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd >= 0) { struct ifreq ifr; memcpy(ifr.ifr_name, addr->ifa_name, IFNAMSIZ); if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0) { r["mtu"] = BIGINT_FROM_UINT32(ifr.ifr_mtu); } if (ioctl(fd, SIOCGIFMETRIC, &ifr) >= 0) { r["metric"] = BIGINT_FROM_UINT32(ifr.ifr_metric); } if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) { r["type"] = INTEGER_FROM_UCHAR(ifr.ifr_hwaddr.sa_family); } } // Last change is not implemented in Linux. r["last_change"] = "-1"; #else // Apple and FreeBSD interface details parsing. auto ifd = (struct if_data *)addr->ifa_data; r["type"] = INTEGER_FROM_UCHAR(ifd->ifi_type); r["mtu"] = BIGINT_FROM_UINT32(ifd->ifi_mtu); r["metric"] = BIGINT_FROM_UINT32(ifd->ifi_metric); r["ipackets"] = BIGINT_FROM_UINT32(ifd->ifi_ipackets); r["opackets"] = BIGINT_FROM_UINT32(ifd->ifi_opackets); r["ibytes"] = BIGINT_FROM_UINT32(ifd->ifi_ibytes); r["obytes"] = BIGINT_FROM_UINT32(ifd->ifi_obytes); r["ierrors"] = BIGINT_FROM_UINT32(ifd->ifi_ierrors); r["oerrors"] = BIGINT_FROM_UINT32(ifd->ifi_oerrors); r["last_change"] = BIGINT_FROM_UINT32(ifd->ifi_lastchange.tv_sec); #endif } results.push_back(r); }
void getDrivesForArray(const std::string& arrayName, MDInterface& md, QueryData& data) { std::string path(md.getPathByDevName(arrayName)); if (path.empty()) { LOG(ERROR) << "Could not get file path for " << arrayName; return; } mdu_array_info_t array; if (!md.getArrayInfo(path, array)) { return; } /* Create a vector of with all expected slot positions. As we work through * the RAID disks, we remove discovered slots */ std::vector<size_t> missingSlots(array.raid_disks); std::iota(missingSlots.begin(), missingSlots.end(), 0); /* Keep track of index in QueryData that have removed slots since we can't * make safe assumptions about it's original slot position if disk_number >= * total_disk and we're unable to deteremine total number of missing slots * until we walk thru all MD_SB_DISKS */ std::vector<size_t> removedSlots; size_t qdPos = data.size(); for (size_t i = 0; i < MD_SB_DISKS; i++) { mdu_disk_info_t disk; disk.number = i; if (!md.getDiskInfo(path, disk)) { continue; } if (disk.major > 0) { Row r; r["md_device_name"] = arrayName; r["drive_name"] = md.getDevName(disk.major, disk.minor); r["state"] = getDiskStateStr(disk.state); if (disk.raid_disk >= 0) { r["slot"] = INTEGER(disk.raid_disk); missingSlots.erase( std::remove( missingSlots.begin(), missingSlots.end(), disk.raid_disk), missingSlots.end()); /* We assume that if the disk number is less than the total disk count * of the array, then it assumes its original slot position; If the * number is greater than the disk count, then it's not safe to make * that assumption. We do this check here b/c if a recovery is targeted * for the same slot, we potentially miss identifying the original slot * position of the bad disk. */ } else if (disk.raid_disk < 0 && disk.number < array.raid_disks) { r["slot"] = std::to_string(disk.number); missingSlots.erase( std::remove(missingSlots.begin(), missingSlots.end(), disk.number), missingSlots.end()); /* Mark QueryData position as a removedSlot to handle later*/ } else { removedSlots.push_back(qdPos); } qdPos++; data.push_back(r); } } /* Handle all missing slots. See `scattered_faulty_and_removed` unit test in * `./tests/md_tables_tests.cpp`*/ for (const auto& slot : missingSlots) { if (!removedSlots.empty()) { data[removedSlots[0]]["slot"] = INTEGER(slot); removedSlots.erase(removedSlots.begin()); } else { Row r; r["md_device_name"] = arrayName; r["drive_name"] = "unknown"; r["state"] = "removed"; r["slot"] = std::to_string(slot); data.push_back(r); } } }
void genProcess(const WmiResultItem& result, QueryData& results_data) { Row r; Status s; long pid; long lPlaceHolder; std::string sPlaceHolder; /// Store current process pid for more efficient API use. auto currentPid = GetCurrentProcessId(); s = result.GetLong("ProcessId", pid); r["pid"] = s.ok() ? BIGINT(pid) : BIGINT(-1); long uid = -1; long gid = -1; HANDLE hProcess = nullptr; if (pid == currentPid) { hProcess = GetCurrentProcess(); } else { hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); } if (GetLastError() == ERROR_ACCESS_DENIED) { uid = 0; gid = 0; } result.GetString("Name", r["name"]); result.GetString("ExecutablePath", r["path"]); result.GetString("CommandLine", r["cmdline"]); result.GetString("ExecutionState", r["state"]); result.GetLong("ParentProcessId", lPlaceHolder); r["parent"] = BIGINT(lPlaceHolder); result.GetLong("Priority", lPlaceHolder); r["nice"] = INTEGER(lPlaceHolder); r["on_disk"] = osquery::pathExists(r["path"]).toString(); result.GetLong("ThreadCount", lPlaceHolder); r["threads"] = INTEGER(lPlaceHolder); std::vector<char> fileName(MAX_PATH); fileName.assign(MAX_PATH + 1, '\0'); if (pid == currentPid) { GetModuleFileName(nullptr, fileName.data(), MAX_PATH); } else { GetModuleFileNameEx(hProcess, nullptr, fileName.data(), MAX_PATH); } r["cwd"] = SQL_TEXT(fileName.data()); r["root"] = r["cwd"]; r["pgroup"] = "-1"; r["euid"] = "-1"; r["suid"] = "-1"; r["egid"] = "-1"; r["sgid"] = "-1"; FILETIME createTime; FILETIME exitTime; FILETIME kernelTime; FILETIME userTime; auto procRet = GetProcessTimes(hProcess, &createTime, &exitTime, &kernelTime, &userTime); if (procRet == FALSE) { r["user_time"] = BIGINT(-1); r["system_time"] = BIGINT(-1); r["start_time"] = BIGINT(-1); } else { // Windows stores proc times in 100 nanosecond ticks ULARGE_INTEGER utime; utime.HighPart = userTime.dwHighDateTime; utime.LowPart = userTime.dwLowDateTime; r["user_time"] = BIGINT(utime.QuadPart / 10000000); utime.HighPart = kernelTime.dwHighDateTime; utime.LowPart = kernelTime.dwLowDateTime; r["system_time"] = BIGINT(utime.QuadPart / 10000000); r["start_time"] = BIGINT(osquery::filetimeToUnixtime(createTime)); } result.GetString("PrivatePageCount", sPlaceHolder); r["wired_size"] = BIGINT(sPlaceHolder); result.GetString("WorkingSetSize", sPlaceHolder); r["resident_size"] = sPlaceHolder; result.GetString("VirtualSize", sPlaceHolder); r["total_size"] = BIGINT(sPlaceHolder); /// Get the process UID and GID from its SID HANDLE tok = nullptr; std::vector<char> tokOwner(sizeof(TOKEN_OWNER), 0x0); auto ret = OpenProcessToken(hProcess, TOKEN_READ, &tok); if (ret != 0 && tok != nullptr) { unsigned long tokOwnerBuffLen; ret = GetTokenInformation(tok, TokenUser, nullptr, 0, &tokOwnerBuffLen); if (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { tokOwner.resize(tokOwnerBuffLen); ret = GetTokenInformation( tok, TokenUser, tokOwner.data(), tokOwnerBuffLen, &tokOwnerBuffLen); } // Check if the process is using an elevated token auto elevated = FALSE; TOKEN_ELEVATION Elevation; DWORD cbSize = sizeof(TOKEN_ELEVATION); if (GetTokenInformation( tok, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) { elevated = Elevation.TokenIsElevated; } r["is_elevated_token"] = elevated ? INTEGER(1) : INTEGER(0); } if (uid != 0 && ret != 0 && !tokOwner.empty()) { auto sid = PTOKEN_OWNER(tokOwner.data())->Owner; r["uid"] = INTEGER(getUidFromSid(sid)); r["gid"] = INTEGER(getGidFromSid(sid)); } else { r["uid"] = INTEGER(uid); r["gid"] = INTEGER(gid); } if (hProcess != nullptr) { CloseHandle(hProcess); } if (tok != nullptr) { CloseHandle(tok); tok = nullptr; } results_data.push_back(r); }