LCOV - code coverage report
Current view: top level - libpkg - pkg_audit.c (source / functions) Hit Total Coverage
Test: plop Lines: 61 459 13.3 %
Date: 2024-12-28 18:40:32 Functions: 4 23 17.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 17 337 5.0 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       3                 :            :  * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
       4                 :            :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       5                 :            :  * Copyright (c) 2020 Baptiste Daroussin <bapt@FreeBSD.org>
       6                 :            :  * All rights reserved.
       7                 :            :  *
       8                 :            :  * Redistribution and use in source and binary forms, with or without
       9                 :            :  * modification, are permitted provided that the following conditions
      10                 :            :  * are met:
      11                 :            :  * 1. Redistributions of source code must retain the above copyright
      12                 :            :  *    notice, this list of conditions and the following disclaimer
      13                 :            :  *    in this position and unchanged.
      14                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      15                 :            :  *    notice, this list of conditions and the following disclaimer in the
      16                 :            :  *    documentation and/or other materials provided with the distribution.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      19                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      20                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      21                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      22                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      23                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      24                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      25                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      26                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      27                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28                 :            :  */
      29                 :            : 
      30                 :            : #include <sys/mman.h>
      31                 :            : 
      32                 :            : #include <archive.h>
      33                 :            : #include <err.h>
      34                 :            : #include <fcntl.h>
      35                 :            : #include <fnmatch.h>
      36                 :            : #include <stdio.h>
      37                 :            : #include <string.h>
      38                 :            : #include <utlist.h>
      39                 :            : #include <xstring.h>
      40                 :            : 
      41                 :            : #include <yxml.h>
      42                 :            : 
      43                 :            : #ifdef __linux__
      44                 :            : # ifdef __GLIBC__
      45                 :            : #  include <sys/time.h>
      46                 :            : # endif
      47                 :            : #endif
      48                 :            : 
      49                 :            : #include "pkg.h"
      50                 :            : #include "pkg/audit.h"
      51                 :            : #include "private/pkg.h"
      52                 :            : #include "private/event.h"
      53                 :            : 
      54                 :            : /*
      55                 :            :  * The _sorted stuff.
      56                 :            :  *
      57                 :            :  * We are using the optimized search based on the following observations:
      58                 :            :  *
      59                 :            :  * - number of VuXML entries is more likely to be far greater than
      60                 :            :  *   the number of installed ports; thus we should try to optimize
      61                 :            :  *   the walk through all entries for a given port;
      62                 :            :  *
      63                 :            :  * - fnmatch() is good and fast, but if we will compare the audit entry
      64                 :            :  *   name prefix without globbing characters to the prefix of port name
      65                 :            :  *   of the same length and they are different, there is no point to
      66                 :            :  *   check the rest;
      67                 :            :  *
      68                 :            :  * - (most important bit): if parsed VuXML entries are lexicographically
      69                 :            :  *   sorted per the largest prefix with no globbing characters and we
      70                 :            :  *   know how many succeeding entries have the same prefix we can
      71                 :            :  *
      72                 :            :  *   a. skip the rest of the entries once the non-globbing prefix is
      73                 :            :  *      lexicographically larger than the port name prefix of the
      74                 :            :  *      same length: all successive prefixes will be larger as well;
      75                 :            :  *
      76                 :            :  *   b. if we have non-globbing prefix that is lexicographically smaller
      77                 :            :  *      than port name prefix, we can skip all succeeding entries with
      78                 :            :  *      the same prefix; and as some port names tend to repeat due to
      79                 :            :  *      multiple vulnerabilities, it could be a large win.
      80                 :            :  */
      81                 :            : struct pkg_audit_item {
      82                 :            :         struct pkg_audit_entry *e;      /* Entry itself */
      83                 :            :         size_t noglob_len;      /* Prefix without glob characters */
      84                 :            :         size_t next_pfx_incr;   /* Index increment for the entry with
      85                 :            :                                    different prefix */
      86                 :            : };
      87                 :            : 
      88                 :            : struct pkg_audit {
      89                 :            :         struct pkg_audit_entry *entries;
      90                 :            :         struct pkg_audit_item *items;
      91                 :            :         bool parsed;
      92                 :            :         bool loaded;
      93                 :            :         char **ignore_globs;
      94                 :            :         char **ignore_regexp;
      95                 :            :         void *map;
      96                 :            :         size_t len;
      97                 :            : };
      98                 :            : 
      99                 :            : 
     100                 :            : /*
     101                 :            :  * Another small optimization to skip the beginning of the
     102                 :            :  * VuXML entry array, if possible.
     103                 :            :  *
     104                 :            :  * audit_entry_first_byte_idx[ch] represents the index
     105                 :            :  * of the first VuXML entry in the sorted array that has
     106                 :            :  * its non-globbing prefix that is started with the character
     107                 :            :  * 'ch'.  It allows to skip entries from the beginning of the
     108                 :            :  * VuXML array that aren't relevant for the checked port name.
     109                 :            :  */
     110                 :            : static size_t audit_entry_first_byte_idx[256];
     111                 :            : 
     112                 :            : static void
     113                 :          0 : pkg_audit_free_entry(struct pkg_audit_entry *e)
     114                 :            : {
     115                 :            :         struct pkg_audit_package *ppkg, *ppkg_tmp;
     116                 :            :         struct pkg_audit_versions_range *vers, *vers_tmp;
     117                 :            :         struct pkg_audit_cve *cve, *cve_tmp;
     118                 :            :         struct pkg_audit_pkgname *pname, *pname_tmp;
     119                 :            : 
     120         [ #  # ]:          0 :         if (!e->ref) {
     121   [ #  #  #  #  :          0 :                 LL_FOREACH_SAFE(e->packages, ppkg, ppkg_tmp) {
                   #  # ]
     122   [ #  #  #  #  :          0 :                         LL_FOREACH_SAFE(ppkg->versions, vers, vers_tmp) {
                   #  # ]
     123                 :          0 :                                 free(vers->v1.version);
     124                 :          0 :                                 free(vers->v2.version);
     125                 :          0 :                                 free(vers);
     126                 :          0 :                         }
     127                 :            : 
     128   [ #  #  #  #  :          0 :                         LL_FOREACH_SAFE(ppkg->names, pname, pname_tmp) {
                   #  # ]
     129                 :          0 :                                 free(pname->pkgname);
     130                 :          0 :                                 free(pname);
     131                 :          0 :                         }
     132                 :          0 :                 }
     133   [ #  #  #  #  :          0 :                 LL_FOREACH_SAFE(e->cve, cve, cve_tmp) {
                   #  # ]
     134                 :          0 :                         free(cve->cvename);
     135                 :          0 :                         free(cve);
     136                 :          0 :                 }
     137                 :          0 :                         free(e->url);
     138                 :          0 :                         free(e->desc);
     139                 :          0 :                         free(e->id);
     140                 :          0 :         }
     141                 :          0 :         free(e);
     142                 :          0 : }
     143                 :            : 
     144                 :            : static void
     145                 :          0 : pkg_audit_free_list(struct pkg_audit_entry *h)
     146                 :            : {
     147                 :            :         struct pkg_audit_entry *e;
     148                 :            : 
     149         [ #  # ]:          0 :         while (h) {
     150                 :          0 :                 e = h;
     151                 :          0 :                 h = h->next;
     152                 :          0 :                 pkg_audit_free_entry(e);
     153                 :            :         }
     154                 :          0 : }
     155                 :            : 
     156                 :            : struct pkg_audit_extract_cbdata {
     157                 :            :         int out;
     158                 :            :         const char *fname;
     159                 :            :         const char *dest;
     160                 :            : };
     161                 :            : 
     162                 :            : static int
     163                 :          0 : pkg_audit_sandboxed_extract(int fd, void *ud)
     164                 :            : {
     165                 :          0 :         struct pkg_audit_extract_cbdata *cbdata = ud;
     166                 :          0 :         int rc = EPKG_OK;
     167                 :          0 :         struct archive *a = NULL;
     168                 :          0 :         struct archive_entry *ae = NULL;
     169                 :            : 
     170                 :          0 :         a = archive_read_new();
     171                 :            : #if ARCHIVE_VERSION_NUMBER < 3000002
     172                 :            :         archive_read_support_compression_all(a);
     173                 :            : #else
     174                 :          0 :         archive_read_support_filter_all(a);
     175                 :            : #endif
     176                 :            : 
     177                 :          0 :         archive_read_support_format_raw(a);
     178                 :            : 
     179         [ #  # ]:          0 :         if (archive_read_open_fd(a, fd, 4096) != ARCHIVE_OK) {
     180                 :          0 :                 pkg_emit_error("archive_read_open_filename(%s) failed: %s",
     181                 :          0 :                                 cbdata->fname, archive_error_string(a));
     182                 :          0 :                 rc = EPKG_FATAL;
     183                 :          0 :         }
     184                 :            :         else {
     185         [ #  # ]:          0 :                 while (archive_read_next_header(a, &ae) == ARCHIVE_OK) {
     186         [ #  # ]:          0 :                         if (archive_read_data_into_fd(a, cbdata->out) != ARCHIVE_OK) {
     187                 :          0 :                                 pkg_emit_error("archive_read_data_into_fd(%s) failed: %s",
     188                 :          0 :                                                 cbdata->dest, archive_error_string(a));
     189                 :          0 :                                 break;
     190                 :            :                         }
     191                 :            :                 }
     192                 :          0 :                 archive_read_close(a);
     193                 :          0 :                 archive_read_free(a);
     194                 :            :         }
     195                 :            : 
     196                 :          0 :         return (rc);
     197                 :            : }
     198                 :            : 
     199                 :            : int
     200                 :          1 : pkg_audit_fetch(const char *src, const char *dest)
     201                 :            : {
     202                 :          1 :         int fd = -1, outfd = -1;
     203                 :            :         char tmp[MAXPATHLEN];
     204                 :            :         const char *tmpdir;
     205                 :          1 :         int retcode = EPKG_FATAL;
     206                 :          1 :         time_t t = 0;
     207                 :            :         struct stat st;
     208                 :            :         struct pkg_audit_extract_cbdata cbdata;
     209                 :          1 :         int dfd = -1;
     210                 :          1 :         struct timespec ts[2] = {
     211                 :            :                 {
     212                 :            :                 .tv_nsec = 0
     213                 :            :                 },
     214                 :            :                 {
     215                 :            :                 .tv_nsec = 0
     216                 :            :                 }
     217                 :            :         };
     218                 :            : 
     219         [ -  + ]:          1 :         if (src == NULL) {
     220                 :          1 :                 src = pkg_object_string(pkg_config_get("VULNXML_SITE"));
     221                 :          1 :         }
     222                 :            : 
     223                 :          1 :         tmpdir = getenv("TMPDIR");
     224         [ +  - ]:          1 :         if (tmpdir == NULL)
     225                 :          0 :                 tmpdir = "/tmp";
     226                 :            : 
     227                 :          1 :         strlcpy(tmp, tmpdir, sizeof(tmp));
     228                 :          1 :         strlcat(tmp, "/vuln.xml.XXXXXXXXXX", sizeof(tmp));
     229                 :            : 
     230         [ -  + ]:          1 :         if (dest != NULL) {
     231         [ #  # ]:          0 :                 if (stat(dest, &st) != -1)
     232                 :          0 :                         t = st.st_mtime;
     233                 :          0 :         } else {
     234                 :          1 :                 dfd = pkg_get_dbdirfd();
     235         [ +  - ]:          1 :                 if (fstatat(dfd, "vuln.xml", &st, 0) != -1)
     236                 :          0 :                         t = st.st_mtime;
     237                 :            :         }
     238                 :            : 
     239      [ -  +  - ]:          1 :         switch (pkg_fetch_file_tmp(NULL, src, tmp, t)) {
     240                 :            :         case EPKG_OK:
     241                 :          1 :                 break;
     242                 :            :         case EPKG_UPTODATE:
     243                 :          0 :                 pkg_emit_notice("vulnxml file up-to-date");
     244                 :          0 :                 retcode = EPKG_OK;
     245                 :          0 :                 goto cleanup;
     246                 :            :         default:
     247                 :          0 :                 pkg_emit_error("cannot fetch vulnxml file");
     248                 :          0 :                 goto cleanup;
     249                 :            :         }
     250                 :            : 
     251                 :            :         /* Open input fd */
     252                 :          1 :         fd = open(tmp, O_RDONLY);
     253         [ +  - ]:          1 :         if (fd == -1)
     254                 :          0 :                 goto cleanup;
     255                 :            :         /* Open out fd */
     256         [ -  + ]:          1 :         if (dest != NULL) {
     257                 :          0 :                 outfd = open(dest, O_RDWR|O_CREAT|O_TRUNC,
     258                 :            :                     S_IRUSR|S_IRGRP|S_IROTH);
     259                 :          0 :         } else {
     260                 :          1 :                 outfd = openat(dfd, "vuln.xml", O_RDWR|O_CREAT|O_TRUNC,
     261                 :            :                     S_IRUSR|S_IRGRP|S_IROTH);
     262                 :            :         }
     263         [ +  - ]:          1 :         if (outfd == -1) {
     264                 :          0 :                 pkg_emit_errno("pkg_audit_fetch", "open out fd");
     265                 :          0 :                 goto cleanup;
     266                 :            :         }
     267                 :            : 
     268                 :          1 :         cbdata.fname = tmp;
     269                 :          1 :         cbdata.out = outfd;
     270                 :          1 :         cbdata.dest = dest;
     271                 :          1 :         fstat(fd, &st);
     272                 :            : 
     273                 :            :         /* Call sandboxed */
     274                 :          1 :         retcode = pkg_emit_sandbox_call(pkg_audit_sandboxed_extract, fd, &cbdata);
     275                 :          1 :         ts[0].tv_sec = st.st_mtime;
     276                 :          1 :         ts[1].tv_sec = st.st_mtime;
     277                 :          1 :         futimens(outfd, ts);
     278                 :            : 
     279                 :            : cleanup:
     280                 :          1 :         unlink(tmp);
     281                 :            : 
     282         [ -  + ]:          1 :         if (fd != -1)
     283                 :          1 :                 close(fd);
     284         [ -  + ]:          1 :         if (outfd != -1)
     285                 :          1 :                 close(outfd);
     286                 :            : 
     287                 :          1 :         return (retcode);
     288                 :            : }
     289                 :            : 
     290                 :            : /*
     291                 :            :  * Expand multiple names to a set of audit entries
     292                 :            :  */
     293                 :            : static void
     294                 :          0 : pkg_audit_expand_entry(struct pkg_audit_entry *entry, struct pkg_audit_entry **head)
     295                 :            : {
     296                 :            :         struct pkg_audit_entry *n;
     297                 :            :         struct pkg_audit_pkgname *ncur;
     298                 :            :         struct pkg_audit_package *pcur;
     299                 :            : 
     300                 :            :         /* Set the name of the current entry */
     301   [ #  #  #  # ]:          0 :         if (entry->packages == NULL || entry->packages->names == NULL) {
     302                 :          0 :                 pkg_audit_free_entry(entry);
     303                 :          0 :                 return;
     304                 :            :         }
     305                 :            : 
     306         [ #  # ]:          0 :         LL_FOREACH(entry->packages, pcur) {
     307         [ #  # ]:          0 :                 LL_FOREACH(pcur->names, ncur) {
     308                 :          0 :                         n = xcalloc(1, sizeof(struct pkg_audit_entry));
     309                 :          0 :                         n->pkgname = ncur->pkgname;
     310                 :            :                         /* Set new entry as reference entry */
     311                 :          0 :                         n->ref = true;
     312                 :          0 :                         n->cve = entry->cve;
     313                 :          0 :                         n->desc = entry->desc;
     314                 :          0 :                         n->versions = pcur->versions;
     315                 :          0 :                         n->url = entry->url;
     316                 :          0 :                         n->id = entry->id;
     317                 :          0 :                         LL_PREPEND(*head, n);
     318                 :          0 :                 }
     319                 :          0 :         }
     320                 :          0 :         LL_PREPEND(*head, entry);
     321                 :          0 : }
     322                 :            : 
     323                 :            : enum vulnxml_parse_state {
     324                 :            :         VULNXML_PARSE_INIT = 0,
     325                 :            :         VULNXML_PARSE_VULN,
     326                 :            :         VULNXML_PARSE_TOPIC,
     327                 :            :         VULNXML_PARSE_PACKAGE,
     328                 :            :         VULNXML_PARSE_PACKAGE_NAME,
     329                 :            :         VULNXML_PARSE_RANGE,
     330                 :            :         VULNXML_PARSE_RANGE_GT,
     331                 :            :         VULNXML_PARSE_RANGE_GE,
     332                 :            :         VULNXML_PARSE_RANGE_LT,
     333                 :            :         VULNXML_PARSE_RANGE_LE,
     334                 :            :         VULNXML_PARSE_RANGE_EQ,
     335                 :            :         VULNXML_PARSE_CVE
     336                 :            : };
     337                 :            : 
     338                 :            : enum vulnxml_parse_attribute_state {
     339                 :            :         VULNXML_ATTR_NONE = 0,
     340                 :            :         VULNXML_ATTR_VID,
     341                 :            : };
     342                 :            : 
     343                 :            : struct vulnxml_userdata {
     344                 :            :         struct pkg_audit_entry *cur_entry;
     345                 :            :         struct pkg_audit *audit;
     346                 :            :         enum vulnxml_parse_state state;
     347                 :            :         xstring *content;
     348                 :            :         int range_num;
     349                 :            :         enum vulnxml_parse_attribute_state attr;
     350                 :            : };
     351                 :            : 
     352                 :            : static void
     353                 :          0 : vulnxml_start_element(struct vulnxml_userdata *ud, yxml_t *xml)
     354                 :            : {
     355                 :            :         struct pkg_audit_versions_range *vers;
     356                 :            :         struct pkg_audit_pkgname *name_entry;
     357                 :            :         struct pkg_audit_package *pkg_entry;
     358                 :            : 
     359   [ #  #  #  # ]:          0 :         if (ud->state == VULNXML_PARSE_INIT && STRIEQ(xml->elem, "vuln")) {
     360                 :          0 :                 ud->cur_entry = xcalloc(1, sizeof(struct pkg_audit_entry));
     361                 :          0 :                 ud->cur_entry->next = ud->audit->entries;
     362                 :          0 :                 ud->state = VULNXML_PARSE_VULN;
     363                 :          0 :         }
     364   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_VULN && STRIEQ(xml->elem, "topic")) {
     365                 :          0 :                 ud->state = VULNXML_PARSE_TOPIC;
     366                 :          0 :         }
     367   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_VULN && STRIEQ(xml->elem, "package")) {
     368                 :          0 :                 pkg_entry = xcalloc(1, sizeof(struct pkg_audit_package));
     369                 :          0 :                 LL_PREPEND(ud->cur_entry->packages, pkg_entry);
     370                 :          0 :                 ud->state = VULNXML_PARSE_PACKAGE;
     371                 :          0 :         }
     372   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_VULN && STRIEQ(xml->elem, "cvename")) {
     373                 :          0 :                 ud->state = VULNXML_PARSE_CVE;
     374                 :          0 :         }
     375   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_PACKAGE && STRIEQ(xml->elem, "name")) {
     376                 :          0 :                 ud->state = VULNXML_PARSE_PACKAGE_NAME;
     377                 :          0 :                 name_entry = xcalloc(1, sizeof(struct pkg_audit_pkgname));
     378                 :          0 :                 LL_PREPEND(ud->cur_entry->packages->names, name_entry);
     379                 :          0 :         }
     380   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_PACKAGE && STRIEQ(xml->elem, "range")) {
     381                 :          0 :                 ud->state = VULNXML_PARSE_RANGE;
     382                 :          0 :                 vers = xcalloc(1, sizeof(struct pkg_audit_versions_range));
     383                 :          0 :                 LL_PREPEND(ud->cur_entry->packages->versions, vers);
     384                 :          0 :                 ud->range_num = 0;
     385                 :          0 :         }
     386   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE && STRIEQ(xml->elem, "gt")) {
     387                 :          0 :                 ud->range_num ++;
     388                 :          0 :                 ud->state = VULNXML_PARSE_RANGE_GT;
     389                 :          0 :         }
     390   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE && STRIEQ(xml->elem, "ge")) {
     391                 :          0 :                 ud->range_num ++;
     392                 :          0 :                 ud->state = VULNXML_PARSE_RANGE_GE;
     393                 :          0 :         }
     394   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE && STRIEQ(xml->elem, "lt")) {
     395                 :          0 :                 ud->range_num ++;
     396                 :          0 :                 ud->state = VULNXML_PARSE_RANGE_LT;
     397                 :          0 :         }
     398   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE && STRIEQ(xml->elem, "le")) {
     399                 :          0 :                 ud->range_num ++;
     400                 :          0 :                 ud->state = VULNXML_PARSE_RANGE_LE;
     401                 :          0 :         }
     402   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE && STRIEQ(xml->elem, "eq")) {
     403                 :          0 :                 ud->range_num ++;
     404                 :          0 :                 ud->state = VULNXML_PARSE_RANGE_EQ;
     405                 :          0 :         }
     406                 :          0 : }
     407                 :            : 
     408                 :            : static void
     409                 :          0 : vulnxml_end_element(struct vulnxml_userdata *ud, yxml_t *xml)
     410                 :            : {
     411                 :            :         struct pkg_audit_cve *cve;
     412                 :            :         struct pkg_audit_entry *entry;
     413                 :            :         struct pkg_audit_versions_range *vers;
     414                 :          0 :         int range_type = -1;
     415                 :            : 
     416                 :          0 :         fflush(ud->content->fp);
     417   [ #  #  #  # ]:          0 :         if (ud->state == VULNXML_PARSE_VULN && STRIEQ(xml->elem, "vuxml")) {
     418                 :          0 :                 pkg_audit_expand_entry(ud->cur_entry, &ud->audit->entries);
     419                 :          0 :                 ud->state = VULNXML_PARSE_INIT;
     420                 :          0 :         }
     421   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_TOPIC && STRIEQ(xml->elem, "vuln")) {
     422                 :          0 :                 ud->cur_entry->desc = xstrdup(ud->content->buf);
     423                 :          0 :                 ud->state = VULNXML_PARSE_VULN;
     424                 :          0 :         }
     425   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_CVE && STRIEQ(xml->elem, "references")) {
     426                 :          0 :                 entry = ud->cur_entry;
     427                 :          0 :                 cve = xmalloc(sizeof(struct pkg_audit_cve));
     428                 :          0 :                 cve->cvename = xstrdup(ud->content->buf);
     429                 :          0 :                 LL_PREPEND(entry->cve, cve);
     430                 :          0 :                 ud->state = VULNXML_PARSE_VULN;
     431                 :          0 :         }
     432   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_PACKAGE && STRIEQ(xml->elem, "affects")) {
     433                 :          0 :                 ud->state = VULNXML_PARSE_VULN;
     434                 :          0 :         }
     435   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_PACKAGE_NAME && STRIEQ(xml->elem, "package")) {
     436                 :          0 :                 ud->cur_entry->packages->names->pkgname = xstrdup(ud->content->buf);
     437                 :          0 :                 ud->state = VULNXML_PARSE_PACKAGE;
     438                 :          0 :         }
     439   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE && STRIEQ(xml->elem, "package")) {
     440                 :          0 :                 ud->state = VULNXML_PARSE_PACKAGE;
     441                 :          0 :         }
     442   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE_GT && STRIEQ(xml->elem, "range")) {
     443                 :          0 :                 range_type = GT;
     444                 :          0 :                 ud->state = VULNXML_PARSE_RANGE;
     445                 :          0 :         }
     446   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE_GE && STRIEQ(xml->elem, "range")) {
     447                 :          0 :                 range_type = GTE;
     448                 :          0 :                 ud->state = VULNXML_PARSE_RANGE;
     449                 :          0 :         }
     450   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE_LT && STRIEQ(xml->elem, "range")) {
     451                 :          0 :                 range_type = LT;
     452                 :          0 :                 ud->state = VULNXML_PARSE_RANGE;
     453                 :          0 :         }
     454   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE_LE && STRIEQ(xml->elem, "range")) {
     455                 :          0 :                 range_type = LTE;
     456                 :          0 :                 ud->state = VULNXML_PARSE_RANGE;
     457                 :          0 :         }
     458   [ #  #  #  # ]:          0 :         else if (ud->state == VULNXML_PARSE_RANGE_EQ && STRIEQ(xml->elem, "range")) {
     459                 :          0 :                 range_type = EQ;
     460                 :          0 :                 ud->state = VULNXML_PARSE_RANGE;
     461                 :          0 :         }
     462                 :            : 
     463         [ #  # ]:          0 :         if (range_type > 0) {
     464                 :          0 :                 vers = ud->cur_entry->packages->versions;
     465         [ #  # ]:          0 :                 if (ud->range_num == 1) {
     466                 :          0 :                         vers->v1.version = xstrdup(ud->content->buf);
     467                 :          0 :                         vers->v1.type = range_type;
     468                 :          0 :                 }
     469         [ #  # ]:          0 :                 else if (ud->range_num == 2) {
     470                 :          0 :                         vers->v2.version = xstrdup(ud->content->buf);
     471                 :          0 :                         vers->v2.type = range_type;
     472                 :          0 :                 }
     473                 :          0 :         }
     474                 :          0 :         xstring_reset(ud->content);
     475                 :          0 : }
     476                 :            : 
     477                 :            : static void
     478                 :          0 : vulnxml_start_attribute(struct vulnxml_userdata *ud, yxml_t *xml)
     479                 :            : {
     480         [ #  # ]:          0 :         if (ud->state != VULNXML_PARSE_VULN)
     481                 :          0 :                 return;
     482                 :            : 
     483         [ #  # ]:          0 :         if (STRIEQ(xml->attr, "vid"))
     484                 :          0 :                 ud->attr = VULNXML_ATTR_VID;
     485                 :          0 : }
     486                 :            : 
     487                 :            : static void
     488                 :          0 : vulnxml_end_attribute(struct vulnxml_userdata *ud, yxml_t *xml __unused)
     489                 :            : {
     490                 :          0 :         fflush(ud->content->fp);
     491   [ #  #  #  # ]:          0 :         if (ud->state == VULNXML_PARSE_VULN && ud->attr == VULNXML_ATTR_VID) {
     492                 :          0 :                 ud->cur_entry->id = xstrdup(ud->content->buf);
     493                 :          0 :                 ud->attr = VULNXML_ATTR_NONE;
     494                 :          0 :         }
     495                 :          0 :         xstring_reset(ud->content);
     496                 :          0 : }
     497                 :            : 
     498                 :            : static void
     499                 :          0 : vulnxml_val_attribute(struct vulnxml_userdata *ud, yxml_t *xml)
     500                 :            : {
     501   [ #  #  #  # ]:          0 :         if (ud->state == VULNXML_PARSE_VULN && ud->attr == VULNXML_ATTR_VID) {
     502                 :          0 :                 fputs(xml->data, ud->content->fp);
     503                 :          0 :         }
     504                 :          0 : }
     505                 :            : 
     506                 :            : static void
     507                 :          0 : vulnxml_handle_data(struct vulnxml_userdata *ud, yxml_t *xml)
     508                 :            : {
     509                 :            : 
     510   [ #  #  #  #  :          0 :         switch(ud->state) {
          #  #  #  #  #  
             #  #  #  # ]
     511                 :            :         case VULNXML_PARSE_INIT:
     512                 :            :         case VULNXML_PARSE_VULN:
     513                 :            :         case VULNXML_PARSE_PACKAGE:
     514                 :            :         case VULNXML_PARSE_RANGE:
     515                 :            :                 /* On these states we do not need any data */
     516                 :          0 :                 break;
     517                 :            :         case VULNXML_PARSE_TOPIC:
     518                 :            :         case VULNXML_PARSE_PACKAGE_NAME:
     519                 :            :         case VULNXML_PARSE_CVE:
     520                 :            :         case VULNXML_PARSE_RANGE_GT:
     521                 :            :         case VULNXML_PARSE_RANGE_GE:
     522                 :            :         case VULNXML_PARSE_RANGE_LT:
     523                 :            :         case VULNXML_PARSE_RANGE_LE:
     524                 :            :         case VULNXML_PARSE_RANGE_EQ:
     525                 :          0 :                 fputs(xml->data, ud->content->fp);
     526                 :          0 :                 break;
     527                 :            :         }
     528                 :          0 : }
     529                 :            : 
     530                 :            : static int
     531                 :          0 : pkg_audit_parse_vulnxml(struct pkg_audit *audit)
     532                 :            : {
     533                 :          0 :         int ret = EPKG_FATAL;
     534                 :            :         yxml_t x;
     535                 :            :         yxml_ret_t r;
     536                 :            :         char buf[BUFSIZ];
     537                 :            :         char *walk, *end;
     538                 :            :         struct vulnxml_userdata ud;
     539                 :            : 
     540                 :          0 :         yxml_init(&x, buf, BUFSIZ);
     541                 :          0 :         ud.cur_entry = NULL;
     542                 :          0 :         ud.audit = audit;
     543                 :          0 :         ud.range_num = 0;
     544                 :          0 :         ud.state = VULNXML_PARSE_INIT;
     545                 :          0 :         ud.content = xstring_new();
     546                 :            : 
     547                 :          0 :         walk = audit->map;
     548                 :          0 :         end = walk + audit->len;
     549         [ #  # ]:          0 :         while (walk < end) {
     550                 :          0 :                 r = yxml_parse(&x, *walk++);
     551   [ #  #  #  #  :          0 :                 switch (r) {
          #  #  #  #  #  
                   #  # ]
     552                 :            :                 case YXML_EREF:
     553                 :            :                 case YXML_ESTACK:
     554                 :          0 :                         pkg_emit_error("Unexpected EOF while parsing vulnxml");
     555                 :          0 :                         goto out;
     556                 :            :                 case YXML_ESYN:
     557                 :          0 :                         pkg_emit_error("Syntax error while parsing vulnxml");
     558                 :          0 :                         goto out;
     559                 :            :                 case YXML_ECLOSE:
     560                 :          0 :                         pkg_emit_error("Close tag does not match open tag line %d", x.line);
     561                 :          0 :                         goto out;
     562                 :            :                 case YXML_ELEMSTART:
     563                 :          0 :                         vulnxml_start_element(&ud, &x);
     564                 :          0 :                                 break;
     565                 :            :                 case YXML_ELEMEND:
     566                 :          0 :                         vulnxml_end_element(&ud, &x);
     567                 :          0 :                         break;
     568                 :            :                 case YXML_CONTENT:
     569                 :          0 :                         vulnxml_handle_data(&ud, &x);
     570                 :          0 :                         break;
     571                 :            :                 case YXML_ATTRVAL:
     572                 :          0 :                         vulnxml_val_attribute(&ud, &x);
     573                 :          0 :                         break;
     574                 :            :                 case YXML_ATTRSTART:
     575                 :          0 :                         vulnxml_start_attribute(&ud, &x);
     576                 :          0 :                         break;
     577                 :            :                         /* ignore */
     578                 :            :                 case YXML_ATTREND:
     579                 :          0 :                         vulnxml_end_attribute(&ud, &x);
     580                 :            :                         /* ignore */
     581                 :          0 :                         break;
     582                 :            :                 }
     583                 :            :         }
     584                 :            : 
     585         [ #  # ]:          0 :         if (yxml_eof(&x) == YXML_OK)
     586                 :          0 :                 ret = EPKG_OK;
     587                 :            :         else
     588                 :          0 :                 pkg_emit_error("Invalid end of XML");
     589                 :            : out:
     590                 :          0 :         xstring_free(ud.content);
     591                 :            : 
     592                 :          0 :         return (ret);
     593                 :            : }
     594                 :            : 
     595                 :            : /*
     596                 :            :  * Returns the length of the largest prefix without globbing
     597                 :            :  * characters, as per fnmatch().
     598                 :            :  */
     599                 :            : static size_t
     600                 :          0 : pkg_audit_str_noglob_len(const char *s)
     601                 :            : {
     602                 :            :         size_t n;
     603                 :            : 
     604   [ #  #  #  #  :          0 :         for (n = 0; s[n] && s[n] != '*' && s[n] != '?' &&
             #  #  #  # ]
     605   [ #  #  #  #  :          0 :             s[n] != '[' && s[n] != '{' && s[n] != '\\'; n++);
                   #  # ]
     606                 :            : 
     607                 :          0 :         return (n);
     608                 :            : }
     609                 :            : 
     610                 :            : /*
     611                 :            :  * Helper for quicksort that lexicographically orders prefixes.
     612                 :            :  */
     613                 :            : static int
     614                 :          0 : pkg_audit_entry_cmp(const void *a, const void *b)
     615                 :            : {
     616                 :            :         const struct pkg_audit_item *e1, *e2;
     617                 :            :         size_t min_len;
     618                 :            :         int result;
     619                 :            : 
     620                 :          0 :         e1 = (const struct pkg_audit_item *)a;
     621                 :          0 :         e2 = (const struct pkg_audit_item *)b;
     622                 :            : 
     623         [ #  # ]:          0 :         min_len = (e1->noglob_len < e2->noglob_len ?
     624                 :          0 :             e1->noglob_len : e2->noglob_len);
     625                 :          0 :         result = strncmp(e1->e->pkgname, e2->e->pkgname, min_len);
     626                 :            :         /*
     627                 :            :          * Additional check to see if some word is a prefix of an
     628                 :            :          * another one and, thus, should go before the former.
     629                 :            :          */
     630         [ #  # ]:          0 :         if (result == 0) {
     631         [ #  # ]:          0 :                 if (e1->noglob_len < e2->noglob_len)
     632                 :          0 :                         result = -1;
     633         [ #  # ]:          0 :                 else if (e1->noglob_len > e2->noglob_len)
     634                 :          0 :                         result = 1;
     635                 :          0 :         }
     636                 :            : 
     637                 :          0 :         return (result);
     638                 :            : }
     639                 :            : 
     640                 :            : /*
     641                 :            :  * Sorts VuXML entries and calculates increments to jump to the
     642                 :            :  * next distinct prefix.
     643                 :            :  */
     644                 :            : static struct pkg_audit_item *
     645                 :          0 : pkg_audit_preprocess(struct pkg_audit_entry *h)
     646                 :            : {
     647                 :            :         struct pkg_audit_entry *e;
     648                 :            :         struct pkg_audit_item *ret;
     649                 :            :         size_t i, n, tofill;
     650                 :            : 
     651                 :          0 :         n = 0;
     652         [ #  # ]:          0 :         LL_FOREACH(h, e)
     653                 :          0 :                 n++;
     654                 :            : 
     655                 :          0 :         ret = xcalloc(n + 1, sizeof(ret[0]));
     656                 :          0 :         n = 0;
     657         [ #  # ]:          0 :         LL_FOREACH(h, e) {
     658         [ #  # ]:          0 :                 if (e->pkgname != NULL) {
     659                 :          0 :                         ret[n].e = e;
     660                 :          0 :                         ret[n].noglob_len = pkg_audit_str_noglob_len(e->pkgname);
     661                 :          0 :                         ret[n].next_pfx_incr = 1;
     662                 :          0 :                         n++;
     663                 :          0 :                 }
     664                 :          0 :         }
     665                 :            : 
     666                 :          0 :         qsort(ret, n, sizeof(*ret), pkg_audit_entry_cmp);
     667                 :            : 
     668                 :            :         /*
     669                 :            :          * Determining jump indexes to the next different prefix.
     670                 :            :          * Only non-1 increments are calculated there.
     671                 :            :          *
     672                 :            :          * Due to the current usage that picks only increment for the
     673                 :            :          * first of the non-unique prefixes in a row, we could
     674                 :            :          * calculate only that one and skip calculations for the
     675                 :            :          * succeeding, but for the uniformity and clarity we're
     676                 :            :          * calculating 'em all.
     677                 :            :          */
     678         [ #  # ]:          0 :         for (n = 1, tofill = 0; ret[n].e; n++) {
     679         [ #  # ]:          0 :                 if (ret[n - 1].noglob_len != ret[n].noglob_len) {
     680                 :            :                         struct pkg_audit_item *base;
     681                 :            : 
     682                 :          0 :                         base = ret + n - tofill;
     683         [ #  # ]:          0 :                         for (i = 0; tofill > 1; i++, tofill--)
     684                 :          0 :                                 base[i].next_pfx_incr = tofill;
     685                 :          0 :                         tofill = 1;
     686         [ #  # ]:          0 :                 } else if (STREQ(ret[n - 1].e->pkgname, ret[n].e->pkgname)) {
     687                 :          0 :                         tofill++;
     688                 :          0 :                 } else {
     689                 :          0 :                         tofill = 1;
     690                 :            :                 }
     691                 :          0 :         }
     692                 :            : 
     693                 :            :         /* Calculate jump indexes for the first byte of the package name */
     694                 :          0 :         memset(audit_entry_first_byte_idx, '\0', sizeof(audit_entry_first_byte_idx));
     695         [ #  # ]:          0 :         for (n = 1, i = 0; n < 256; n++) {
     696   [ #  #  #  #  :          0 :                 while (ret[i].e != NULL &&
                   #  # ]
     697                 :          0 :                     (size_t)(ret[i].e->pkgname[0]) < n)
     698                 :          0 :                         i++;
     699                 :          0 :                 audit_entry_first_byte_idx[n] = i;
     700                 :          0 :         }
     701                 :            : 
     702                 :          0 :         return (ret);
     703                 :            : }
     704                 :            : 
     705                 :            : static bool
     706                 :          0 : pkg_audit_version_match(const char *pkgversion, struct pkg_audit_version *v)
     707                 :            : {
     708                 :          0 :         bool res = false;
     709                 :            : 
     710                 :            :         /*
     711                 :            :          * Return true so it is easier for the caller to handle case where there is
     712                 :            :          * only one version to match: the missing one will always match.
     713                 :            :          */
     714         [ #  # ]:          0 :         if (v->version == NULL)
     715                 :          0 :                 return (true);
     716                 :            : 
     717   [ #  #  #  # ]:          0 :         switch (pkg_version_cmp(pkgversion, v->version)) {
     718                 :            :         case -1:
     719   [ #  #  #  # ]:          0 :                 if (v->type == LT || v->type == LTE)
     720                 :          0 :                         res = true;
     721                 :          0 :                 break;
     722                 :            :         case 0:
     723   [ #  #  #  #  :          0 :                 if (v->type == EQ || v->type == LTE || v->type == GTE)
                   #  # ]
     724                 :          0 :                         res = true;
     725                 :          0 :                 break;
     726                 :            :         case 1:
     727   [ #  #  #  # ]:          0 :                 if (v->type == GT || v->type == GTE)
     728                 :          0 :                         res = true;
     729                 :          0 :                 break;
     730                 :            :         }
     731                 :          0 :         return (res);
     732                 :          0 : }
     733                 :            : 
     734                 :            : static void
     735                 :          0 : pkg_audit_add_entry(struct pkg_audit_entry *e, struct pkg_audit_issues **ai)
     736                 :            : {
     737                 :            :         struct pkg_audit_issue *issue;
     738                 :            : 
     739         [ #  # ]:          0 :         if (*ai == NULL)
     740                 :          0 :                 *ai = xcalloc(1, sizeof(**ai));
     741                 :          0 :         issue = xcalloc(1, sizeof(*issue));
     742                 :          0 :         issue->audit = e;
     743                 :          0 :         (*ai)->count++;
     744   [ #  #  #  # ]:          0 :         LL_APPEND((*ai)->issues, issue);
     745                 :          0 : }
     746                 :            : 
     747                 :            : bool
     748                 :          0 : pkg_audit_is_vulnerable(struct pkg_audit *audit, struct pkg *pkg,
     749                 :            :     struct pkg_audit_issues **ai, bool stop_quick)
     750                 :            : {
     751                 :            :         struct pkg_audit_entry *e;
     752                 :            :         struct pkg_audit_versions_range *vers;
     753                 :            :         struct pkg_audit_item *a;
     754                 :          0 :         bool res = false, res1, res2;
     755                 :            : 
     756         [ #  # ]:          0 :         if (!audit->parsed)
     757                 :          0 :                 return false;
     758                 :            : 
     759                 :            :         /* check if we decided to ignore that package or not */
     760   [ #  #  #  # ]:          0 :         if (match_ucl_lists(pkg->name,
     761                 :          0 :             pkg_config_get("AUDIT_IGNORE_GLOB"),
     762                 :          0 :             pkg_config_get("AUDIT_IGNORE_REGEX")))
     763                 :          0 :                 return (false);
     764                 :            : 
     765                 :          0 :         a = audit->items;
     766                 :          0 :         a += audit_entry_first_byte_idx[(size_t)pkg->name[0]];
     767                 :            : 
     768         [ #  # ]:          0 :         for (; (e = a->e) != NULL; a += a->next_pfx_incr) {
     769                 :            :                 int cmp;
     770                 :            :                 size_t i;
     771                 :            : 
     772                 :            :                 /*
     773                 :            :                  * Audit entries are sorted, so if we had found one
     774                 :            :                  * that is lexicographically greater than our name,
     775                 :            :                  * it and the rest won't match our name.
     776                 :            :                  */
     777                 :          0 :                 cmp = strncmp(pkg->name, e->pkgname, a->noglob_len);
     778         [ #  # ]:          0 :                 if (cmp > 0)
     779                 :          0 :                         continue;
     780         [ #  # ]:          0 :                 else if (cmp < 0)
     781                 :          0 :                         break;
     782                 :            : 
     783         [ #  # ]:          0 :                 for (i = 0; i < a->next_pfx_incr; i++) {
     784                 :          0 :                         e = a[i].e;
     785         [ #  # ]:          0 :                         if (fnmatch(e->pkgname, pkg->name, 0) != 0)
     786                 :          0 :                                 continue;
     787                 :            : 
     788         [ #  # ]:          0 :                         if (pkg->version == NULL) {
     789                 :            :                                 /*
     790                 :            :                                  * Assume that all versions should be checked
     791                 :            :                                  */
     792                 :          0 :                                 res = true;
     793                 :          0 :                                 pkg_audit_add_entry(e, ai);
     794                 :          0 :                         }
     795                 :            :                         else {
     796         [ #  # ]:          0 :                                 LL_FOREACH(e->versions, vers) {
     797                 :          0 :                                         res1 = pkg_audit_version_match(pkg->version, &vers->v1);
     798                 :          0 :                                         res2 = pkg_audit_version_match(pkg->version, &vers->v2);
     799                 :            : 
     800   [ #  #  #  # ]:          0 :                                         if (res1 && res2) {
     801                 :          0 :                                                 res = true;
     802                 :          0 :                                                 pkg_audit_add_entry(e, ai);
     803                 :          0 :                                                 break;
     804                 :            :                                         }
     805                 :          0 :                                 }
     806                 :            :                         }
     807                 :            : 
     808   [ #  #  #  # ]:          0 :                         if (res && stop_quick)
     809                 :          0 :                                 return (res);
     810                 :          0 :                 }
     811                 :          0 :         }
     812                 :            : 
     813                 :          0 :         return (res);
     814                 :          0 : }
     815                 :            : 
     816                 :            : struct pkg_audit *
     817                 :          1 : pkg_audit_new(void)
     818                 :            : {
     819                 :            :         struct pkg_audit *audit;
     820                 :            : 
     821                 :          1 :         audit = xcalloc(1, sizeof(struct pkg_audit));
     822                 :            : 
     823                 :          1 :         return (audit);
     824                 :            : }
     825                 :            : 
     826                 :            : int
     827                 :          1 : pkg_audit_load(struct pkg_audit *audit, const char *fname)
     828                 :            : {
     829                 :            :         int dfd, fd;
     830                 :            :         void *mem;
     831                 :            :         struct stat st;
     832                 :            : 
     833         [ -  + ]:          1 :         if (fname != NULL) {
     834         [ #  # ]:          0 :                 if ((fd = open(fname, O_RDONLY)) == -1)
     835                 :          0 :                         return (EPKG_FATAL);
     836                 :          0 :         } else {
     837                 :          1 :                 dfd = pkg_get_dbdirfd();
     838         [ +  - ]:          1 :                 if ((fd = openat(dfd, "vuln.xml", O_RDONLY)) == -1)
     839                 :          0 :                         return (EPKG_FATAL);
     840                 :            :         }
     841                 :            : 
     842         [ +  - ]:          1 :         if (fstat(fd, &st) == -1) {
     843                 :          0 :                 close(fd);
     844                 :          0 :                 return (EPKG_FATAL);
     845                 :            :         }
     846                 :            : 
     847         [ +  - ]:          1 :         if ((mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
     848                 :          0 :                 close(fd);
     849                 :          0 :                 return (EPKG_FATAL);
     850                 :            :         }
     851                 :          1 :         close(fd);
     852                 :            : 
     853                 :          1 :         audit->map = mem;
     854                 :          1 :         audit->len = st.st_size;
     855                 :          1 :         audit->loaded = true;
     856                 :            : 
     857                 :          1 :         return (EPKG_OK);
     858                 :          1 : }
     859                 :            : 
     860                 :            : /* This can and should be executed after cap_enter(3) */
     861                 :            : int
     862                 :          0 : pkg_audit_process(struct pkg_audit *audit)
     863                 :            : {
     864         [ #  # ]:          0 :         if (geteuid() == 0)
     865                 :          0 :                 return (EPKG_FATAL);
     866                 :            : 
     867         [ #  # ]:          0 :         if (!audit->loaded)
     868                 :          0 :                 return (EPKG_FATAL);
     869                 :            : 
     870         [ #  # ]:          0 :         if (pkg_audit_parse_vulnxml(audit) == EPKG_FATAL)
     871                 :          0 :                 return (EPKG_FATAL);
     872                 :            : 
     873                 :          0 :         audit->items = pkg_audit_preprocess(audit->entries);
     874                 :          0 :         audit->parsed = true;
     875                 :            : 
     876                 :          0 :         return (EPKG_OK);
     877                 :          0 : }
     878                 :            : 
     879                 :            : void
     880                 :          1 : pkg_audit_free (struct pkg_audit *audit)
     881                 :            : {
     882         [ -  + ]:          1 :         if (audit != NULL) {
     883         [ +  - ]:          1 :                 if (audit->parsed) {
     884                 :          0 :                         pkg_audit_free_list(audit->entries);
     885                 :          0 :                         free(audit->items);
     886                 :          0 :                 }
     887         [ -  + ]:          1 :                 if (audit->loaded) {
     888                 :          1 :                         munmap(audit->map, audit->len);
     889                 :          1 :                 }
     890                 :          1 :                 free(audit);
     891                 :          1 :         }
     892                 :          1 : }
     893                 :            : 
     894                 :            : void
     895                 :          0 : pkg_audit_issues_free(struct pkg_audit_issues *issues)
     896                 :            : {
     897                 :            :         struct pkg_audit_issue *i, *issue;
     898                 :            : 
     899         [ #  # ]:          0 :         if (issues == NULL)
     900                 :          0 :                 return;
     901                 :            : 
     902   [ #  #  #  #  :          0 :         LL_FOREACH_SAFE(issues->issues, issue, i) {
                   #  # ]
     903   [ #  #  #  #  :          0 :                 LL_DELETE(issues->issues, issue);
          #  #  #  #  #  
                      # ]
     904                 :          0 :                 free(issue);
     905                 :          0 :         }
     906                 :          0 : }

Generated by: LCOV version 1.15