mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-08 10:23:54 +00:00
113 lines
2.9 KiB
C++
113 lines
2.9 KiB
C++
/*
|
|
* 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";
|
|
|
|
FLAG(bool, disable_memory, false, "Disable physical memory reads");
|
|
|
|
Status readMem(int fd, size_t base, size_t length, uint8_t* buffer) {
|
|
if (lseek(fd, base, SEEK_SET) == -1) {
|
|
return Status(1, "Cannot seek to physical base");
|
|
}
|
|
|
|
// Read from raw memory until an unrecoverable read error or the all of 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 Status(1, "Cannot read requested length");
|
|
}
|
|
} else {
|
|
total_read += bytes_read;
|
|
}
|
|
}
|
|
|
|
// The read call finished without reading the requested number of bytes.
|
|
if (total_read != length) {
|
|
return Status(1, "Read incorrect number of bytes");
|
|
}
|
|
|
|
return Status(0, "OK");
|
|
}
|
|
|
|
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).ok()) {
|
|
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");
|
|
}
|
|
}
|