Skip to content

Commit

Permalink
Update YARA Sandboxed API sandbox
Browse files Browse the repository at this point in the history
- Compatiblity with YARA 4.0
- Fix issues due to newer Sandboxed API
- Use public Abseil API and the new absl::Status
  • Loading branch information
cblichmann authored and plusvic committed May 12, 2020
1 parent 7568acb commit f014492
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 47 deletions.
2 changes: 2 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Build in C++17 mode without a custom CROSSTOOL
build --cxxopt=-std=c++17
4 changes: 2 additions & 2 deletions bazel/yara_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ def yara_deps():
maybe(
git_repository,
name = "com_google_sandboxed_api",
commit = "aafc597630ecf22e32ae71fdd45cab8c43584e65", # 2020-04-30
commit = "144a441d798f13d27cc71e7c2a630e0063d747b5", # 2020-05-12
remote = "https://github.com/google/sandboxed-api.git",
shallow_since = "1588247853 -0700",
shallow_since = "1589270865 -0700",
)
maybe(
http_archive,
Expand Down
13 changes: 5 additions & 8 deletions sandbox/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,24 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")

load(
"@com_google_sandboxed_api//sandboxed_api/bazel:proto.bzl",
"sapi_proto_library",
)
load(
"@com_google_sandboxed_api//sandboxed_api/bazel:sapi.bzl",
"sapi_library",
)

# Proto message that stores YARA matches. Used to communicate matches from
# the sandboxee to the host code.
proto_library(
sapi_proto_library(
name = "yara_matches",
srcs = ["yara_matches.proto"],
)

cc_proto_library(
name = "yara_matches_cc_proto",
deps = [":yara_matches"],
)

# Library with a callback function to collect YARA matches into a YaraMatches
# proto
cc_library(
Expand Down
5 changes: 3 additions & 2 deletions sandbox/collect_matches.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

namespace yara {

int CollectMatches(int message, void* message_data, void* user_data) {
int CollectMatches(YR_SCAN_CONTEXT*, int message, void* message_data,
void* user_data) {
if (message != CALLBACK_MSG_RULE_MATCHING) {
return ERROR_SUCCESS; // There are no matching rules, simply return
}
Expand All @@ -47,7 +48,7 @@ int CollectMatches(int message, void* message_data, void* user_data) {
match->mutable_id()->set_rule_namespace(rule->ns->name);
}
match->mutable_id()->set_rule_name(rule->identifier);
while (!META_IS_NULL(rule_meta)) {
yr_rule_metas_foreach(rule, rule_meta) {
auto* meta = match->add_meta();
meta->set_identifier(rule_meta->identifier);
switch (rule_meta->type) {
Expand Down
5 changes: 4 additions & 1 deletion sandbox/collect_matches.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SANDBOX_COLLECT_MATCHES_H_
#define SANDBOX_COLLECT_MATCHES_H_

struct YR_SCAN_CONTEXT;

namespace yara {

// Callback function for yr_scan_mem() that collects YARA matches in a
// YaraMatches proto given in user_data.
int CollectMatches(int message, void* message_data, void* user_data);
int CollectMatches(YR_SCAN_CONTEXT*, int message, void* message_data,
void* user_data);

} // namespace yara

Expand Down
21 changes: 10 additions & 11 deletions sandbox/sandboxed_yara.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sstream>

#include "sandbox/yara_transaction.h"
#include "sandboxed_api/util/canonical_errors.h"
#include "sandboxed_api/util/statusor.h"
// TODO(cblichmann): SAPI leaks these symbols currently.
#undef ABSL_FLAG
#undef ABSL_DECLARE_FLAG
#undef ABSL_RETIRED_FLAG

#include "absl/flags/flag.h"
#include "absl/flags/internal/usage.h"
#include "absl/flags/parse.h"
#include "absl/time/time.h"
#include "absl/flags/usage.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"

ABSL_FLAG(std::string, identifier, "", "print only rules with this name");
ABSL_FLAG(int, timeout, 5, "abort scanning after the given number of seconds");
Expand All @@ -62,7 +62,7 @@ ::sapi::StatusOr<std::string> ReadFileToString(absl::string_view filename) {
std::ostringstream output;
output << input.rdbuf();
if (!input) {
return ::sapi::UnknownError(absl::StrCat("Cannot read file '", filename, "'"));
return absl::UnknownError(absl::StrCat("Cannot read file '", filename, "'"));
}
return output.str();
}
Expand All @@ -71,9 +71,9 @@ ::sapi::StatusOr<std::string> ReadFileToString(absl::string_view filename) {

// Implements a subset of the YARA command line scanner, but runs the actual
// scan inside of a sandbox.
::sapi::Status YaraMain(const std::vector<char*>& args) {
absl::Status YaraMain(const std::vector<char*>& args) {
if (args.size() < 3) {
return ::sapi::InvalidArgumentError("Missing operand. Try '--help'.");
return absl::InvalidArgumentError("Missing operand. Try '--help'.");
}

// Get file to scan and concatenate all the YARA rules from the specified
Expand All @@ -99,7 +99,7 @@ ::sapi::Status YaraMain(const std::vector<char*>& args) {
int fd;
} fd_closer{open(scan_filename.c_str(), O_RDONLY)};
if (fd_closer.fd == -1) {
return ::sapi::UnknownError(absl::StrCat(
return absl::UnknownError(absl::StrCat(
"Cannot open file '", scan_filename, "': ", strerror(errno)));
}

Expand All @@ -112,7 +112,7 @@ ::sapi::Status YaraMain(const std::vector<char*>& args) {
}
}

return ::sapi::OkStatus();
return absl::OkStatus();
}

} // namespace yara
Expand All @@ -125,12 +125,11 @@ int main(int argc, char* argv[]) {
argv0 = argv0.substr(last_slash_pos + 1);
}
}
// TODO(cblichmann): Use public API once available from Bazel builds.
absl::flags_internal::SetProgramUsageMessage(
absl::SetProgramUsageMessage(
absl::StrCat("YARA, the pattern matching swiss army knife.\n",
"Usage: ", argv0, " [OPTION] RULES_FILE... FILE"));

::sapi::Status status = ::yara::YaraMain(absl::ParseCommandLine(argc, argv));
absl::Status status = ::yara::YaraMain(absl::ParseCommandLine(argc, argv));
if (!status.ok()) {
absl::FPrintF(stderr, "ERROR: %s\n", status.message());
return EXIT_FAILURE;
Expand Down
35 changes: 16 additions & 19 deletions sandbox/yara_transaction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "absl/strings/str_cat.h"
#include "libyara/include/yara/error.h"
#include "sandboxed_api/util/canonical_errors.h"
#include "sandboxed_api/util/status_macros.h"

namespace yara {
Expand All @@ -49,7 +48,7 @@ ::sapi::StatusOr<std::unique_ptr<YaraTransaction>> YaraTransaction::Create(
// "Run" the transaction in order to initialize the underlying sandbox.
SAPI_RETURN_IF_ERROR(transaction->Run());

sandbox::YaraApi api(transaction->GetSandbox());
sandbox::YaraApi api(transaction->sandbox());
SAPI_RETURN_IF_ERROR(
api.YaraInitWorkers(options.num_workers >= 1 ? options.num_workers : 1));

Expand All @@ -59,7 +58,7 @@ ::sapi::StatusOr<std::unique_ptr<YaraTransaction>> YaraTransaction::Create(
::sapi::StatusOr<int> YaraTransaction::LoadRules(
const std::string& rule_string) {
absl::MutexLock lock(&mutex_);
sandbox::YaraApi api(GetSandbox());
sandbox::YaraApi api(sandbox());

::sapi::v::ConstCStr rule_string_sapi(rule_string.c_str());
YaraStatus error_status;
Expand All @@ -70,39 +69,38 @@ ::sapi::StatusOr<int> YaraTransaction::LoadRules(
if (num_rules <= 0) {
auto error_status_copy = error_status_sapi.GetProtoCopy();
if (!error_status_copy) {
return ::sapi::UnknownError("Deserialization of response failed");
return absl::UnknownError("Deserialization of response failed");
}
return ::sapi::InvalidArgumentError(error_status_copy->message());
return absl::InvalidArgumentError(error_status_copy->message());
}
return num_rules;
}

::sapi::StatusOr<YaraMatches> YaraTransaction::ScanFd(int fd) {
int local_event_fd = eventfd(0 /* initval */, 0 /* flags */);
if (local_event_fd == -1) {
return ::sapi::InternalError(
return absl::InternalError(
absl::StrCat("eventfd() error: ", strerror(errno)));
}
struct FDCloser {
~FDCloser() { close(event_fd); }
int event_fd;
} event_fd_closer = {local_event_fd};

auto* sandbox = GetSandbox();
sandbox::YaraApi api(sandbox);
sandbox::YaraApi api(sandbox());
uint64_t result_id;
{
absl::MutexLock lock(&mutex_);

// Note: These SAPI Fd objects use the underlying sandbox comms to
// synchronize. Hence they must live within this locked scope.
::sapi::v::Fd event_fd{local_event_fd};
SAPI_RETURN_IF_ERROR(sandbox->TransferToSandboxee(&event_fd));
::sapi::v::Fd event_fd(local_event_fd);
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&event_fd));
event_fd.OwnLocalFd(false); // Needs to be valid during poll()
event_fd.OwnRemoteFd(false); // Sandboxee will close

::sapi::v::Fd data_fd{fd};
SAPI_RETURN_IF_ERROR(sandbox->TransferToSandboxee(&data_fd));
::sapi::v::Fd data_fd(fd);
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&data_fd));
data_fd.OwnLocalFd(false); // To be closed by caller
data_fd.OwnRemoteFd(false); // Sandboxee will close

Expand All @@ -122,16 +120,16 @@ ::sapi::StatusOr<YaraMatches> YaraTransaction::ScanFd(int fd) {
// Add extra time to allow code inside the sandbox to time out first.
absl::ToInt64Milliseconds(scan_timeout_ + absl::Seconds(10))));
if (poll_result == 0) {
return ::sapi::DeadlineExceededError("Scan timeout during poll()");
return absl::DeadlineExceededError("Scan timeout during poll()");
}

if (poll_result == -1) {
return ::sapi::InternalError(
return absl::InternalError(
absl::StrCat("poll() error: ", strerror(errno)));
}
if (poll_events.revents & POLLHUP || poll_events.revents & POLLERR ||
poll_events.revents & POLLNVAL) {
return ::sapi::InternalError(
return absl::InternalError(
absl::StrCat("poll() error, revents: ", poll_events.revents));
}

Expand All @@ -146,16 +144,15 @@ ::sapi::StatusOr<YaraMatches> YaraTransaction::ScanFd(int fd) {
case ERROR_TOO_MANY_MATCHES: {
auto matches_copy = matches_sapi.GetProtoCopy();
if (!matches_copy) {
return ::sapi::UnknownError("Deserialization of response failed");
return absl::UnknownError("Deserialization of response failed");
}
return *matches_copy;
}

case ERROR_SCAN_TIMEOUT:
return ::sapi::DeadlineExceededError("Scan timeout");
return absl::DeadlineExceededError("Scan timeout");
}
return ::sapi::InternalError(
absl::StrCat("Error during scan: ", scan_result));
return absl::InternalError(absl::StrCat("Error during scan: ", scan_result));
}

} // namespace yara
1 change: 1 addition & 0 deletions sandbox/yara_transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unistd.h>

#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "sandbox/yara_matches.pb.h"
Expand Down
7 changes: 3 additions & 4 deletions sandbox/yara_transaction_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,16 @@ class MemoryFD {
mem_fd.fd_ = syscall(__NR_memfd_create, reinterpret_cast<uintptr_t>(kName),
MFD_CLOEXEC);
if (mem_fd.fd_ == -1) {
return ::sapi::UnknownError(absl::StrCat("memfd(): ", strerror(errno)));
return absl::UnknownError(absl::StrCat("memfd(): ", strerror(errno)));
}
if (ftruncate(mem_fd.fd_, content.size()) == -1) {
return ::sapi::UnknownError(
absl::StrCat("ftruncate(): ", strerror(errno)));
return absl::UnknownError(absl::StrCat("ftruncate(): ", strerror(errno)));
}
while (!content.empty()) {
ssize_t written =
TEMP_FAILURE_RETRY(write(mem_fd.fd_, content.data(), content.size()));
if (written <= 0) {
return ::sapi::UnknownError(absl::StrCat("write(): ", strerror(errno)));
return absl::UnknownError(absl::StrCat("write(): ", strerror(errno)));
}
content.remove_prefix(written);
}
Expand Down

0 comments on commit f014492

Please sign in to comment.