mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2026-05-07 07:06:20 -04:00
Generate Rust-bindings for some internal C-headers
Use bindgen to generate Rust-bindings for some libclamav internal functions and structures in an new "sys.rs" module. "sys.rs" will be generated at build-time and unfortunately must be dropped in the source/libclamav_rust/src directory rather than under the build directory. As far as I know, Cargo/Rust provide no way to set an include path to the build directory to separately place generated files. TODO: Verify if this is true and move sys.rs to the build directory if possible. Using the new bindings with: - the logging module. - the cdiff module. Also: - Removed clamav_rust.h from .gitignore, because we generate it in the build directory now. - Removed the hand-written bindings from the cbindgen exclusions. lib.rs has an annotation that prevents cbindgen from looking at sys.rs. - Fixed a `u8` -> `c_char` type issue in cdiff in the cli_getdsig() call parameters.
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -228,12 +228,13 @@ libclamav/c++/llvm/tools/llvmc/plugins/Base/Base.td
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Generated by libclamav_rust/build.rs in IDEs
|
||||
libclamav_rust/clamav_rust.h
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# The name of our generated ClamAV-Rust bindings file.
|
||||
libclamav_rust/src/sys.rs
|
||||
|
||||
|
||||
@@ -856,6 +856,12 @@ inline void cli_dbgmsg(const char *str, ...) __attribute__((format(printf, 1, 2)
|
||||
inline void cli_dbgmsg(const char *str, ...);
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
void cli_dbgmsg_no_inline(const char *str, ...) __attribute__((format(printf, 1, 2)));
|
||||
#else
|
||||
void cli_dbgmsg_no_inline(const char *str, ...);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CLI_GETPAGESIZE
|
||||
#undef HAVE_CLI_GETPAGESIZE
|
||||
#endif
|
||||
|
||||
@@ -180,6 +180,14 @@ inline void cli_dbgmsg(const char *str, ...)
|
||||
}
|
||||
}
|
||||
|
||||
void cli_dbgmsg_no_inline(const char *str, ...)
|
||||
{
|
||||
if (UNLIKELY(cli_get_debug_flag())) {
|
||||
MSGCODE(buff, len, "LibClamAV debug: ");
|
||||
fputs(buff, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
int cli_matchregex(const char *str, const char *regex)
|
||||
{
|
||||
regex_t reg;
|
||||
|
||||
@@ -19,3 +19,4 @@ name = "clamav_rust"
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.20"
|
||||
bindgen = "0.59"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use bindgen::builder;
|
||||
|
||||
// Note to maintainers: this is currently a hybrid of examination of the
|
||||
// CMake environment, and leaning on Rust `cfg` elements. Ideally, it
|
||||
// should be possible to work in this space (e.g., execute tests from an
|
||||
@@ -14,7 +16,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
// A list of environment variables to query to determine additional libraries
|
||||
// that need to be linked to resolve dependencies.
|
||||
const LIB_ENV_LINK: [&str; 12] = [
|
||||
const LIB_ENV_LINK: &[&str] = &[
|
||||
"LIBSSL",
|
||||
"LIBCRYPTO",
|
||||
"LIBZ",
|
||||
@@ -30,13 +32,47 @@ const LIB_ENV_LINK: [&str; 12] = [
|
||||
];
|
||||
|
||||
// The same, but additional values to check on Windows platforms
|
||||
const LIB_ENV_LINK_WINDOWS: [&str; 2] = ["LIBPTHREADW32", "LIBWIN32COMPAT"];
|
||||
const LIB_ENV_LINK_WINDOWS: &[&str] = &["LIBPTHREADW32", "LIBWIN32COMPAT"];
|
||||
|
||||
// Additional [verbatim] libraries to link on Windows platforms
|
||||
const LIB_LINK_WINDOWS: [&str; 4] = ["wsock32", "ws2_32", "Shell32", "User32"];
|
||||
const LIB_LINK_WINDOWS: &[&str] = &["wsock32", "ws2_32", "Shell32", "User32"];
|
||||
|
||||
// Windows library names that must have the leading `lib` trimmed (if encountered)
|
||||
const WINDOWS_TRIM_LOCAL_LIB: [&str; 2] = ["libclamav", "libclammspack"];
|
||||
const WINDOWS_TRIM_LOCAL_LIB: &[&str] = &["libclamav", "libclammspack"];
|
||||
|
||||
// Generate bindings for these functions:
|
||||
const BINDGEN_FUNCTIONS: &[&str] = &[
|
||||
"cli_ctx",
|
||||
"cli_warnmsg",
|
||||
"cli_dbgmsg_no_inline",
|
||||
"cli_infomsg_simple",
|
||||
"cli_errmsg",
|
||||
"cli_append_virus",
|
||||
"cli_versig2",
|
||||
"cli_getdsig",
|
||||
"cli_get_debug_flag",
|
||||
];
|
||||
|
||||
// Generate bindings for these types (structs, enums):
|
||||
const BINDGEN_TYPES: &[&str] = &["cli_matcher", "cli_ac_data", "cli_ac_result"];
|
||||
|
||||
// Find the required functions and types in these headers:
|
||||
const BINDGEN_HEADERS: &[&str] = &[
|
||||
"../libclamav/matcher.h",
|
||||
"../libclamav/matcher-ac.h",
|
||||
"../libclamav/others.h",
|
||||
"../libclamav/dsig.h",
|
||||
];
|
||||
|
||||
// Find the required headers in these directories:
|
||||
const BINDGEN_INCLUDE_PATHS: &[&str] = &[
|
||||
"-I../libclamav",
|
||||
"-I../libclamunrar_iface",
|
||||
"-I../libclammspack",
|
||||
];
|
||||
|
||||
// Write the bindings to this file:
|
||||
const BINDGEN_OUTPUT_FILE: &str = "src/sys.rs";
|
||||
|
||||
const C_HEADER_OUTPUT: &str = "clamav_rust.h";
|
||||
|
||||
@@ -58,14 +94,54 @@ fn main() -> Result<(), &'static str> {
|
||||
|
||||
// We only want to execute cbindgen for `cargo build`, not `cargo test`.
|
||||
// FindRust.cmake defines $CARGO_CMD so we can differentiate.
|
||||
if "build" == env::var("CARGO_CMD").or(Ok("".to_string()))? {
|
||||
let cargo_cmd = env::var("CARGO_CMD").unwrap_or("".into());
|
||||
if cargo_cmd == "build" {
|
||||
execute_bindgen()?;
|
||||
execute_cbindgen()?;
|
||||
} else {
|
||||
eprintln!("NOTE: Not performing cbindgen as CARGO_CMD != build");
|
||||
eprintln!("NOTE: Not generating bindings because CARGO_CMD != build");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Use bindgen to generate Rust bindings to call into C libraries.
|
||||
fn execute_bindgen() -> Result<(), &'static str> {
|
||||
let build_dir = PathBuf::from(env::var("CARGO_TARGET_DIR").unwrap_or(".".into()));
|
||||
let build_include_path = format!("-I{}", build_dir.join("..").to_str().unwrap());
|
||||
|
||||
// Configure and generate bindings.
|
||||
let mut builder = builder()
|
||||
// Silence code-style warnings for generated bindings.
|
||||
.raw_line("#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]")
|
||||
// Make the bindings pretty.
|
||||
.rustfmt_bindings(true)
|
||||
// Enable bindgen to find generated headers in the build directory, too.
|
||||
.clang_arg(build_include_path);
|
||||
|
||||
for &include_path in BINDGEN_INCLUDE_PATHS {
|
||||
builder = builder.clang_arg(include_path);
|
||||
}
|
||||
for &header in BINDGEN_HEADERS {
|
||||
builder = builder.header(header);
|
||||
}
|
||||
for &c_function in BINDGEN_FUNCTIONS {
|
||||
builder = builder.allowlist_function(c_function);
|
||||
}
|
||||
for &c_type in BINDGEN_TYPES {
|
||||
builder = builder.allowlist_type(c_type);
|
||||
}
|
||||
|
||||
// Generate!
|
||||
let bindings = builder.generate().unwrap();
|
||||
|
||||
// Write the generated bindings to an output file.
|
||||
bindings.write_to_file(BINDGEN_OUTPUT_FILE).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Use cbindgen to generate C-header's for Rust static libraries.
|
||||
fn execute_cbindgen() -> Result<(), &'static str> {
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").or(Err("CARGO_MANIFEST_DIR not specified"))?;
|
||||
let build_dir = PathBuf::from(env::var("CARGO_TARGET_DIR").unwrap_or(".".into()));
|
||||
@@ -86,15 +162,15 @@ fn detect_clamav_build() -> Result<(), &'static str> {
|
||||
if search_and_link_lib("LIBCLAMAV")? {
|
||||
eprintln!("NOTE: LIBCLAMAV defined. Examining LIB* environment variables");
|
||||
// Need to link with libclamav dependencies
|
||||
for var in &LIB_ENV_LINK {
|
||||
for var in LIB_ENV_LINK {
|
||||
let _ = search_and_link_lib(var);
|
||||
}
|
||||
|
||||
if cfg!(windows) {
|
||||
for var in &LIB_ENV_LINK_WINDOWS {
|
||||
for var in LIB_ENV_LINK_WINDOWS {
|
||||
let _ = search_and_link_lib(var);
|
||||
}
|
||||
for lib in &LIB_LINK_WINDOWS {
|
||||
for lib in LIB_LINK_WINDOWS {
|
||||
println!("cargo:rustc-link-lib={}", lib);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -17,15 +17,8 @@ after_includes = ""
|
||||
|
||||
[export]
|
||||
include = ["cdiff_apply", "script2cdiff"]
|
||||
exclude = [
|
||||
"cli_dbgmsg",
|
||||
"cli_errmsg",
|
||||
"cli_infomsg_simple",
|
||||
"cli_warnmsg",
|
||||
"cli_versig2",
|
||||
"cli_get_debug_flag",
|
||||
"cli_getdsig",
|
||||
]
|
||||
exclude = []
|
||||
|
||||
# prefix = "CAPI_"
|
||||
item_types = []
|
||||
renaming_overrides_prefixing = false
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::{
|
||||
fs::{self, File, OpenOptions},
|
||||
io::{prelude::*, BufReader, BufWriter, Read, Seek, SeekFrom, Write},
|
||||
iter::*,
|
||||
os::raw::{c_char, c_uchar},
|
||||
os::raw::c_char,
|
||||
process,
|
||||
};
|
||||
|
||||
@@ -34,6 +34,8 @@ use log::{debug, error, warn};
|
||||
use sha2::{Digest, Sha256};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::sys;
|
||||
|
||||
/// Maximum size of a digital signature
|
||||
const MAX_SIG_SIZE: usize = 350;
|
||||
|
||||
@@ -255,28 +257,9 @@ impl<'a> XchgOp<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn cli_versig2(
|
||||
digest: *const c_uchar,
|
||||
dsig: *const c_char,
|
||||
n: *const c_char,
|
||||
e: *const c_char,
|
||||
) -> i32;
|
||||
|
||||
fn cli_getdsig(
|
||||
host: *const u8,
|
||||
user: *const u8,
|
||||
data: *const u8,
|
||||
datalen: u32,
|
||||
mode: u8,
|
||||
) -> *const c_char;
|
||||
|
||||
fn cli_get_debug_flag() -> u8;
|
||||
}
|
||||
|
||||
fn is_debug_enabled() -> bool {
|
||||
unsafe {
|
||||
let debug_flag = cli_get_debug_flag();
|
||||
let debug_flag = sys::cli_get_debug_flag();
|
||||
// Return true if debug_flag is not 0
|
||||
!matches!(debug_flag, 0)
|
||||
}
|
||||
@@ -418,9 +401,9 @@ pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Resu
|
||||
// These strings should not contain interior NULs
|
||||
let server = CString::new(server).unwrap();
|
||||
let builder = CString::new(builder).unwrap();
|
||||
let dsig_ptr = cli_getdsig(
|
||||
server.as_c_str().as_ptr() as *const u8,
|
||||
builder.as_c_str().as_ptr() as *const u8,
|
||||
let dsig_ptr = sys::cli_getdsig(
|
||||
server.as_c_str().as_ptr() as *const c_char,
|
||||
builder.as_c_str().as_ptr() as *const c_char,
|
||||
sha256.to_vec().as_ptr(),
|
||||
32,
|
||||
2,
|
||||
@@ -511,7 +494,7 @@ pub fn cdiff_apply(file: &mut File, mode: ApplyMode) -> Result<(), CdiffError> {
|
||||
let n = CString::new(PUBLIC_KEY_MODULUS).unwrap();
|
||||
let e = CString::new(PUBLIC_KEY_EXPONENT).unwrap();
|
||||
let versig_result = unsafe {
|
||||
cli_versig2(
|
||||
sys::cli_versig2(
|
||||
sha256.to_vec().as_ptr(),
|
||||
dsig_cstring.as_ptr(),
|
||||
n.as_ptr() as *const c_char,
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/// cbindgen:ignore
|
||||
pub mod sys;
|
||||
|
||||
pub mod cdiff;
|
||||
pub mod logging;
|
||||
pub mod util;
|
||||
|
||||
@@ -21,16 +21,10 @@
|
||||
*/
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
use log::{set_max_level, Level, LevelFilter, Metadata, Record};
|
||||
|
||||
extern "C" {
|
||||
fn cli_warnmsg(str: *const c_char, ...) -> ();
|
||||
fn cli_dbgmsg(str: *const c_char, ...) -> ();
|
||||
fn cli_infomsg_simple(str: *const c_char, ...) -> ();
|
||||
fn cli_errmsg(str: *const c_char, ...) -> ();
|
||||
}
|
||||
use crate::sys;
|
||||
|
||||
pub struct ClamLogger;
|
||||
|
||||
@@ -46,16 +40,16 @@ impl log::Log for ClamLogger {
|
||||
|
||||
match record.level() {
|
||||
Level::Debug => unsafe {
|
||||
cli_dbgmsg(ptr);
|
||||
sys::cli_dbgmsg_no_inline(ptr);
|
||||
},
|
||||
Level::Error => unsafe {
|
||||
cli_errmsg(ptr);
|
||||
sys::cli_errmsg(ptr);
|
||||
},
|
||||
Level::Info => unsafe {
|
||||
cli_infomsg_simple(ptr);
|
||||
sys::cli_infomsg_simple(ptr);
|
||||
},
|
||||
Level::Warn => unsafe {
|
||||
cli_warnmsg(ptr);
|
||||
sys::cli_warnmsg(ptr);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user