Skip to content

Commit

Permalink
Add -r flag to pkg-audit.
Browse files Browse the repository at this point in the history
Add -r (--recursive) flag to pkg-audit that makes pkg-audit to print all
reverse dependencies of vulnerable packages. This allows users to
upgrade or reinstall potentially vulnerable packages.
  • Loading branch information
vstakhov committed Jul 12, 2014
1 parent d0a69a5 commit e956ff1
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 12 deletions.
9 changes: 6 additions & 3 deletions docs/pkg-audit.8
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@
.\" @(#)pkg.8
.\" $FreeBSD$
.\"
.Dd May 25, 2014
.Dd July 12, 2014
.Dt PKG-AUDIT 8
.Os
.Sh NAME
.Nm "pkg audit"
.Nd Audits installed packages against known vulnerabilities.
.Sh SYNOPSIS
.Nm
.Op Fl Fq
.Op Fl Fqr
.Op Fl f Ar filename
.Ar pkg-name
.Pp
.Nm
.Op Cm --{fetch,quiet}
.Op Cm --{fetch,quiet,recursive}
.Op Cm --file Ar filename
.Ar pkg-name
.Sh DESCRIPTION
Expand Down Expand Up @@ -75,6 +75,9 @@ Fetch the database before checking.
Be ``quiet''.
Prints only the requested information without
displaying many hints.
.It Fl r , Cm --recursive
Prints packages that depend on vulnerable packages and are thus
potentially vulnerable as well.
.El
.Sh ENVIRONMENT
The following environment variables affect the execution of
Expand Down
82 changes: 73 additions & 9 deletions src/audit.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2011-2012 Julien Laffaye <[email protected]>
* Copyright (c) 2014 Matthew Seaman <[email protected]>
* Copyright (c) 2014 Vsevolod Stakhov <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -43,35 +44,72 @@
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#include <utlist.h>
#include <uthash.h>

#include <pkg.h>
#include "pkgcli.h"

void
usage_audit(void)
{
fprintf(stderr, "Usage: pkg audit [-Fq] <pattern>\n\n");
fprintf(stderr, "Usage: pkg audit [-Fqr] [-f file] <pattern>\n\n");
fprintf(stderr, "For more information see 'pkg help audit'.\n");
}

struct pkg_check_entry {
struct pkg *pkg;
struct pkg_check_entry *next;
UT_hash_handle hh;
UT_hash_handle hs;
};

static void
add_to_check(struct pkg_check_entry **head, struct pkg *pkg)
{
struct pkg_check_entry *e;
const char *uid;

e = malloc(sizeof(*e));
if (e == NULL) {
warnx("malloc failed for pkg_check_entry");
exit(EXIT_FAILURE);
}
e->pkg = pkg;
LL_PREPEND(*head, e);
pkg_get(pkg, PKG_UNIQUEID, &uid);

HASH_ADD_KEYPTR(hh, *head, uid, strlen(uid), e);
}

static void
print_recursive_rdeps(struct pkg_check_entry *head, struct pkg *p,
struct sbuf *sb, struct pkg_check_entry **seen, bool top)
{
struct pkg_dep *dep = NULL;
static char uidbuf[1024];
struct pkg_check_entry *r;

while(pkg_rdeps(p, &dep) == EPKG_OK) {
const char *name = pkg_dep_get(dep, PKG_DEP_NAME);

HASH_FIND(hs, *seen, name, strlen(name), r);

if (r == NULL) {
snprintf(uidbuf, sizeof(uidbuf), "%s~%s",
name, pkg_dep_get(dep, PKG_DEP_ORIGIN));
HASH_FIND(hh, head, uidbuf, strlen(uidbuf), r);

if (r != NULL) {
HASH_ADD_KEYPTR(hs, *seen, name, strlen(name), r);
if (!top)
sbuf_cat(sb, ", ");

sbuf_cat(sb, name);

print_recursive_rdeps(head, r->pkg, sb, seen, false);

top = false;
}
}
}
}

int
Expand All @@ -87,24 +125,25 @@ exec_audit(int argc, char **argv)
char audit_file_buf[MAXPATHLEN];
char *audit_file = audit_file_buf;
unsigned int vuln = 0;
bool fetch = false;
bool fetch = false, recursive = false;
int ch;
int ret = EX_OK;
const char *portaudit_site = NULL;
struct sbuf *sb;
struct pkg_check_entry *check = NULL, *cur;
struct pkg_check_entry *check = NULL, *cur, *tmp;

db_dir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
snprintf(audit_file_buf, sizeof(audit_file_buf), "%s/vuln.xml", db_dir);

struct option longopts[] = {
{ "fetch", no_argument, NULL, 'F' },
{ "file", required_argument, NULL, 'f' },
{ "recursive", no_argument, NULL, 'r' },
{ "quiet", no_argument, NULL, 'q' },
{ NULL, 0, NULL, 0 },
};

while ((ch = getopt_long(argc, argv, "Ff:q", longopts, NULL)) != -1) {
while ((ch = getopt_long(argc, argv, "Ff:qr", longopts, NULL)) != -1) {
switch (ch) {
case 'F':
fetch = true;
Expand All @@ -115,6 +154,9 @@ exec_audit(int argc, char **argv)
case 'q':
quiet = true;
break;
case 'r':
recursive = true;
break;
default:
usage_audit();
return(EX_USAGE);
Expand Down Expand Up @@ -195,7 +237,8 @@ exec_audit(int argc, char **argv)
ret = EX_IOERR;
}
else {
while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC)) == EPKG_OK) {
while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_RDEPS))
== EPKG_OK) {
add_to_check(&check, pkg);
pkg = NULL;
}
Expand All @@ -220,10 +263,25 @@ exec_audit(int argc, char **argv)
#endif

if (pkg_audit_process(audit) == EPKG_OK) {
LL_FOREACH(check, cur) {
HASH_ITER(hh, check, cur, tmp) {
if (pkg_audit_is_vulnerable(audit, cur->pkg, quiet, &sb)) {
vuln ++;
printf("%s", sbuf_data(sb));

if (recursive) {
const char *name;
struct pkg_check_entry *seen = NULL, *scur, *stmp;

pkg_get(cur->pkg, PKG_NAME, &name);
sbuf_printf(sb, "Packages that depend on %s: ", name);
print_recursive_rdeps(check, cur->pkg, sb, &seen, true);
sbuf_finish(sb);
printf("%s\n", sbuf_data(sb));

HASH_ITER(hs, seen, scur, stmp) {
HASH_DELETE(hs, seen, scur);
}
}
sbuf_delete(sb);
}
}
Expand All @@ -233,6 +291,12 @@ exec_audit(int argc, char **argv)

if (!quiet)
printf("%u problem(s) in the installed packages found.\n", vuln);

HASH_ITER(hh, check, cur, tmp) {
HASH_DELETE(hh, check, cur);
pkg_free(cur->pkg);
free(cur);
}
}
else {
warnx("cannot process vulnxml");
Expand Down

0 comments on commit e956ff1

Please sign in to comment.