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

Pino Toscano ptoscano at redhat.com
Mon Nov 7 15:02:32 UTC 2016


On Wednesday, 2 November 2016 21:26:20 CET Matteo Cafasso wrote:
> 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.

This paragraph may be worth added in the API longdesc as well, since it
gives more hint to users.

> +/* Yara compiled rules. */
> +static YR_RULES *rules = NULL;

This is not properly freed at shutdown -- take a look at what is done
for Augeas, aug_finalize.

> +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 ();

The libyara API docs do not say whether this is doable multiple times,
so I'd do that only once at all.

> +  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 ();

Accoding to the API documentation, yr_finalize "must be called when
you are finished using the library". OTOH, libyara is used also after
this point (by other APIs, for example), so we cannot use yr_finalize
here.

> +  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);

'fd' happens to be the first member in the write_callback_data struct,
so this passes the right address for the callback. OTOH, passing the
address of the struct itself is a better option, so order changes in
the members of the struct won't cause the callback to explode.

> +  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;

Sounds like you could copy the CLEANUP_FCLOSE stuff from the library
to the daemon (see daemon/cleanups.{c,h}).

> +  YR_COMPILER *compiler = NULL;

Likewise, adding a custom CLEANUP_YR_COMPILER would help making this
function less leak prone.

> +  ret = yr_compiler_create (&compiler);
> +  if (ret != ERROR_SUCCESS) {
> +    perror ("yr_compiler_create");

I'd issue reply_with_(p)error instead of perror directly in this
function, avoiding generic error messages in do_yara_load.

> +    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");

It looks like there is yr_compiler_* API for getting more information
on the actual error -- please make use of it in error message, so it's
easier to know why something failed.

Thanks,
-- 
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20161107/40f170c9/attachment.sig>


More information about the Libguestfs mailing list