-
Notifications
You must be signed in to change notification settings - Fork 378
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite dpkginfo probe without using APT
This change rewrites the dpkginfo probe without using the APT library. The dpkginfo now parses the list of installed package (/var/lib/dpkg/status) directly, instead of relying on the APT library. This prevents loading the full list of packages in memory and various issues related to the use of the APT library. The dpkginfo probe is now stateless and doesn't require init and fini functions. Also, the dpkginfo_get_by_name function can now be called from multiple threads without having to be protected by a lock. The dependency on the APT library has been removed from OpenSCAP.
- Loading branch information
Showing
13 changed files
with
188 additions
and
255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
#ifdef HAVE_CONFIG_H | ||
#include <config.h> | ||
#endif | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <ctype.h> | ||
#include <limits.h> | ||
|
||
#include "debug_priv.h" | ||
#include "dpkginfo-helper.h" | ||
|
||
#define DPKG_STATUS_BUFFER_SIZE 4096 | ||
|
||
static char* trimleft(char *str) | ||
{ | ||
while (isspace((unsigned char)*str)) | ||
str++; | ||
|
||
if (*str == 0) | ||
return str; | ||
|
||
return str; | ||
} | ||
|
||
static int version(struct dpkginfo_reply_t *reply) | ||
{ | ||
char *evr, *epoch, *version, *release; | ||
|
||
if (reply->evr == NULL) | ||
return -1; | ||
|
||
evr = strdup(reply->evr); | ||
if (evr == NULL) | ||
return -1; | ||
|
||
if ((epoch = strchr(evr, ':')) != NULL) { | ||
*epoch++ = '\0'; | ||
reply->epoch = strdup(evr); | ||
if (reply->epoch == NULL) | ||
goto err; | ||
} else { | ||
reply->epoch = strdup("0"); | ||
if (reply->epoch == NULL) | ||
goto err; | ||
epoch = evr; | ||
} | ||
|
||
version = epoch; | ||
if ((release = strchr(version, '-')) != NULL) { | ||
*release++ = '\0'; | ||
reply->release = strdup(release); | ||
if (reply->release == NULL) | ||
goto err; | ||
} | ||
reply->version = strdup(version); | ||
if (reply->version == NULL) | ||
goto err; | ||
|
||
free(evr); | ||
return 0; | ||
err: | ||
free(evr); | ||
return -1; | ||
} | ||
|
||
struct dpkginfo_reply_t* dpkginfo_get_by_name(const char *name, int *err) | ||
{ | ||
FILE *f; | ||
char buf[DPKG_STATUS_BUFFER_SIZE], path[PATH_MAX], *root, *key, *value; | ||
struct dpkginfo_reply_t *reply; | ||
|
||
*err = 0; | ||
reply = NULL; | ||
|
||
root = getenv("OSCAP_PROBE_ROOT"); | ||
if (root != NULL) | ||
snprintf(path, PATH_MAX, "%s/var/lib/dpkg/status", root); | ||
else | ||
snprintf(path, PATH_MAX, "/var/lib/dpkg/status"); | ||
|
||
f = fopen(path, "r"); | ||
Check failure Code scanning / CodeQL Uncontrolled data used in path expression High
This argument to a file access function is derived from
user input (an environment variable) Error loading related location Loading This argument to a file access function is derived from user input (an environment variable) Error loading related location Loading |
||
if (f == NULL) { | ||
dW("%s not found.", path); | ||
*err = -1; | ||
return NULL; | ||
} | ||
|
||
dD("Searching package \"%s\".", name); | ||
|
||
while (fgets(buf, DPKG_STATUS_BUFFER_SIZE, f)) { | ||
if (buf[0] == '\n') { | ||
// New package entry. | ||
if (reply != NULL) { | ||
// Package found. | ||
goto out; | ||
} | ||
continue; | ||
} | ||
if (isspace(buf[0])) { | ||
// Ignore line beginning by a space. | ||
continue; | ||
} | ||
buf[strcspn(buf, "\n")] = 0; | ||
key = buf; | ||
value = strchr(buf, ':'); | ||
if (value == NULL) { | ||
// Ignore truncated line. | ||
continue; | ||
} | ||
*value++ = '\0'; | ||
value = trimleft(value); | ||
// Package should be the first line. | ||
if (strcmp(key, "Package") == 0) { | ||
if (strcmp(value, name) == 0) { | ||
if (reply != NULL) | ||
continue; | ||
reply = calloc(1, sizeof(*reply)); | ||
if (reply == NULL) | ||
goto err; | ||
reply->name = strdup(value); | ||
if (reply->name == NULL) | ||
goto err; | ||
} | ||
} else if (reply != NULL) { | ||
if (strcmp(key, "Status") == 0) { | ||
if (strcmp(value, "install") != 0) { | ||
// Package deinstalled. | ||
dD("Package \"%s\" has been deinstalled.", name); | ||
dpkginfo_free_reply(reply); | ||
reply = NULL; | ||
continue; | ||
} | ||
} else if (strcmp(key, "Architecture") == 0) { | ||
reply->arch = strdup(value); | ||
if (reply->arch == NULL) | ||
goto err; | ||
} else if (strcmp(key, "Version") == 0) { | ||
reply->evr = strdup(value); | ||
if (reply->evr == NULL) | ||
goto err; | ||
if (version(reply) < 0) | ||
goto err; | ||
} | ||
} | ||
} | ||
|
||
// Reached end of file. | ||
|
||
out: | ||
if (reply != NULL) { | ||
// Package found. | ||
dD("Package \"%s\" found (arch=%s evr=%s epoch=%s version=%s release=%s).", | ||
name, reply->arch, reply->evr, reply->epoch, reply->version, reply->release); | ||
*err = 1; | ||
} | ||
fclose(f); | ||
return reply; | ||
err: | ||
dW("Insufficient memory available to allocate duplicate string."); | ||
fclose(f); | ||
dpkginfo_free_reply(reply); | ||
*err = -1; | ||
return NULL; | ||
} | ||
|
||
void dpkginfo_free_reply(struct dpkginfo_reply_t *reply) | ||
{ | ||
if (reply) { | ||
free(reply->name); | ||
free(reply->arch); | ||
free(reply->epoch); | ||
free(reply->release); | ||
free(reply->version); | ||
free(reply->evr); | ||
free(reply); | ||
} | ||
} |
Oops, something went wrong.