Skip to content

Commit

Permalink
selinux_settings: New table that presents effective SELinux settings (o…
Browse files Browse the repository at this point in the history
…squery#6118)

* selinux_settings: New table that presents effective SELinux settings

* selinux_settings: Use the SELinux root path from the mounted fs

The code that was originally directly implemented inside the
`mounts` table has been moved outside so that it can be reused
by the selinux_settings table.

This also updates the code to use getmntent_r instead of getmntent.
  • Loading branch information
alessandrogario authored Jan 27, 2020
1 parent 0b2aa61 commit 8d9059f
Show file tree
Hide file tree
Showing 13 changed files with 588 additions and 37 deletions.
3 changes: 3 additions & 0 deletions osquery/filesystem/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ osquery_cxx_library(
LINUX,
[
"linux/proc.h",
"linux/mounts.h",
],
),
],
Expand Down Expand Up @@ -55,6 +56,7 @@ osquery_cxx_library(
[
"linux/mem.cpp",
"linux/proc.cpp",
"linux/mounts.cpp",
],
),
(
Expand All @@ -74,6 +76,7 @@ osquery_cxx_library(
osquery_target("osquery/utils/conversions:conversions"),
osquery_target("osquery/utils/status:status"),
osquery_target("osquery/utils/system:env"),
osquery_target("osquery/utils/system:filepath"),
osquery_tp_target("boost"),
osquery_tp_target("libarchive"),
osquery_tp_target("zstd"),
Expand Down
3 changes: 3 additions & 0 deletions osquery/filesystem/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function(generateOsqueryFilesystem)
list(APPEND source_files
linux/mem.cpp
linux/proc.cpp
linux/mounts.cpp
)

elseif(DEFINED PLATFORM_WINDOWS)
Expand All @@ -55,6 +56,7 @@ function(generateOsqueryFilesystem)
osquery_utils_conversions
osquery_utils_status
osquery_utils_system_env
osquery_utils_system_filepath
thirdparty_boost
thirdparty_libarchive
thirdparty_zstd
Expand All @@ -68,6 +70,7 @@ function(generateOsqueryFilesystem)
if(DEFINED PLATFORM_LINUX)
list(APPEND public_header_files
linux/proc.h
linux/mounts.h
)
endif()

Expand Down
113 changes: 113 additions & 0 deletions osquery/filesystem/linux/mounts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed in accordance with the terms specified in
* the LICENSE file found in the root directory of this source tree.
*/

#include <mntent.h>
#include <sys/vfs.h>

#include <osquery/filesystem/linux/mounts.h>
#include <osquery/logger.h>
#include <osquery/utils/system/filepath.h>

namespace osquery {
namespace {
const std::string kMountsPseudoFile{"/proc/mounts"};

struct MountDataDeleter final {
void operator()(FILE* ptr) {
if (ptr == nullptr) {
return;
}

endmntent(ptr);
}
};

using MountData = std::unique_ptr<FILE, MountDataDeleter>;

Status getMountData(MountData& obj) {
obj = {};

auto mount_data = setmntent(kMountsPseudoFile.c_str(), "r");
if (mount_data == nullptr) {
return Status::failure("Failed to open the '" + kMountsPseudoFile +
"' pseudo file");
}

obj.reset(mount_data);
return Status::success();
}
} // namespace

Status getMountedFilesystemMap(MountedFilesystemMap& mounted_fs_info) {
mounted_fs_info = {};

MountData mount_data;
auto status = getMountData(mount_data);
if (!status.ok()) {
return status;
}

std::vector<char> string_buffer(4096);

for (;;) {
mntent ent = {};
if (getmntent_r(mount_data.get(),
&ent,
string_buffer.data(),
string_buffer.size()) == nullptr) {
if (errno != ENOENT) {
LOG(ERROR) << "getmntent_r failed with errno " << std::to_string(errno);
}

break;
}

MountInformation mount_info = {};
mount_info.type = ent.mnt_type;
mount_info.device = ent.mnt_fsname;
mount_info.device_alias = canonicalize_file_name(ent.mnt_fsname);
mount_info.path = ent.mnt_dir;
mount_info.flags = ent.mnt_opts;

if (mount_info.type == "autofs") {
VLOG(1) << "Skipping statfs information for autofs mount: "
<< mount_info.path;

} else {
struct statfs stats = {};
if (statfs(mount_info.path.c_str(), &stats) == 0) {
MountInformation::StatFsInfo statfs_info = {};

statfs_info.block_size = static_cast<std::uint32_t>(stats.f_bsize);
statfs_info.block_count = static_cast<std::uint32_t>(stats.f_blocks);

statfs_info.free_block_count =
static_cast<std::uint32_t>(stats.f_bfree);

statfs_info.unprivileged_free_block_count =
static_cast<std::uint32_t>(stats.f_bavail);

statfs_info.inode_count = static_cast<std::uint32_t>(stats.f_files);

statfs_info.free_inode_count =
static_cast<std::uint32_t>(stats.f_ffree);

mount_info.optional_statfs_info = std::move(statfs_info);

} else {
LOG(ERROR) << "statfs failed with errno " << std::to_string(errno)
<< " on path " << mount_info.path;
}
}

mounted_fs_info.insert({mount_info.path, std::move(mount_info)});
}

return Status::success();
}
} // namespace osquery
62 changes: 62 additions & 0 deletions osquery/filesystem/linux/mounts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed in accordance with the terms specified in
* the LICENSE file found in the root directory of this source tree.
*/

#include <boost/optional.hpp>
#include <unordered_map>

#include <osquery/core.h>
#include <osquery/filesystem/filesystem.h>

namespace osquery {
// Information about a single mounted filesystem
struct MountInformation final {
struct StatFsInfo final {
// Optimal transfer block size (statfs::f_bsize)
std::uint32_t block_size{0U};

// Total data blocks in file system (statfs::f_blocks)
std::uint32_t block_count{0U};

// Free blocks in filesystem (statfs::f_bfree)
std::uint32_t free_block_count{0U};

// Free blocks available to unprivileged user (statfs::f_bavail)
std::uint32_t unprivileged_free_block_count{0U};

// Total file nodes in filesystem (statfs::f_files)
std::uint32_t inode_count{0U};

// Free file nodes in filesystem (statfs::f_ffree)
std::uint32_t free_inode_count{0U};
};

// Filesystem type
std::string type;

// Device path
std::string device;

// Canonicalized device path
std::string device_alias;

// Mount path
std::string path;

// Mount options
std::string flags;

// statfs information; may not be set if the statfs operation
// has failed
boost::optional<StatFsInfo> optional_statfs_info;
};

// Information about all mounted filesystems
using MountedFilesystemMap = std::unordered_map<std::string, MountInformation>;

Status getMountedFilesystemMap(MountedFilesystemMap& mounted_fs_info);
} // namespace osquery
1 change: 1 addition & 0 deletions osquery/tables/system/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ osquery_cxx_library(
"linux/process_open_files.cpp",
"linux/processes.cpp",
"linux/rpm_packages.cpp",
"linux/selinux_settings.cpp",
"linux/shadow.cpp",
"linux/shared_memory.cpp",
"linux/smbios_tables.cpp",
Expand Down
1 change: 1 addition & 0 deletions osquery/tables/system/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ function(generateOsqueryTablesSystemSystemtable)
linux/usb_devices.cpp
linux/user_groups.cpp
linux/users.cpp
linux/selinux_settings.cpp
)

elseif(DEFINED PLATFORM_MACOS)
Expand Down
75 changes: 38 additions & 37 deletions osquery/tables/system/linux/mounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,58 @@
* the LICENSE file found in the root directory of this source tree.
*/

#include <mntent.h>
#include <sys/vfs.h>

#include <set>

#include <osquery/core.h>
#include <osquery/filesystem/filesystem.h>
#include <osquery/filesystem/linux/mounts.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
#include <osquery/utils/system/filepath.h>

namespace osquery {
namespace tables {

std::set<std::string> kMountStatBlacklist = {
"autofs",
};

QueryData genMounts(QueryContext& context) {
QueryData results;

FILE* mounts = setmntent("/proc/mounts", "r");
if (mounts == nullptr) {
MountedFilesystemMap mounted_fs_map{};
auto status = getMountedFilesystemMap(mounted_fs_map);
if (!status.ok()) {
LOG(ERROR) << "Failed to list the system mounts: " << status.getMessage();
return {};
}

struct mntent* ent = nullptr;
while ((ent = getmntent(mounts))) {
Row r;
QueryData results;

for (const auto& p : mounted_fs_map) {
Row r = {};

const auto& mount_info = p.second;

r["type"] = mount_info.type;
r["device"] = mount_info.device;
r["device_alias"] = mount_info.device_alias;
r["path"] = mount_info.path;
r["flags"] = mount_info.flags;

// optional::has_value is not present in Boost 1.66 (which is
// what we have when compiling with BUCK)
if (mount_info.optional_statfs_info != boost::none) {
const auto& statfs_info = mount_info.optional_statfs_info.value();

r["blocks_size"] = BIGINT(statfs_info.block_size);
r["blocks"] = BIGINT(statfs_info.block_count);
r["blocks_free"] = BIGINT(statfs_info.free_block_count);

r["blocks_available"] = BIGINT(statfs_info.unprivileged_free_block_count);

r["type"] = std::string(ent->mnt_type);
r["device"] = std::string(ent->mnt_fsname);
r["device_alias"] = canonicalize_file_name(ent->mnt_fsname);
r["path"] = std::string(ent->mnt_dir);
r["flags"] = std::string(ent->mnt_opts);
r["inodes"] = BIGINT(statfs_info.inode_count);
r["inodes_free"] = BIGINT(statfs_info.free_inode_count);

// Check type against blacklist before running statfs.
if (kMountStatBlacklist.find(r["type"]) == kMountStatBlacklist.end()) {
struct statfs st;
if (!statfs(ent->mnt_dir, &st)) {
r["blocks_size"] = BIGINT(st.f_bsize);
r["blocks"] = BIGINT(st.f_blocks);
r["blocks_free"] = BIGINT(st.f_bfree);
r["blocks_available"] = BIGINT(st.f_bavail);
r["inodes"] = BIGINT(st.f_files);
r["inodes_free"] = BIGINT(st.f_ffree);
}
} else {
r["blocks_size"] = BIGINT(0);
r["blocks"] = BIGINT(0);
r["blocks_free"] = BIGINT(0);
r["blocks_available"] = BIGINT(0);
r["inodes"] = BIGINT(0);
r["inodes_free"] = BIGINT(0);
}

results.push_back(std::move(r));
}
endmntent(mounts);

return results;
}
Expand Down
Loading

0 comments on commit 8d9059f

Please sign in to comment.