[Libguestfs] [PATCH 2/6] New API: yara_load

Matteo Cafasso noxdafox at gmail.com
Wed Nov 2 19:26:20 UTC 2016


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 at gmail.com>
---
 daemon/Makefile.am   |   1 +
 daemon/yara.c        | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++
 generator/actions.ml |  15 ++++
 src/MAX_PROC_NR      |   2 +-
 4 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 daemon/yara.c

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3a25f43..c385edc 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -200,6 +200,7 @@ guestfsd_SOURCES = \
 	wc.c \
 	xattr.c \
 	xfs.c \
+	yara.c \
 	zero.c \
 	zerofree.c

diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0000000..0d085a8
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,205 @@
+/* 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 <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_LIBYARA
+
+#include <yara.h>
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+
+static int upload_rules_file (char *);
+static int compile_rules_file (const char *);
+static int write_callback (void *, const void *, size_t);
+
+/* Has one FileIn parameter. */
+int
+do_yara_load (void)
+{
+  int ret = 0;
+  char tmpfile[] = "/tmp/yaraXXXXXX";
+
+  ret = upload_rules_file (tmpfile);
+  if (ret < 0)
+    return -1;
+
+  ret = yr_initialize ();
+  if (ret != ERROR_SUCCESS) {
+    reply_with_error ("failed initializing yara");
+    unlink (tmpfile);
+    return -1;
+  }
+
+  /* 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.
+   */
+  ret = yr_rules_load (tmpfile, &rules);
+  if (ret == ERROR_INVALID_FILE)
+    ret = compile_rules_file (tmpfile);
+
+  unlink (tmpfile);
+
+  if (ret != ERROR_SUCCESS) {
+    reply_with_error ("failed loading the rules");
+    yr_finalize ();
+    return -1;
+  }
+
+  ret = yr_finalize ();
+  if (ret != ERROR_SUCCESS) {
+    reply_with_error ("failed finalizing yara");
+    return -1;
+  }
+
+  return 0;
+}
+
+/* Upload rules file on a temporary file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+upload_rules_file (char *rules_path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = 0;
+  struct write_callback_data data = { .written = 0 };
+
+  data.fd = mkstemp (rules_path);
+  if (data.fd == -1) {
+    reply_with_perror ("mkstemp");
+    return -1;
+  }
+
+  ret = receive_file (write_callback, &data.fd);
+  if (ret == -1) {
+    /* Write error. */
+    cancel_receive ();
+    reply_with_error ("write error: %s", rules_path);
+    return -1;
+  }
+  if (ret == -2) {
+    /* Cancellation from library */
+    reply_with_error ("file upload cancelled");
+    return -1;
+  }
+
+  return 0;
+}
+
+/* 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 = 0;
+  FILE *rule_file = NULL;
+  YR_COMPILER *compiler = NULL;
+
+  ret = yr_compiler_create (&compiler);
+  if (ret != ERROR_SUCCESS) {
+    perror ("yr_compiler_create");
+    return ret;
+  }
+
+  rule_file = fopen (rules_path, "r");
+  if (rule_file == NULL) {
+    yr_compiler_destroy (compiler);
+    perror ("unable to open rules file");
+    return ret;
+  }
+
+  ret = yr_compiler_add_file (compiler, rule_file, NULL, rules_path);
+  if (ret > 0) {
+    yr_compiler_destroy (compiler);
+    fclose (rule_file);
+    perror ("yr_compiler_add_file");
+    return ret;
+  }
+
+  ret = yr_compiler_get_rules (compiler, &rules);
+  yr_compiler_destroy (compiler);
+  fclose (rule_file);
+
+  if (ret != ERROR_SUCCESS)
+    perror ("yr_compiler_get_rules");
+
+  return ret;
+}
+
+/* File upload callback, called by receive_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+write_callback (void *data_vp, const void *buf, size_t len)
+{
+  int ret;
+  struct write_callback_data *data = data_vp;
+
+  ret = xwrite (data->fd, buf, len);
+  if (ret == -1)
+    return -1;
+
+  data->written += len;
+
+  if (progress_hint > 0)
+    notify_progress (data->written, progress_hint);
+
+  return 0;
+}
+
+int
+optgroup_libyara_available (void)
+{
+  return 1;
+}
+
+#else   /* !HAVE_LIBYARA */
+
+OPTGROUP_LIBYARA_NOT_AVAILABLE
+
+#endif  /* !HAVE_LIBYARA */
diff --git a/generator/actions.ml b/generator/actions.ml
index 91a1819..14659bd 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13253,6 +13253,21 @@ is removed." };
     shortdesc = "search the entries associated to the given inode";
     longdesc = "Internal function for find_inode." };

+  { defaults with
+    name = "yara_load"; added = (1, 35, 15);
+    style = RErr, [FileIn "filename";], [];
+    proc_nr = Some 471;
+    progress = true; cancellable = true;
+    optional = Some "libyara";
+    shortdesc = "load yara rules within libguestfs";
+    longdesc = "\
+Load a set of Yara rules from F<filename> within libguestfs appliance.
+
+Rules can be both in source code and compiled form.
+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." };
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 5f476b6..c305aa5 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-470
+471
--
2.10.1




More information about the Libguestfs mailing list