Skip to content

Commit 557ddee

Browse files
committed
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.
1 parent 727256c commit 557ddee

File tree

13 files changed

+188
-255
lines changed

13 files changed

+188
-255
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- name: Install Deps
3535
run: |
3636
sudo apt-get update
37-
sudo apt-get -y install lcov swig xsltproc rpm-common lua5.3 libpcre2-dev libyaml-dev libapt-pkg-dev libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt-dev libselinux1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libxslt1-dev libxml-parser-perl libxml-xpath-perl libperl-dev librpm-dev librtmp-dev libxmlsec1-dev libxmlsec1-openssl python3-dbusmock python3-pytest
37+
sudo apt-get -y install lcov swig xsltproc rpm-common lua5.3 libpcre2-dev libyaml-dev libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt-dev libselinux1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libxslt1-dev libxml-parser-perl libxml-xpath-perl libperl-dev librpm-dev librtmp-dev libxmlsec1-dev libxmlsec1-openssl python3-dbusmock python3-pytest
3838
sudo apt-get -y remove rpm
3939
4040
# Runs a set of commands using the runners shell
@@ -57,7 +57,7 @@ jobs:
5757
image: fedora:latest
5858
steps:
5959
- name: Install Deps
60-
run: dnf install -y cmake git dbus-devel GConf2-devel libacl-devel libblkid-devel libcap-devel libcurl-devel libgcrypt-devel libselinux-devel libxml2-devel libxslt-devel libattr-devel make openldap-devel pcre2-devel perl-XML-Parser perl-XML-XPath perl-devel python3-devel python3-dbusmock rpm-devel swig bzip2-devel gcc-c++ libyaml-devel xmlsec1-devel xmlsec1-openssl-devel hostname bzip2 lua rpm-build which strace apt-devel python3-pytest
60+
run: dnf install -y cmake git dbus-devel GConf2-devel libacl-devel libblkid-devel libcap-devel libcurl-devel libgcrypt-devel libselinux-devel libxml2-devel libxslt-devel libattr-devel make openldap-devel pcre2-devel perl-XML-Parser perl-XML-XPath perl-devel python3-devel python3-dbusmock rpm-devel swig bzip2-devel gcc-c++ libyaml-devel xmlsec1-devel xmlsec1-openssl-devel hostname bzip2 lua rpm-build which strace python3-pytest
6161
- name: Checkout
6262
uses: actions/checkout@v3
6363
with:

.github/workflows/codeql.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- name: Install Deps
3333
run: |
3434
sudo apt-get update
35-
sudo apt-get -y install lcov swig xsltproc rpm-common lua5.3 libyaml-dev libapt-pkg-dev libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt-dev libselinux1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libxslt1-dev libxml-parser-perl libxml-xpath-perl libperl-dev librpm-dev librtmp-dev libxmlsec1-dev libxmlsec1-openssl python3-dbusmock
35+
sudo apt-get -y install lcov swig xsltproc rpm-common lua5.3 libyaml-dev libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev libgcrypt-dev libselinux1-dev libgconf2-dev libacl1-dev libblkid-dev libcap-dev libxml2-dev libxslt1-dev libxml-parser-perl libxml-xpath-perl libperl-dev librpm-dev librtmp-dev libxmlsec1-dev libxmlsec1-openssl python3-dbusmock
3636
sudo apt-get -y remove rpm
3737
3838
# Initializes the CodeQL tools for scanning.

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ cmake_dependent_option(OPENSCAP_PROBE_UNIX_UNAME "Unix uname probe" ON "ENABLE_P
299299
cmake_dependent_option(OPENSCAP_PROBE_UNIX_XINETD "Unix xinetd probe" ON "ENABLE_PROBES_UNIX" OFF)
300300

301301
# LINUX PROBES
302-
cmake_dependent_option(OPENSCAP_PROBE_LINUX_DPKGINFO "Linux dpkginfo probe" ON "ENABLE_PROBES_LINUX; APTPKG_FOUND" OFF)
302+
cmake_dependent_option(OPENSCAP_PROBE_LINUX_DPKGINFO "Linux dpkginfo probe" ON "ENABLE_PROBES_LINUX" OFF)
303303
cmake_dependent_option(OPENSCAP_PROBE_LINUX_IFLISTENERS "Linux iflisteners probe" ON "ENABLE_PROBES_LINUX" OFF)
304304
cmake_dependent_option(OPENSCAP_PROBE_LINUX_INETLISTENINGSERVERS "Linux inetlisteningservers probe" ON "ENABLE_PROBES_LINUX" OFF)
305305
cmake_dependent_option(OPENSCAP_PROBE_LINUX_PARTITION "Linux partition probe" ON "ENABLE_PROBES_LINUX; BLKID_FOUND" OFF)
@@ -433,7 +433,7 @@ message(STATUS " Unix xinetd probe: ${OPENSCAP_PROBE_UNIX_XINETD}")
433433
message(STATUS " ")
434434

435435
message(STATUS "Linux probes: ${ENABLE_PROBES_LINUX}")
436-
message(STATUS " Linux dpkginfo probe (depends on aptpkg): ${OPENSCAP_PROBE_LINUX_DPKGINFO}")
436+
message(STATUS " Linux dpkginfo probe: ${OPENSCAP_PROBE_LINUX_DPKGINFO}")
437437
message(STATUS " Linux iflisteners probe: ${OPENSCAP_PROBE_LINUX_IFLISTENERS}")
438438
message(STATUS " Linux inetlisteningservers probe: ${OPENSCAP_PROBE_LINUX_INETLISTENINGSERVERS}")
439439
message(STATUS " Linux partition probe (depends on blkid): ${OPENSCAP_PROBE_LINUX_PARTITION}")

cmake/FindAptPkg.cmake

Lines changed: 0 additions & 30 deletions
This file was deleted.

docs/developer/developer.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ sudo dnf install \
6666
cmake dbus-devel GConf2-devel libacl-devel libblkid-devel libcap-devel libcurl-devel \
6767
libgcrypt-devel libselinux-devel libxml2-devel libxslt-devel libattr-devel make openldap-devel \
6868
pcre-devel perl-XML-Parser perl-XML-XPath perl-devel python3-devel python3-dbusmock rpm-devel swig \
69-
bzip2-devel gcc-c++ libyaml-devel xmlsec1-devel xmlsec1-openssl-devel apt-devel
69+
bzip2-devel gcc-c++ libyaml-devel xmlsec1-devel xmlsec1-openssl-devel
7070
----
7171

7272
On RHEL 8+ / CentOS 8+, the command to install the build dependencies is:
@@ -85,7 +85,7 @@ On Ubuntu 16.04, Debian 8 or Debian 9, the command to install the build dependen
8585
sudo apt-get install -y cmake libdbus-1-dev libdbus-glib-1-dev libcurl4-openssl-dev \
8686
libgcrypt20-dev libselinux1-dev libxslt1-dev libgconf2-dev libacl1-dev libblkid-dev \
8787
libcap-dev libxml2-dev libldap2-dev libpcre3-dev python-dev swig libxml-parser-perl \
88-
libxml-xpath-perl libperl-dev libbz2-dev librpm-dev g++ libapt-pkg-dev libyaml-dev \
88+
libxml-xpath-perl libperl-dev libbz2-dev librpm-dev g++ libyaml-dev \
8989
libxmlsec1-dev libxmlsec1-openssl
9090
----
9191

openscap.spec

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ BuildRequires: cmake >= 2.6
1313
BuildRequires: gcc
1414
BuildRequires: gcc-c++
1515
BuildRequires: swig libxml2-devel libxslt-devel perl-generators perl-XML-Parser
16-
%if 0%{?fedora}
17-
BuildRequires: apt-devel
18-
%endif
1916
BuildRequires: rpm-devel
2017
BuildRequires: libgcrypt-devel
2118
%if 0%{?fedora}
@@ -47,9 +44,6 @@ Requires: libacl
4744
Requires: libblkid
4845
Requires: libcap
4946
Requires: libselinux
50-
%if 0%{?fedora}
51-
Requires: apt-libs
52-
%endif
5347
Requires: openldap
5448
Requires: popt
5549
# Fedora has procps-ng, which provides procps

src/CMakeLists.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,6 @@ endif()
115115
if(DBUS_FOUND)
116116
target_link_libraries(openscap ${DBUS_LIBRARIES})
117117
endif()
118-
if(APTPKG_FOUND)
119-
target_link_libraries(openscap ${APTPKG_LIBRARIES})
120-
endif()
121118
if(ACL_FOUND)
122119
target_link_libraries(openscap ${ACL_LIBRARY})
123120
endif()

src/OVAL/probes/probe-table.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ static const probe_table_entry_t probe_table[] = {
257257
{OVAL_INDEPENDENT_YAML_FILE_CONTENT, NULL, yamlfilecontent_probe_main, NULL, yamlfilecontent_probe_offline_mode_supported},
258258
#endif
259259
#ifdef OPENSCAP_PROBE_LINUX_DPKGINFO
260-
{OVAL_LINUX_DPKG_INFO, dpkginfo_probe_init, dpkginfo_probe_main, dpkginfo_probe_fini, dpkginfo_probe_offline_mode_supported},
260+
{OVAL_LINUX_DPKG_INFO, NULL, dpkginfo_probe_main, NULL, dpkginfo_probe_offline_mode_supported},
261261
#endif
262262
#ifdef OPENSCAP_PROBE_LINUX_IFLISTENERS
263263
{OVAL_LINUX_IFLISTENERS, NULL, iflisteners_probe_main, NULL, NULL},

src/OVAL/probes/unix/linux/CMakeLists.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
if(OPENSCAP_PROBE_LINUX_DPKGINFO)
22
list(APPEND LINUX_PROBES_SOURCES
3-
"dpkginfo-helper.cxx"
3+
"dpkginfo-helper.c"
44
"dpkginfo-helper.h"
55
"dpkginfo_probe.c"
66
"dpkginfo_probe.h"
77
)
8-
list(APPEND LINUX_PROBES_INCLUDE_DIRECTORIES
9-
${APTPKG_INCLUDE_DIR}
10-
)
118
endif()
129

1310
if(OPENSCAP_PROBE_LINUX_IFLISTENERS)
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#ifdef HAVE_CONFIG_H
2+
#include <config.h>
3+
#endif
4+
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <ctype.h>
9+
#include <limits.h>
10+
11+
#include "debug_priv.h"
12+
#include "dpkginfo-helper.h"
13+
14+
#define DPKG_STATUS_BUFFER_SIZE 4096
15+
16+
static char* trimleft(char *str)
17+
{
18+
while (isspace((unsigned char)*str))
19+
str++;
20+
21+
if (*str == 0)
22+
return str;
23+
24+
return str;
25+
}
26+
27+
static int version(struct dpkginfo_reply_t *reply)
28+
{
29+
char *evr, *epoch, *version, *release;
30+
31+
if (reply->evr == NULL)
32+
return -1;
33+
34+
evr = strdup(reply->evr);
35+
if (evr == NULL)
36+
return -1;
37+
38+
if ((epoch = strchr(evr, ':')) != NULL) {
39+
*epoch++ = '\0';
40+
reply->epoch = strdup(evr);
41+
if (reply->epoch == NULL)
42+
goto err;
43+
} else {
44+
reply->epoch = strdup("0");
45+
if (reply->epoch == NULL)
46+
goto err;
47+
epoch = evr;
48+
}
49+
50+
version = epoch;
51+
if ((release = strchr(version, '-')) != NULL) {
52+
*release++ = '\0';
53+
reply->release = strdup(release);
54+
if (reply->release == NULL)
55+
goto err;
56+
}
57+
reply->version = strdup(version);
58+
if (reply->version == NULL)
59+
goto err;
60+
61+
free(evr);
62+
return 0;
63+
err:
64+
free(evr);
65+
return -1;
66+
}
67+
68+
struct dpkginfo_reply_t* dpkginfo_get_by_name(const char *name, int *err)
69+
{
70+
FILE *f;
71+
char buf[DPKG_STATUS_BUFFER_SIZE], path[PATH_MAX], *root, *key, *value;
72+
struct dpkginfo_reply_t *reply;
73+
74+
*err = 0;
75+
reply = NULL;
76+
77+
root = getenv("OSCAP_PROBE_ROOT");
78+
if (root != NULL)
79+
snprintf(path, PATH_MAX, "%s/var/lib/dpkg/status", root);
80+
else
81+
snprintf(path, PATH_MAX, "/var/lib/dpkg/status");
82+
83+
f = fopen(path, "r");
84+
if (f == NULL) {
85+
dW("%s not found.", path);
86+
*err = -1;
87+
return NULL;
88+
}
89+
90+
dD("Searching package \"%s\".", name);
91+
92+
while (fgets(buf, DPKG_STATUS_BUFFER_SIZE, f)) {
93+
if (buf[0] == '\n') {
94+
// New package entry.
95+
if (reply != NULL) {
96+
// Package found.
97+
goto out;
98+
}
99+
continue;
100+
}
101+
if (isspace(buf[0])) {
102+
// Ignore line beginning by a space.
103+
continue;
104+
}
105+
buf[strcspn(buf, "\n")] = 0;
106+
key = buf;
107+
value = strchr(buf, ':');
108+
if (value == NULL) {
109+
// Ignore truncated line.
110+
continue;
111+
}
112+
*value++ = '\0';
113+
value = trimleft(value);
114+
// Package should be the first line.
115+
if (strcmp(key, "Package") == 0) {
116+
if (strcmp(value, name) == 0) {
117+
if (reply != NULL)
118+
continue;
119+
reply = calloc(1, sizeof(*reply));
120+
if (reply == NULL)
121+
goto err;
122+
reply->name = strdup(value);
123+
if (reply->name == NULL)
124+
goto err;
125+
}
126+
} else if (reply != NULL) {
127+
if (strcmp(key, "Status") == 0) {
128+
if (strcmp(value, "install") != 0) {
129+
// Package deinstalled.
130+
dD("Package \"%s\" has been deinstalled.", name);
131+
dpkginfo_free_reply(reply);
132+
reply = NULL;
133+
continue;
134+
}
135+
} else if (strcmp(key, "Architecture") == 0) {
136+
reply->arch = strdup(value);
137+
if (reply->arch == NULL)
138+
goto err;
139+
} else if (strcmp(key, "Version") == 0) {
140+
reply->evr = strdup(value);
141+
if (reply->evr == NULL)
142+
goto err;
143+
if (version(reply) < 0)
144+
goto err;
145+
}
146+
}
147+
}
148+
149+
// Reached end of file.
150+
151+
out:
152+
if (reply != NULL) {
153+
// Package found.
154+
dD("Package \"%s\" found (arch=%s evr=%s epoch=%s version=%s release=%s).",
155+
name, reply->arch, reply->evr, reply->epoch, reply->version, reply->release);
156+
*err = 1;
157+
}
158+
fclose(f);
159+
return reply;
160+
err:
161+
dW("Insufficient memory available to allocate duplicate string.");
162+
fclose(f);
163+
dpkginfo_free_reply(reply);
164+
*err = -1;
165+
return NULL;
166+
}
167+
168+
void dpkginfo_free_reply(struct dpkginfo_reply_t *reply)
169+
{
170+
if (reply) {
171+
free(reply->name);
172+
free(reply->arch);
173+
free(reply->epoch);
174+
free(reply->release);
175+
free(reply->version);
176+
free(reply->evr);
177+
free(reply);
178+
}
179+
}

0 commit comments

Comments
 (0)