From owner-freebsd-ports-bugs@FreeBSD.ORG Tue Aug 26 12:10:02 2008 Return-Path: Delivered-To: freebsd-ports-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B1FDB1065686 for ; Tue, 26 Aug 2008 12:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 9FA3E8FC1C for ; Tue, 26 Aug 2008 12:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.2/8.14.2) with ESMTP id m7QCA2tW002867 for ; Tue, 26 Aug 2008 12:10:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.2/8.14.1/Submit) id m7QCA2B3002866; Tue, 26 Aug 2008 12:10:02 GMT (envelope-from gnats) Resent-Date: Tue, 26 Aug 2008 12:10:02 GMT Resent-Message-Id: <200808261210.m7QCA2B3002866@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-ports-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Eygene Ryabinkin Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 9A09D10656E6; Tue, 26 Aug 2008 12:03:23 +0000 (UTC) (envelope-from rea-fbsd@codelabs.ru) Received: from 0.mx.codelabs.ru (0.mx.codelabs.ru [144.206.177.45]) by mx1.freebsd.org (Postfix) with ESMTP id DE7DE8FC24; Tue, 26 Aug 2008 12:03:22 +0000 (UTC) (envelope-from rea-fbsd@codelabs.ru) Received: from phoenix.codelabs.ru (ppp91-78-251-88.pppoe.mtu-net.ru [91.78.251.88]) by 0.mx.codelabs.ru with esmtps (TLSv1:CAMELLIA256-SHA:256) id 1KXxGZ-0007Y7-DS; Tue, 26 Aug 2008 16:03:19 +0400 Message-Id: <20080826120320.35C3EF181E@phoenix.codelabs.ru> Date: Tue, 26 Aug 2008 16:03:20 +0400 (MSD) From: Eygene Ryabinkin To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: secteam@FreeBSD.org, flz@FreeBSD.org Subject: ports/126853: ports-mgmt/portaudit: speed up audit of installed packages X-BeenThere: freebsd-ports-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Eygene Ryabinkin List-Id: Ports bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Aug 2008 12:10:02 -0000 >Number: 126853 >Category: ports >Synopsis: ports-mgmt/portaudit: speed up audit of installed packages >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Aug 26 12:10:02 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Eygene Ryabinkin >Release: FreeBSD 7.0-STABLE i386 >Organization: Code Labs >Environment: System: FreeBSD XXX 7.0-STABLE FreeBSD 7.0-STABLE #1: Wed Aug 20 14:32:07 MSD 2008 root@XXX:/usr/obj/usr/src/sys/XXX i386 >Description: Currently on my machines portaudit(1) takes some seconds to perform the search for the vulnerable packages (system has >500 installed packages). The reason is that portaudit(1) uses awk and invokes pkg_info a number of times. I had mimicked the awk part of auditing of the installed packages in the new utility, pkg_audit. It is thought to be added to the pkg_install bundle. With this utility I achieved 15x speedup on my system. The modifications for the portaudit itself were rather small. The real reason why I care about two seconds of portaudit life is that I am running portaudit plugin for Nagios [1] and it sometimes time out in the innocent situations and seem to create visible load on the monitored server. I had not looked into the sequence of auditing the individual package at the port compilation time -- this is not yet showed as much problems as auditing of the whole list of installed packages. [1] ports/net-mgmt/nagios-portaudit >How-To-Repeat: Try 'time portaudit'. You'll surely get a real time of a second or more. Try my patches -- the real time should be dropped significantly. Tests for the sufficiently new machine (Core 2 E8200) show 1.5 seconds vs 0.1 seconds respectively. But for the dual-CPU P3 1GHz host I have 8.4/0.85 seconds. And this is not the slowest system that can run FreeBSD. >Fix: First two patches add the needed functionality to pkg_install bundle. I am not completely sure that the new match_* functions belong to lib/match.c, may be they deserve the separate file. --- 0001-Add-functions-for-traversing-package-database-and-ma.patch begins here -- >From ce2fbab57ffb6f91d0a13a07cc82ec5a97cb06ff Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Tue, 26 Aug 2008 14:59:29 +0400 This functions will help one who wants to search package database for the given package names or name globs and do something more than just collecting the names of the matched packages. They are skeleton-like functions and are supposed to be used as package database iterator and a handy match function: ----- session = match_begin(MATCH_STYLE); while (match_next_package(session)) { ... pkg_name = match_get_pkgname(session); ... match_matches(session, template); ... } match_end(session); ----- Signed-off-by: Eygene Ryabinkin --- lib/lib.h | 5 +++ lib/match.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 0 deletions(-) diff --git a/lib/lib.h b/lib/lib.h index 773278a..2890df6 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -228,6 +228,11 @@ char **matchbyorigin(const char *, int *); char ***matchallbyorigin(const char **, int *); int isinstalledpkg(const char *name); int pattern_match(match_t MatchType, char *pattern, const char *pkgname); +struct match_session *match_begin(match_t); +void match_end(struct match_session *); +Boolean match_next_package(struct match_session *); +int match_matches(struct match_session *, char *); +const char *match_get_pkgname(struct match_session *); /* Dependencies */ int sortdeps(char **); diff --git a/lib/match.c b/lib/match.c index 07c136b..01f09ee 100644 --- a/lib/match.c +++ b/lib/match.c @@ -37,6 +37,16 @@ struct store { char **store; }; +/* + * Structure that holds information about package traversal + * and matching session. + */ +struct match_session { + FTS *ftsp; + FTSENT *f; + match_t match_type;; +}; + static int rex_match(const char *, const char *, int); static int csh_match(const char *, const char *, int); struct store *storecreate(struct store *); @@ -416,6 +426,96 @@ errout: } /* + * Prepares package database for the traversal. + */ +struct match_session * +match_begin(match_t MatchType) +{ + struct match_session *sess; + const char *paths[2] = {LOG_DIR, NULL}; + + if (!isdir(paths[0])) + return NULL; + + sess = (struct match_session *)malloc(sizeof(*sess)); + if (sess == NULL) + return NULL; + bzero((void *)sess, sizeof(*sess)); + + sess->match_type = MatchType; + sess->ftsp = fts_open((char * const *)(uintptr_t)paths, + FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp); + if (sess->ftsp == NULL) { + free((void *)sess); + return NULL; + } + + return sess; +} + +/* + * Ends package traversal session. + */ +void +match_end(struct match_session *sess) +{ + if (sess == NULL) + return; + if (sess->ftsp != NULL) + fts_close(sess->ftsp); + free((void *)sess); + return; +} + +/* + * Proceeds to the next package in the session. + * Returns TRUE if package was selected, FALSE otherwise. + */ +Boolean +match_next_package(struct match_session *sess) +{ + if (sess == NULL || sess->ftsp == NULL) + return FALSE; + + while ((sess->f = fts_read(sess->ftsp)) != NULL) { + if (sess->f->fts_info == FTS_D && + sess->f->fts_level == 1) { + fts_set(sess->ftsp, sess->f, FTS_SKIP); + return TRUE; + } + } + return FALSE; +} + +/* + * Matches the current package name against the given pattern. + * Returns 1 if pattern matches, 0 if not matches and -1 for + * the error condition. + */ +int +match_matches(struct match_session *sess, char *pattern) +{ + if (sess == NULL || sess->ftsp == NULL || sess->f == NULL || + pattern == NULL) + return FALSE; + + return pattern_match(sess->match_type, pattern, + sess->f->fts_name); +} + +/* + * Returns name of the current package. + */ +const char * +match_get_pkgname(struct match_session *sess) +{ + if (sess == NULL || sess->ftsp == NULL || sess->f == NULL) + return NULL; + + return (const char *)(sess->f->fts_name); +} + +/* * Returns 1 if specified pkgname matches RE pattern. * Otherwise returns 0 if doesn't match or -1 if RE * engine reported an error (usually invalid syntax). -- 1.5.6.4 --- 0001-Add-functions-for-traversing-package-database-and-ma.patch ends here -- --- 0002-New-utility-pkg_audit.patch begins here --- >From 854bc5645c15ae9ae9d72a1e123c5c738d6f2d82 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Tue, 26 Aug 2008 15:08:46 +0400 Subject: [PATCH] New utility: pkg_audit It is mainly a helper for portupgrade to avoid awk scripting and numerous calls for pkg_info. This utility speeds up portaudit by a factor of 10 on a system with 521 installed ports and the auditfile that contains 3213 entries: ----- $ ls -d /var/db/pkg/* | wc -l 521 $ tar xOf /var/db/portaudit/auditfile.tbz auditfile | sed -e'/^#/d' | wc -l 3213 $ time ./portaudit Affected package: ruby-1.8.6.111_4,1 Type of problem: ruby -- DNS spoofing vulnerability. Reference: Affected package: ruby-1.8.6.111_4,1 Type of problem: ruby -- DoS vulnerability in WEBrick. Reference: Affected package: ruby-1.8.6.111_4,1 Type of problem: ruby -- multiple vulnerabilities in safe level. Reference: 3 problem(s) in your installed packages found. You are advised to update or deinstall the affected package(s) immediately. real 0m0.107s user 0m0.116s sys 0m0.012s $ time portaudit Affected package: ruby-1.8.6.111_4,1 Type of problem: ruby -- multiple vulnerabilities in safe level. Reference: Affected package: ruby-1.8.6.111_4,1 Type of problem: ruby -- DoS vulnerability in WEBrick. Reference: Affected package: ruby-1.8.6.111_4,1 Type of problem: ruby -- DNS spoofing vulnerability. Reference: 3 problem(s) in your installed packages found. You are advised to update or deinstall the affected package(s) immediately. real 0m1.583s user 0m0.560s sys 0m1.057s ----- Signed-off-by: Eygene Ryabinkin --- Makefile | 2 +- audit/Makefile | 14 +++ audit/audit.h | 43 +++++++++ audit/main.c | 162 +++++++++++++++++++++++++++++++++ audit/parse.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++ audit/pkg_audit.1 | 63 +++++++++++++ 6 files changed, 542 insertions(+), 1 deletions(-) create mode 100644 audit/Makefile create mode 100644 audit/audit.h create mode 100644 audit/main.c create mode 100644 audit/parse.c create mode 100644 audit/pkg_audit.1 diff --git a/Makefile b/Makefile index fefbd08..abc1e65 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ .include -SUBDIR= lib add create delete info updating version +SUBDIR= lib add create delete info updating version audit .include diff --git a/audit/Makefile b/audit/Makefile new file mode 100644 index 0000000..2ece5f8 --- /dev/null +++ b/audit/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +PROG= pkg_audit +SRCS= main.c parse.c + +CFLAGS+= -I${.CURDIR}/../lib + +WARNS?= 6 +WFORMAT?= 1 + +DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} +LDADD= ${LIBINSTALL} -lfetch -lmd + +.include diff --git a/audit/audit.h b/audit/audit.h new file mode 100644 index 0000000..1f0a369 --- /dev/null +++ b/audit/audit.h @@ -0,0 +1,43 @@ +/* + * + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Eygene Ryabinkin + * 26 August 2008 + * + * Parsing module for pkg_audit, header file. + * + */ + +#ifndef __AUDIT_H__ +#define __AUDIT_H__ + +#include + +SLIST_HEAD(audit_contents, audit_entry); + +struct audit_entry { + char *pkgglob; /* Package name glob */ + char *url; /* URL of advisory */ + char *descr; /* Description of vulnerability */ + size_t pfx_size; /* Metacharacter-less glob part size */ + SLIST_ENTRY(audit_entry) entries; +}; + + +/* Function prototypes */ +int +parse_auditfile(FILE *_fp, struct audit_contents *_head); + + +#endif /* defined(__AUDIT_H__) */ diff --git a/audit/main.c b/audit/main.c new file mode 100644 index 0000000..98d4869 --- /dev/null +++ b/audit/main.c @@ -0,0 +1,162 @@ +/* + * + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Eygene Ryabinkin + * 26 August 2008 + * + * This is the audit module -- fast helper for the portaudit script. + * + * It is filter-like utility: it reads the audit file from the + * standard input, intersects the vulnerable port list with the + * packages installed in the system and outputs the entries for + * the vulnerable ports that are present in the system to the + * standard output. + * + * The installed package can be listed multiple times, since it + * can be vulnerable to more than one bug at a time. But the + * whole output entries will be unique -- package name and + * vulnerability details should produce unique entry. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#ifdef PROFILING +#include +#endif + +#include +#include +#include +#include +#include + +#include "lib.h" +#include "audit.h" + +static inline void +audit_package(const char *_pkgname, struct audit_contents *_head, + struct match_session *_msess, FILE *_fp); + +int +main(int argc, char *argv[]) +{ + char freebsd[sizeof("FreeBSD-XXYYZZXXYYZZ")]; + unsigned long reldate; + size_t reldate_size = sizeof(reldate); + int mib[2]; + + FILE *in = stdin, *out = stdout; + struct match_session *msess; + struct audit_entry *item; +#ifdef PROFILING + struct timeval t1, t2; + double dt; +#endif + + /* Make compiler happy */ + if (argv[argc] == NULL) {}; + + struct audit_contents head = + SLIST_HEAD_INITIALIZER(head); + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELDATE; + if (sysctl(mib, 2, (void *)&reldate, &reldate_size, NULL, 0) != 0) + errx(1, "Unable to get kern.osreldate"); + snprintf(freebsd, sizeof(freebsd), "%s-%lu", "FreeBSD", reldate); + + SLIST_INIT(&head); +#ifdef PROFILING + gettimeofday(&t1, NULL); +#endif + if (parse_auditfile(in, &head) != 0) { + errx(1, "Failed to parse audit entries"); + } +#ifdef PROFILING + gettimeofday(&t2, NULL); + dt = t2.tv_sec - t1.tv_sec + 1e-6 * (t2.tv_usec - t1.tv_usec); + fprintf(stderr, "parse_auditfile(): %.6lf sec\n", dt); +#endif + + msess = match_begin(MATCH_GLOB); + if (msess == NULL) + return 1; + +#ifdef PROFILING + gettimeofday(&t1, NULL); +#endif + + /* Special check: FreeBSD itself */ + SLIST_FOREACH (item, &head, entries) { + if (strncmp(item->pkgglob, + "FreeBSD", sizeof("FreeBSD") - 1) == 0 && + pattern_match(MATCH_GLOB, item->pkgglob, freebsd)) { + fprintf(out, "%s|%s|%s\n", + freebsd, item->url, item->descr); + } + } + + /* Installed packages */ + while (match_next_package(msess)) + audit_package(match_get_pkgname(msess), &head, msess, out); + +#ifdef PROFILING + gettimeofday(&t2, NULL); + dt = t2.tv_sec - t1.tv_sec + 1e-6 * (t2.tv_usec - t1.tv_usec); + fprintf(stderr, "match loop: %.6lf sec\n", dt); +#endif + + match_end(msess); + + SLIST_FOREACH (item, &head, entries) { + free((void *)item->pkgglob); + free((void *)item); + } + + return 0; +} + +void +cleanup(int sig) +{ + sig = 0; + return; +} + +/* + * Loops over audit file contents and checks each entry in turn. + * + * The great speedup is to test the package prefix at the first + * place and only if it matches perform full match -- match_matches + * uses slow matching routines without precompilation and other + * tricks. For hundreds of installed ports and a couple of thousands + * audit entries this slows things down very well. + */ +static inline void +audit_package(const char *pkgname, struct audit_contents *head, + struct match_session *msess, FILE *fp) +{ + struct audit_entry *item; + + SLIST_FOREACH (item, head, entries) { + if (strncmp(pkgname, item->pkgglob, + item->pfx_size) == 0 && + match_matches(msess, item->pkgglob)) { + fprintf(fp, "%s|%s|%s\n", + pkgname, item->url, item->descr); + } + } +} diff --git a/audit/parse.c b/audit/parse.c new file mode 100644 index 0000000..fb33f7c --- /dev/null +++ b/audit/parse.c @@ -0,0 +1,259 @@ +/* + * + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Eygene Ryabinkin + * 26 August 2008 + * + * Parsing module for pkg_audit. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "lib.h" +#include "audit.h" + +/* Simple exponentially-growing buffer. */ + +struct dyn_buffer { + char *buf; + size_t size; +}; + +/* Prototypes */ +static int +parse_audit_entry(struct dyn_buffer *_b, struct audit_entry *_e); + +static int +read_line(FILE *_fp, struct dyn_buffer *_b); + +static struct dyn_buffer * +buf_init(size_t _size); +static void +buf_destroy(struct dyn_buffer *_b); +static int +buf_grow(struct dyn_buffer *_b); + +/* + * Parses audit file to the linked list of single entries. + * + * Return values: + * 0 -- file was successfully parsed; + * 1 -- parsing or read error occured; + * -1 -- bad arguments, memory allocation problems, etc. + */ +int +parse_auditfile(FILE *fp, struct audit_contents *head) +{ + struct audit_entry *e; + struct dyn_buffer *b; + int errcode; + + b = buf_init(256); + if (b == NULL) + return 1; + + while ((errcode = read_line(fp, b)) == 0) { + if (b->buf[0] == '#') + continue; + e = (struct audit_entry *)malloc(sizeof(*e)); + if (e == NULL) { + buf_destroy(b); + return -1; + } + bzero((void *)e, sizeof(*e)); + if ((errcode = parse_audit_entry(b, e)) != 0) { + buf_destroy(b); + return errcode; + } + SLIST_INSERT_HEAD(head, e, entries); + } + + buf_destroy(b); + + if (errcode != 1) + return 1; + else + return 0; +} + +/* + * Helpers for audit file parsing routine. + */ + +static struct dyn_buffer * +buf_init(size_t size) +{ + struct dyn_buffer *b; + + if (size <= 0) + return NULL; + + b = (struct dyn_buffer *)malloc(sizeof(*b)); + if (b == NULL) + return NULL; + + bzero((void *)b, sizeof(*b)); + b->size = size; + b->buf = (char *)malloc(b->size * sizeof(b->buf[0])); + if (b->buf == NULL) { + free((void *)b); + return NULL; + } + + bzero((void *)b->buf, b->size); + return b; +} + +static void +buf_destroy(struct dyn_buffer *b) +{ + if (b == NULL) + return; + + if (b->buf != NULL) + free((void *)b->buf); + free((void *)b); + return; +} + +static int +buf_grow(struct dyn_buffer *b) +{ + char *newbuf; + + if (b == NULL || b->buf == NULL || b->size <= 0) + return -1; + + newbuf = (char *)malloc(2 * b->size * sizeof(newbuf)); + if (newbuf == NULL) + return 1; + + bzero(newbuf, 2 * b->size); + bcopy((void *)b->buf, (void *)newbuf, b->size); + b->buf = newbuf; + b->size *= 2; + + return 0; +} + +/* + * fgets()-like function that reads the whole input line + * Returns 0 on the successful read, 1 for the end-of-file + * condition, -1 for any error. + * + * Terminating '\n' is removed from the line. + */ +static int +read_line(FILE *fp, struct dyn_buffer *b) +{ + size_t offset = 0, len = 0; + + if (fp == NULL || b == NULL) + return -1; + + if (feof(fp)) + return 1; + + /* We need at least two-character buffer */ + if (b->size == 1 && buf_grow(b) != 0) + return -1; + + b->buf[b->size - 1] = '\0'; + offset = 0; + while (fgets(b->buf + offset, b->size - offset, fp) != NULL) { + len = strlen(b->buf); + /* + * Read zero characters or buffer even shrinked? + * Strange, let's indicate error. + */ + if (len <= offset) + return -1; + if (b->buf[len - 1] == '\n') { + b->buf[len - 1] = '\0'; + return 0; + } + + offset = len; + if (buf_grow(b) != 0) + return -1; + + /* Should not happen, but who knows */ + if (offset >= b->size) + return -1; + } + + if (feof(fp)) { + /* + * If we read no characters, if means that we were + * at the EOF, but it was detected only by fgets(), + * not the first feof(). + */ + if (len == 0) + return 1; + else + return 0; + } else { + return -1; + } +} + +/* + * Parses single audit line and places it to the structure. + * Calculates length of the package name suffix that is free + * from metacharacters -- it is used for the quick matches + * against port name. + */ +static int +parse_audit_entry(struct dyn_buffer *b, struct audit_entry *e) +{ + size_t len; + char *string = NULL, *d1 = NULL, *d2 = NULL; + static const char globset[] = "{*?><=!"; + + /* + * At least 5 characters: + * two delimiters and three non-empty fields. + */ + len = strlen(b->buf); + if (len < 5) + return 1; + + /* Locate delimiters. */ + d1 = strchr(b->buf, '|'); + if (d1 == NULL) + return 1; + d2 = strchr(d1 + 1, '|'); + if (d2 == NULL) + return 1; + + string = (char *)malloc((len + 1) * sizeof(string[0])); + if (string == NULL) + return -1; + + bcopy((void *)b->buf, (void *)string, (len + 1) * sizeof(string[0])); + string[d1 - b->buf] = '\0'; + string[d2 - b->buf] = '\0'; + e->pkgglob = string; + e->url = string + (d1 - b->buf) + 1; + e->descr = string + (d2 - b->buf) + 1; + e->pfx_size = strcspn(e->pkgglob, globset); + + return 0; +} diff --git a/audit/pkg_audit.1 b/audit/pkg_audit.1 new file mode 100644 index 0000000..cd4abbc --- /dev/null +++ b/audit/pkg_audit.1 @@ -0,0 +1,63 @@ +.\" +.\" FreeBSD install - a package for the installation and maintenance +.\" of non-core utilities. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" Eygene Ryabinkin +.\" +.\" +.\" @(#)pkg_audit.1 +.\" $FreeBSD$ +.\" +.Dd Aug 26, 2008 +.Dt PKG_AUDIT 1 +.Os +.Sh NAME +.Nm pkg_audit +.Nd lists vulnerable ports installed in the system +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +The +.Nm +command is used to extract vulnerability information from the audit +file and list vulnerable packages that are present in the system. +It is main purpose to help +.Xr portaudit 1 +utility to avoid time-consuming scripting. +.Nm +reads vulnerability information from the standard input and writes +the list of vulnerable ports to the standard output. +Format of the output lines is the same as for the audit file, but +package matching globs are substituted with the actual package names. +.Sh TECHNICAL DETAILS +First the audit file is parsed to the internal representation +(currently it is linked list). +Then we are traversing installed packages database and trying to +match the package name against each audit entry. +The crucial step for the speeding up the process is to first +match the package prefix that has no CSH-like metacharacters +and perform full comparison only if match is found. +One more name is tested prior to the installed packages: it is +.Qo FreeBSD-`sysctl -n kern.osreldate` Qc , +the version of +.Fx +the current system is running. +.Sh SEE ALSO +.Xr portaudit 1 , +.Xr pkg_add 1 , +.Xr pkg_create 1 , +.Xr pkg_delete 1 , +.Xr pkg_version 1 . +.Sh AUTHORS +.An Eygene Ryabinkin Aq rea-fbsd@codelabs.ru +.Sh BUGS +Sure to be some. -- 1.5.6.4 --- 0002-New-utility-pkg_audit.patch ends here --- And the above patch teaches portaudit(1) to use the new utility if it is available. --- 0001-Modify-portaudit-to-make-use-of-pkg_audit-utility.patch begins here --- >From c982693afce2543b60b1937d13ae18ec2a2240d0 Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Tue, 26 Aug 2008 15:26:02 +0400 Subject: [PATCH] Modify portaudit to make use of pkg_audit utility Signed-off-by: Eygene Ryabinkin --- portaudit | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 42 insertions(+), 1 deletions(-) diff --git a/portaudit b/portaudit index ee1613e..6cf7039 100755 --- a/portaudit +++ b/portaudit @@ -173,6 +173,43 @@ audit_installed() return $rc } +audit_installed_pkgaudit () +{ + local rc=0 + local osversion=`sysctl -n kern.osreldate` + + fixedre=`echo -n $portaudit_fixed | tr -c '[:alnum:]- \t\n' 'x' | tr -s ' \t\n' '|'` + + extract_auditfile | pkg_audit | awk -F\| "$PRINTAFFECTED_AWK"' + BEGIN { vul=0; fixedre="'"$fixedre"'" } + $2 !~ /'"$opt_restrict"'/ { next } + $1 ~ /^FreeBSD[<=>!]/ { + if (fixedre && $2 ~ fixedre) next + print_affected("FreeBSD-'"$osversion"'", \ + "To disable this check add the uuid to \`portaudit_fixed'"'"' in /usr/local/etc/portaudit.conf") + next + } + { + vul++ + print_affected($0, "") + } + END { + if ("'$opt_quiet'" == "false") { + print vul " problem(s) in your installed packages found." + } + if (vul > 0) { + if ("'$opt_quiet'" == "false") { + print "\nYou are advised to update or deinstall" \ + " the affected package(s) immediately." + } + exit(1) + } + } + ' || rc=$? + + return $rc +} + audit_file() { local rc=0 @@ -461,7 +498,11 @@ fi if $opt_audit; then portaudit_prerequisites - audit_installed || ret=$? + if which pkg_audit > /dev/null 2>&1; then + audit_installed_pkgaudit || ret=$? + else + audit_installed || ret=$? + fi fi if $opt_auditcwd; then -- 1.5.6.4 --- 0001-Modify-portaudit-to-make-use-of-pkg_audit-utility.patch ends here --- >Release-Note: >Audit-Trail: >Unformatted: