Skip to content

Commit

Permalink
fix: issue with very large timeouts
Browse files Browse the repository at this point in the history
The default scanner timeout is 315.360.000 seconds instead of  `u64::MAX`. Using `u64::MAX` as the default value doesn't work because that value is later added to the current epoch and would cause an integer overflow. We need a value that is large enough but that has some room before `u64::MAX` is reached.
  • Loading branch information
plusvic committed Sep 1, 2023
1 parent 8121dde commit c0835e1
Showing 1 changed file with 25 additions and 13 deletions.
38 changes: 25 additions & 13 deletions yara-x/src/scanner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::slice::Iter;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Once;
use std::time::Duration;
use std::{fs, thread};
use std::{cmp, fs, thread};

use bitvec::prelude::*;
use fmmap::{MmapFile, MmapFileExt};
Expand Down Expand Up @@ -93,6 +93,7 @@ pub struct Scanner<'r> {

impl<'r> Scanner<'r> {
const DEFAULT_MAX_MATCHES_PER_PATTERN: usize = 1_000_000;
const DEFAULT_SCAN_TIMEOUT: u64 = 315_360_000;

/// Creates a new scanner.
pub fn new(rules: &'r Rules) -> Self {
Expand Down Expand Up @@ -351,6 +352,29 @@ impl<'r> Scanner<'r> {
// Clear information about matches found in a previous scan, if any.
self.clear_matches();

// Timeout in seconds. This is either the value provided by the user or
// 315.360.000 which is the number of seconds in a year. Using u64::MAX
// doesn't work because this value is added to the current epoch, and
// will cause an overflow. We need an integer large enough, but that
// has room before the u64 limit is reached. For this same reason if
// the user specifies a value larger than 315.360.000 we limit it to
// 315.360.000 anyways. One year should be enough, I hope you don't
// plan to run a YARA scan that takes longer.
let timeout_secs =
self.timeout.map_or(Self::DEFAULT_SCAN_TIMEOUT, |t| {
cmp::min(
t.as_secs_f32().ceil() as u64,
Self::DEFAULT_SCAN_TIMEOUT,
)
});

// Sets the deadline for the WASM store. The WASM main function will
// abort if the deadline is reached while the function is being
// executed.
self.wasm_store.set_epoch_deadline(timeout_secs);
self.wasm_store
.epoch_deadline_callback(|_| Err(ScanError::Timeout.into()));

// If the user specified some timeout, start the heartbeat thread, if
// not previously started. The heartbeat thread increments the WASM
// engine epoch and HEARTBEAT_COUNTER every second. There's a single
Expand All @@ -374,18 +398,6 @@ impl<'r> Scanner<'r> {
});
}

// Timeout in seconds, this is either the value provided by the user or
// u64::MAX.
let timeout_secs =
self.timeout.map_or(u64::MAX, |t| t.as_secs_f32().ceil() as u64);

// Sets the deadline for the WASM store. The WASM main function will
// abort if the deadline is reached while the function is being
// executed.
self.wasm_store.set_epoch_deadline(timeout_secs);
self.wasm_store
.epoch_deadline_callback(|_| Err(ScanError::Timeout.into()));

// Set the global variable `filesize` to the size of the scanned data.
self.filesize
.set(
Expand Down

0 comments on commit c0835e1

Please sign in to comment.