Cleanup inode table implementations and unblacklist

This commit is contained in:
Teddy Reed 2014-11-19 14:53:42 -08:00
parent c823de82a0
commit b2debf509a
8 changed files with 163 additions and 76 deletions

View File

@ -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
}

View File

@ -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

View File

@ -16,8 +16,6 @@
#include "osquery/filesystem.h"
using osquery::Status;
namespace pt = boost::property_tree;
namespace fs = boost::filesystem;

View 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");
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -4,5 +4,3 @@
quarantine
suid_bin
port_inode
socket_inode

View File

@ -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")