Adding mem to Linux filesystem lib

This commit is contained in:
Teddy Reed 2015-01-18 18:19:35 -08:00
parent b7852650c2
commit 6b6649bbd4
3 changed files with 140 additions and 0 deletions

View File

@ -191,5 +191,29 @@ Status procDescriptors(const std::string& process,
Status procReadDescriptor(const std::string& process,
const std::string& descriptor,
std::string& result);
/**
* @brief Read bytes from Linux's raw memory.
*
* Most Linux kernels include a device node /dev/mem that allows priviledged
* users to map or seek/read pages of physical memory.
* osquery discourages the use of physical memory reads for security and
* performance reasons and must first try safer methods for data parsing
* such as /sys and /proc.
*
* A platform user may disable physical memory reads:
* --disable_memory=true
* This flag/option will cause readRawMemory to forcefully fail.
*
* @param base The absolute memory address to read from. This does not need
* to be page alined, readRawMem will take care of alignment and only
* return the requested start address and size.
* @param length The length of the buffer with a max of 0x10000.
* @param buffer The output buffer, caller is responsible for resources if
* readRawMem returns success.
* @return status The status of the read.
*/
Status readRawMem(size_t base, size_t length, void** buffer);
#endif
}

View File

@ -6,6 +6,7 @@ if(APPLE)
ADD_OSQUERY_CORE_LINK("-framework Foundation")
elseif(UBUNTU OR CENTOS)
ADD_OSQUERY_CORE_LIBRARY(osquery_filesystem_linux
linux/mem.cpp
linux/proc.cpp
)
endif()

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <osquery/filesystem.h>
#include <osquery/flags.h>
#include <osquery/logger.h>
namespace osquery {
#define kLinuxMaxMemRead 0x10000
const std::string kLinuxMemPath = "/dev/mem";
DEFINE_osquery_flag(bool,
disable_memory,
false,
"Disable physical memory reads.");
int readMem(int fd, size_t base, size_t length, uint8_t* buffer) {
if (lseek(fd, base, SEEK_SET) == -1) {
return -1;
}
// Read from raw memory until an unrecoverable read error or the requested
// bytes are read.
size_t total_read = 0;
size_t bytes_read = 0;
while (total_read != length && bytes_read != 0) {
bytes_read = read(fd, buffer + total_read, length - total_read);
if (bytes_read == -1) {
if (errno != EINTR) {
return -1;
}
} else {
total_read += bytes_read;
}
}
// The read finished without reading the requested number of bytes.
if (total_read != length) {
return -1;
}
return 0;
}
Status readRawMem(size_t base, size_t length, void** buffer) {
*buffer = 0;
if (!FLAGS_disable_memory) {
return Status(1, "Configuration has disabled physical memory reads");
}
if (length > kLinuxMaxMemRead) {
return Status(1, "Cowardly refusing to read a large number of bytes");
}
auto status = isReadable(kLinuxMemPath);
if (!status.ok()) {
// For non-su users *hopefully* raw memory is not readable.
return status;
}
int fd = open(kLinuxMemPath.c_str(), O_RDONLY);
if (fd < 0) {
return Status(1, std::string("Cannot open ") + kLinuxMemPath);
}
if ((*buffer = malloc(length)) == nullptr) {
close(fd);
return Status(1, "Cannot allocate memory for read");
}
#ifdef _SC_PAGESIZE
size_t offset = base % sysconf(_SC_PAGESIZE);
#else
// getpagesize() is more or less deprecated.
size_t offset = base % getpagesize();
#endif
// Use memmap for maximum portability over read().
auto map = mmap(0, offset + length, PROT_READ, MAP_SHARED, fd, base - offset);
if (map == MAP_FAILED) {
// Could fallback to a lseek/read.
if (readMem(fd, base, length, (uint8_t*)*buffer) == -1) {
close(fd);
free(*buffer);
return Status(1, "Cannot memory map or seek/read memory");
}
} else {
// Memory map succeeded, copy and unmap.
memcpy(*buffer, (uint8_t*)map + offset, length);
if (munmap(map, offset + length) == -1) {
LOG(WARNING) << "Unable to unmap raw memory";
}
}
close(fd);
return Status(0, "OK");
}
}