mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
Cleanup inode table implementations and unblacklist
This commit is contained in:
parent
c823de82a0
commit
b2debf509a
@ -149,4 +149,39 @@ Status parsePlist(const boost::filesystem::path& path,
|
||||
Status parsePlistContent(const std::string& fileContent,
|
||||
boost::property_tree::ptree& tree);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
/**
|
||||
* @brief Iterate over proc process, returns a list of pids.
|
||||
*
|
||||
* @param processes output list of process pids as strings (int paths in proc).
|
||||
*
|
||||
* @return status of iteration.
|
||||
*/
|
||||
Status procProcesses(std::vector<std::string>& processes);
|
||||
|
||||
/**
|
||||
* @brief Iterate over a proc process's descriptors, return a list of fds.
|
||||
*
|
||||
* @param process a string pid from proc.
|
||||
* @param descriptors output list of descriptor numbers as strings.
|
||||
*
|
||||
* @return status of iteration, failure if the process path did not exist.
|
||||
*/
|
||||
Status procDescriptors(const std::string& process,
|
||||
std::vector<std::string>& descriptors);
|
||||
|
||||
/**
|
||||
* @brief Read a descriptor's virtual path.
|
||||
*
|
||||
* @param process a string pid from proc.
|
||||
* @param descriptor a string descriptor number for a proc.
|
||||
* @param result output variable with value of link.
|
||||
*
|
||||
* @return status of read, failure on permission error or filesystem error.
|
||||
*/
|
||||
Status procReadDescriptor(const std::string& process,
|
||||
const std::string& descriptor,
|
||||
std::string& result);
|
||||
#endif
|
||||
}
|
||||
|
@ -4,6 +4,10 @@ if(APPLE)
|
||||
)
|
||||
|
||||
ADD_OSQUERY_LINK("-framework Foundation")
|
||||
elseif(UBUNTU OR CENTOS)
|
||||
ADD_OSQUERY_LIBRARY(osquery_filesystem_linux
|
||||
linux/proc.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
ADD_OSQUERY_LIBRARY(osquery_filesystem
|
||||
|
@ -16,8 +16,6 @@
|
||||
|
||||
#include "osquery/filesystem.h"
|
||||
|
||||
using osquery::Status;
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
|
77
osquery/filesystem/linux/proc.cpp
Normal file
77
osquery/filesystem/linux/proc.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "osquery/filesystem.h"
|
||||
|
||||
namespace osquery {
|
||||
|
||||
const std::string kLinuxProcPath = "/proc";
|
||||
|
||||
Status procProcesses(std::vector<std::string>& processes) {
|
||||
boost::regex process_filter("\\d+");
|
||||
|
||||
// Iterate over each process-like directory in proc.
|
||||
boost::filesystem::directory_iterator it(kLinuxProcPath), end;
|
||||
try {
|
||||
for (; it != end; ++it) {
|
||||
if (boost::filesystem::is_directory(it->status())) {
|
||||
boost::smatch what;
|
||||
if (boost::regex_match(
|
||||
it->path().leaf().string(), what, process_filter)) {
|
||||
processes.push_back(it->path().leaf().string());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (boost::filesystem::filesystem_error& e) {
|
||||
VLOG(1) << "Exception iterating Linux processes " << e.what();
|
||||
return Status(1, e.what());
|
||||
}
|
||||
|
||||
return Status(0, "OK");
|
||||
}
|
||||
|
||||
Status procDescriptors(const std::string& process,
|
||||
std::vector<std::string>& descriptors) {
|
||||
auto descriptors_path = kLinuxProcPath + "/" + process + "/fd";
|
||||
try {
|
||||
// Access to the process' /fd may be restricted.
|
||||
boost::filesystem::directory_iterator it(descriptors_path), end;
|
||||
for (; it != end; ++it) {
|
||||
descriptors.push_back(it->path().leaf().string());
|
||||
}
|
||||
} catch (boost::filesystem::filesystem_error& e) {
|
||||
return Status(1, "Cannot access descriptors for " + process);
|
||||
}
|
||||
|
||||
return Status(0, "OK");
|
||||
}
|
||||
|
||||
Status procReadDescriptor(const std::string& process,
|
||||
const std::string& descriptor,
|
||||
std::string& result) {
|
||||
auto link = kLinuxProcPath + "/" + process + "/fd/" + descriptor;
|
||||
auto path_max = pathconf(link.c_str(), _PC_PATH_MAX);
|
||||
auto result_path = (char*)malloc(path_max);
|
||||
|
||||
memset(result_path, 0, path_max);
|
||||
auto size = readlink(link.c_str(), result_path, path_max);
|
||||
if (size >= 0) {
|
||||
result = std::string(result_path);
|
||||
}
|
||||
|
||||
free(result_path);
|
||||
if (size >= 0) {
|
||||
return Status(0, "OK");
|
||||
} else {
|
||||
return Status(1, "Could not read path");
|
||||
}
|
||||
}
|
||||
}
|
@ -3,27 +3,18 @@
|
||||
#include <exception>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pwd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "osquery/core.h"
|
||||
#include "osquery/database.h"
|
||||
#include "osquery/logger.h"
|
||||
|
||||
// From uapi/linux/sock_diag.h
|
||||
// From linux/sock_diag.h (<= 3.6)
|
||||
@ -69,12 +60,7 @@ int send_diag_msg(int sockfd, int family) {
|
||||
|
||||
sa.nl_family = AF_NETLINK;
|
||||
|
||||
// IPv4 vs IPv6
|
||||
if (family == 1) {
|
||||
conn_req.sdiag_family = AF_INET;
|
||||
} else if (family == 2) {
|
||||
conn_req.sdiag_family = AF_INET6;
|
||||
}
|
||||
conn_req.sdiag_family = family;
|
||||
conn_req.sdiag_protocol = IPPROTO_TCP;
|
||||
|
||||
conn_req.idiag_states = TCPF_ALL & ~((1 << TCP_SYN_RECV) |
|
||||
@ -101,7 +87,7 @@ int send_diag_msg(int sockfd, int family) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
Row parse_diag_msg(struct inet_diag_msg *diag_msg, int rtalen) {
|
||||
Row parse_diag_msg(struct inet_diag_msg *diag_msg, int rtalen, int family) {
|
||||
char local_addr_buf[INET6_ADDRSTRLEN];
|
||||
char remote_addr_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
@ -131,17 +117,16 @@ Row parse_diag_msg(struct inet_diag_msg *diag_msg, int rtalen) {
|
||||
|
||||
// populate the Row from diag_msg fields
|
||||
Row row;
|
||||
row["inode"] = boost::lexical_cast<std::string>(diag_msg->idiag_inode);
|
||||
row["local_port"] =
|
||||
boost::lexical_cast<std::string>(ntohs(diag_msg->id.idiag_sport));
|
||||
row["remote_port"] =
|
||||
boost::lexical_cast<std::string>(ntohs(diag_msg->id.idiag_dport));
|
||||
row["local_ip"] = boost::lexical_cast<std::string>(local_addr_buf);
|
||||
row["remote_ip"] = boost::lexical_cast<std::string>(remote_addr_buf);
|
||||
row["inode"] = INTEGER(diag_msg->idiag_inode);
|
||||
row["local_port"] = INTEGER(ntohs(diag_msg->id.idiag_sport));
|
||||
row["remote_port"] = INTEGER(ntohs(diag_msg->id.idiag_dport));
|
||||
row["local_ip"] = TEXT(local_addr_buf);
|
||||
row["remote_ip"] = TEXT(remote_addr_buf);
|
||||
row["family"] = INTEGER(family);
|
||||
return row;
|
||||
}
|
||||
|
||||
void getPortInode(QueryData &results, int type) {
|
||||
void getPortInode(QueryData &results, int family) {
|
||||
int nl_sock = 0;
|
||||
int numbytes = 0;
|
||||
int rtalen = 0;
|
||||
@ -156,7 +141,7 @@ void getPortInode(QueryData &results, int type) {
|
||||
}
|
||||
|
||||
// send the inet_diag message
|
||||
if (send_diag_msg(nl_sock, type) < 0) {
|
||||
if (send_diag_msg(nl_sock, family) < 0) {
|
||||
close(nl_sock);
|
||||
return;
|
||||
}
|
||||
@ -181,10 +166,10 @@ void getPortInode(QueryData &results, int type) {
|
||||
diag_msg = (struct inet_diag_msg *)NLMSG_DATA(nlh);
|
||||
rtalen = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*diag_msg));
|
||||
try {
|
||||
results.push_back(parse_diag_msg(diag_msg, rtalen));
|
||||
results.push_back(parse_diag_msg(diag_msg, rtalen, family));
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
LOG(ERROR) << e.what();
|
||||
LOG(ERROR) << "Could not parse NL message " << e.what();
|
||||
}
|
||||
|
||||
nlh = NLMSG_NEXT(nlh, numbytes);
|
||||
@ -195,10 +180,9 @@ void getPortInode(QueryData &results, int type) {
|
||||
}
|
||||
|
||||
QueryData genPortInode() {
|
||||
|
||||
QueryData results;
|
||||
getPortInode(results, 1); // IPv4
|
||||
getPortInode(results, 2); // IPv6
|
||||
getPortInode(results, AF_INET);
|
||||
getPortInode(results, AF_INET6);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/regex.hpp>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "osquery/core.h"
|
||||
#include "osquery/database.h"
|
||||
|
||||
#include "osquery/filesystem.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
void crawl_proc(QueryData &results) {
|
||||
boost::filesystem::path dir_path = "/proc";
|
||||
for (boost::filesystem::directory_iterator itr(dir_path), end_itr; itr != end_itr; ++itr) {
|
||||
std::vector<std::string> processes;
|
||||
|
||||
if (boost::filesystem::is_directory(itr->status())) {
|
||||
std::string d_path = itr->path().string();
|
||||
if (!osquery::procProcesses(processes).ok()) {
|
||||
LOG(INFO) << "Cannot list Linux processes";
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure /proc/*/fd is there
|
||||
d_path.append("/fd");
|
||||
struct stat s;
|
||||
int err = stat(d_path.c_str(), &s);
|
||||
if (err == -1) {
|
||||
boost::regex socket_filter("[0-9]+");
|
||||
for (const auto& process : processes) {
|
||||
std::vector<std::string> descriptors;
|
||||
if (!osquery::procDescriptors(process, descriptors).ok()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& descriptor : descriptors) {
|
||||
std::string linkname;
|
||||
if (!procReadDescriptor(process, descriptor, linkname).ok()) {
|
||||
// This is an odd error case, but the symlink could not be read.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (boost::filesystem::directory_iterator i(d_path), e_i; i != e_i; ++i) {
|
||||
char* linkname = (char *)malloc(32);
|
||||
std::string path = i->path().string();
|
||||
auto r = readlink(path.c_str(), linkname, 32);
|
||||
std::string link_str(linkname, linkname + 32);
|
||||
free(linkname);
|
||||
if (linkname.find("socket") == std::string::npos) {
|
||||
// This is not a socket descriptor.
|
||||
continue;
|
||||
}
|
||||
|
||||
// matches socket:[13415]
|
||||
if (link_str.find("socket") != std::string::npos) {
|
||||
boost::regex e("[0-9]+");
|
||||
boost::smatch inode;
|
||||
boost::regex_search(link_str, inode, e);
|
||||
if (inode[0].str().length() > 0) {
|
||||
std::vector<std::string> pid;
|
||||
boost::split(pid, path, boost::is_any_of("/"));
|
||||
Row r;
|
||||
r["pid"] = boost::lexical_cast<std::string>(pid[2].c_str());
|
||||
r["inode"] = boost::lexical_cast<std::string>(inode[0].str());
|
||||
results.push_back(r);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// The linkname is in the form socket:[12345].
|
||||
boost::smatch inode;
|
||||
boost::regex_search(linkname, inode, socket_filter);
|
||||
if (inode[0].str().length() > 0) {
|
||||
Row r;
|
||||
r["pid"] = process;
|
||||
r["inode"] = inode[0].str();
|
||||
results.push_back(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,5 +4,3 @@
|
||||
|
||||
quarantine
|
||||
suid_bin
|
||||
port_inode
|
||||
socket_inode
|
||||
|
@ -5,6 +5,7 @@ schema([
|
||||
Column("local_ip", TEXT),
|
||||
Column("remote_ip", TEXT),
|
||||
Column("inode", TEXT),
|
||||
Column("family", INTEGER),
|
||||
])
|
||||
implementation("osquery/tables/networking/linux/port_inode@genPortInode")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user