New API: yara_load

The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxdafox@gmail.com>
This commit is contained in:
Matteo Cafasso
2017-04-25 23:03:01 +03:00
committed by Richard W.M. Jones
parent 2e24129da3
commit 27f175b717
12 changed files with 305 additions and 2 deletions

View File

@@ -170,6 +170,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
yara.c \
zero.c \
zerofree.c

View File

@@ -61,6 +61,15 @@ cleanup_close (void *ptr)
close (fd);
}
void
cleanup_fclose (void *ptr)
{
FILE *f = * (FILE **) ptr;
if (f)
fclose (f);
}
void
cleanup_aug_close (void *ptr)
{

View File

@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
extern void cleanup_free_string_list (void *ptr);
extern void cleanup_unlink_free (void *ptr);
extern void cleanup_close (void *ptr);
extern void cleanup_fclose (void *ptr);
extern void cleanup_aug_close (void *ptr);
extern void cleanup_free_stringsbuf (void *ptr);
@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
__attribute__((cleanup(cleanup_free_string_list)))
#define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
#define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
#define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
#define CLEANUP_FREE_STRINGSBUF __attribute__((cleanup(cleanup_free_stringsbuf)))
#else

215
daemon/yara.c Normal file
View File

@@ -0,0 +1,215 @@
/* libguestfs - the guestfsd daemon
* Copyright (C) 2016 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <config.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <rpc/xdr.h>
#include <rpc/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#include "guestfs_protocol.h"
#ifdef HAVE_YARA
#include <yara.h>
#ifdef HAVE_ATTRIBUTE_CLEANUP
#define CLEANUP_DESTROY_YARA_COMPILER \
__attribute__((cleanup(cleanup_destroy_yara_compiler)))
#else
#define CLEANUP_DESTROY_YARA_COMPILER
#endif
struct write_callback_data {
int fd;
uint64_t written;
};
/* Yara compiled rules. */
static YR_RULES *rules = NULL;
static bool initialized = false;
static int compile_rules_file (const char *);
static void compile_error_callback (int, const char *, int, const char *, void *);
static void cleanup_destroy_yara_compiler (void *ptr);
/* Has one FileIn parameter.
* Takes optional arguments, consult optargs_bitmask.
*/
int
do_yara_load (void)
{
int r;
CLEANUP_CLOSE int fd = -1;
char tmpfile[] = "/tmp/yaraXXXXXX";
fd = mkstemp (tmpfile);
if (fd == -1) {
reply_with_perror ("mkstemp");
return -1;
}
r = upload_to_fd (fd, tmpfile);
if (r == -1) {
unlink (tmpfile);
return -1;
}
/* Initialize yara only once. */
if (!initialized) {
r = yr_initialize ();
if (r != ERROR_SUCCESS) {
reply_with_error ("failed initializing yara");
unlink (tmpfile);
return -1;
}
initialized = true;
}
/* Destroy previously loaded rules. */
if (rules != NULL) {
yr_rules_destroy (rules);
rules = NULL;
}
/* Try to load the rules as compiled.
* If their are in source code format, compile them first.
*/
r = yr_rules_load (tmpfile, &rules);
if (r == ERROR_INVALID_FILE)
r = compile_rules_file (tmpfile);
unlink (tmpfile);
return (r == ERROR_SUCCESS) ? 0 : -1;
}
/* Compile source code rules and load them.
* Return ERROR_SUCCESS on success, Yara error code type on error.
*/
static int
compile_rules_file (const char *rules_path)
{
int ret;
CLEANUP_FCLOSE FILE *rule_file = NULL;
CLEANUP_DESTROY_YARA_COMPILER YR_COMPILER *compiler = NULL;
ret = yr_compiler_create (&compiler);
if (ret != ERROR_SUCCESS) {
reply_with_error ("yr_compiler_create");
return ret;
}
yr_compiler_set_callback (compiler, compile_error_callback, NULL);
rule_file = fopen (rules_path, "r");
if (rule_file == NULL) {
reply_with_error ("unable to open rules file");
ret = ERROR_COULD_NOT_OPEN_FILE;
goto err;
}
ret = yr_compiler_add_file (compiler, rule_file, NULL, NULL);
if (ret > 0) {
reply_with_error ("found %d errors when compiling the rules", ret);
goto err;
}
ret = yr_compiler_get_rules (compiler, &rules);
if (ret == ERROR_INSUFICIENT_MEMORY) {
errno = ENOMEM;
reply_with_perror ("yr_compiler_get_rules");
}
err:
#ifndef HAVE_ATTRIBUTE_CLEANUP
yr_compiler_destroy (compiler);
#endif
return ret;
}
/* Yara compilation error callback.
* Reports back the compilation error message.
* Prints compilation warnings if verbose.
*/
static void
compile_error_callback (int level, const char *name, int line,
const char *message, void *data)
{
if (level == YARA_ERROR_LEVEL_ERROR)
fprintf (stderr, "Yara error (line %d): %s\n", line, message);
else if (verbose)
fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
}
/* Clean up yara handle on daemon exit. */
void yara_finalize (void) __attribute__((destructor));
void
yara_finalize (void)
{
int r;
if (!initialized)
return;
if (rules != NULL) {
yr_rules_destroy (rules);
rules = NULL;
}
r = yr_finalize ();
if (r != ERROR_SUCCESS)
perror ("yr_finalize");
initialized = false;
}
static void
cleanup_destroy_yara_compiler (void *ptr)
{
YR_COMPILER *compiler = * (YR_COMPILER **) ptr;
if (compiler != NULL)
yr_compiler_destroy (compiler);
}
int
optgroup_libyara_available (void)
{
return 1;
}
#else /* !HAVE_YARA */
OPTGROUP_LIBYARA_NOT_AVAILABLE
#endif /* !HAVE_YARA */

View File

@@ -170,6 +170,7 @@ daemon/uuids.c
daemon/wc.c
daemon/xattr.c
daemon/xfs.c
daemon/yara.c
daemon/zero.c
daemon/zerofree.c
df/df.c

View File

@@ -45,6 +45,8 @@ sources = \
actions_tsk.mli \
authors.ml \
authors.mli \
actions_yara.ml \
actions_yara.mli \
bindtests.ml \
bindtests.mli \
c.ml \
@@ -132,6 +134,7 @@ objects = \
actions_properties.cmo \
actions_properties_deprecated.cmo \
actions_tsk.cmo \
actions_yara.cmo \
actions.cmo \
structs.cmo \
fish_commands.cmo \

View File

@@ -50,7 +50,8 @@ let daemon_functions =
Actions_core_deprecated.daemon_functions @
Actions_debug.daemon_functions @
Actions_hivex.daemon_functions @
Actions_tsk.daemon_functions
Actions_tsk.daemon_functions @
Actions_yara.daemon_functions
(* Some post-processing of the basic lists of actions. *)

48
generator/actions_yara.ml Normal file
View File

@@ -0,0 +1,48 @@
(* libguestfs
* Copyright (C) 2009-2017 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
(* Please read generator/README first. *)
open Types
(* Yara APIs. *)
let daemon_functions = [
{ defaults with
name = "yara_load"; added = (1, 37, 13);
style = RErr, [FileIn "filename"], [];
progress = true; cancellable = true;
optional = Some "libyara";
shortdesc = "load yara rules within libguestfs";
longdesc = "\
Upload a set of Yara rules from local file F<filename>.
Yara rules allow to categorize files based on textual or binary patterns
within their content.
See C<guestfs_yara_scan> to see how to scan files with the loaded rules.
Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.
Rules in source code format cannot include external files. In such cases,
it is recommended to compile them first.
Previously loaded rules will be destroyed." };
]

View File

@@ -0,0 +1,21 @@
(* libguestfs
* Copyright (C) 2009-2017 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)
(* Please read generator/README first. *)
val daemon_functions : Types.action list

View File

@@ -479,6 +479,7 @@ let proc_nr = [
469, "aug_transform";
470, "internal_find_inode";
471, "mksquashfs";
472, "yara_load";
]
(* End of list. If adding a new entry, add it at the end of the list

View File

@@ -1 +1 @@
471
472

View File

@@ -152,6 +152,7 @@ daemon/uuids.c
daemon/wc.c
daemon/xattr.c
daemon/xfs.c
daemon/yara.c
daemon/zero.c
daemon/zerofree.c
df/df.c