Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/OVAL/probes/independent/filehash58_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ static int filehash58_cb(const char *prefix, const char *p, const char *f, const
if (prefix == NULL) {
fd = open(pbuf, O_RDONLY | O_NONBLOCK);
} else {
char *path_with_prefix = oscap_path_join(prefix, pbuf);
fd = open(path_with_prefix, O_RDONLY | O_NONBLOCK);
char *path_with_prefix = oscap_path_in_root(prefix, pbuf, true);
fd = path_with_prefix != NULL ? open(path_with_prefix, O_RDONLY | O_NONBLOCK) : -1;
free(path_with_prefix);
}

Expand Down
4 changes: 2 additions & 2 deletions src/OVAL/probes/independent/filehash_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ static int filehash_cb (const char *prefix, const char *p, const char *f, probe_
if (prefix == NULL) {
fd = open(pbuf, O_RDONLY | O_NONBLOCK);
} else {
char *path_with_prefix = oscap_path_join(prefix, pbuf);
fd = open(path_with_prefix, O_RDONLY | O_NONBLOCK);
char *path_with_prefix = oscap_path_in_root(prefix, pbuf, true);
fd = path_with_prefix != NULL ? open(path_with_prefix, O_RDONLY | O_NONBLOCK) : -1;
free(path_with_prefix);
}

Expand Down
4 changes: 2 additions & 2 deletions src/OVAL/probes/independent/textfilecontent54_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ static int process_file(const char *prefix, const char *path, const char *file,
if (probe_path_is_blocked(whole_path, blocked_paths)) {
goto cleanup;
}
whole_path_with_prefix = oscap_path_join(prefix, whole_path);
fd = open(whole_path_with_prefix, O_RDONLY | O_NONBLOCK);
whole_path_with_prefix = oscap_path_in_root(prefix, whole_path, true);
fd = whole_path_with_prefix != NULL ? open(whole_path_with_prefix, O_RDONLY | O_NONBLOCK) : -1;
if (fd == -1) {
if (errno == ENOENT || errno == EACCES || errno == ENOTDIR
|| errno == ENAMETOOLONG || errno == ELOOP)
Expand Down
4 changes: 2 additions & 2 deletions src/OVAL/probes/independent/textfilecontent_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
probe_ctx *ctx;
};

static int process_file(const char *prefix, const char *path, const char *filename, void *arg, oval_schema_version_t over, struct oscap_list *blocked_paths)

Check failure on line 141 in src/OVAL/probes/independent/textfilecontent_probe.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 26 to the 25 allowed.

See more on https://sonarcloud.io/project/issues?id=OpenSCAP_openscap&issues=AaGJaUrmHt5Rnm5PmnII&open=AaGJaUrmHt5Rnm5PmnII&pullRequest=2475
{
struct pfdata *pfd = (struct pfdata *) arg;
int ret = 0, path_len, filename_len, tmp_fd = -1;
Expand Down Expand Up @@ -175,8 +175,8 @@
if (probe_path_is_blocked(whole_path, blocked_paths)) {
goto cleanup;
}
whole_path_with_prefix = oscap_path_join(prefix, whole_path);
tmp_fd = open(whole_path_with_prefix, O_RDONLY | O_NONBLOCK);
whole_path_with_prefix = oscap_path_in_root(prefix, whole_path, true);
tmp_fd = whole_path_with_prefix != NULL ? open(whole_path_with_prefix, O_RDONLY | O_NONBLOCK) : -1;
if (tmp_fd == -1) {
if (errno != ENOENT && errno != EACCES && errno != ENOTDIR
&& errno != ENAMETOOLONG && errno != ELOOP)
Expand Down
4 changes: 2 additions & 2 deletions src/OVAL/probes/independent/xmlfilecontent_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ static int process_file(const char *prefix, const char *path, const char *filena
if (prefix == NULL) {
doc = xmlParseFile(whole_path);
} else {
char *path_with_prefix = oscap_path_join(prefix, whole_path);
doc = xmlParseFile(path_with_prefix);
char *path_with_prefix = oscap_path_in_root(prefix, whole_path, true);
doc = path_with_prefix != NULL ? xmlParseFile(path_with_prefix) : NULL;
free(path_with_prefix);
}

Expand Down
8 changes: 4 additions & 4 deletions src/OVAL/probes/independent/yamlfilecontent_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,14 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f
yaml_parser_t parser;
yaml_parser_initialize(&parser);

char *filepath_with_prefix = oscap_path_join(prefix, filepath);
char *filepath_with_prefix = oscap_path_in_root(prefix, filepath, true);
struct stat st;

tmp_fd = open(filepath_with_prefix, O_RDONLY | O_NONBLOCK);
tmp_fd = filepath_with_prefix != NULL ? open(filepath_with_prefix, O_RDONLY | O_NONBLOCK) : -1;
if (tmp_fd == -1) {
if (errno != ENOENT && errno != EACCES && errno != ENOTDIR
&& errno != ENAMETOOLONG && errno != ELOOP)
result_error("Unable to open file '%s': %s", filepath_with_prefix, strerror(errno));
result_error("Unable to open file '%s': %s", filepath, strerror(errno));
goto cleanup;
}
if (fstat(tmp_fd, &st) == -1
Expand All @@ -422,7 +422,7 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f
goto cleanup;
yaml_file = fdopen(tmp_fd, "r");
if (yaml_file == NULL) {
result_error("Unable to open file '%s': %s", filepath_with_prefix, strerror(errno));
result_error("Unable to open file '%s': %s", filepath, strerror(errno));
goto cleanup;
}
tmp_fd = -1;
Expand Down
20 changes: 20 additions & 0 deletions src/OVAL/probes/oval_fts.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,26 @@ static OVAL_FTSENT *OVAL_FTSENT_new(OVAL_FTS *ofts, FTSENT *fts_ent)
ofts_ent->file = NULL;
}

#if !defined(OS_WINDOWS)
/*
* fts follows a symbolic link from the real root, so a link whose
* target lies in the prefix alone looks dangling. Classify such an
* entry by its target in the prefix.
*/
if (ofts->prefix != NULL && fts_ent->fts_info == FTS_SLNONE) {
char *target = oscap_path_in_root(ofts->prefix, fts_ent->fts_path + shift, true);
struct stat st;

if (target != NULL && stat(target, &st) == 0) {
if (S_ISREG(st.st_mode))
ofts_ent->fts_info = FTS_F;
else if (S_ISDIR(st.st_mode))
ofts_ent->fts_info = FTS_D;
}
free(target);
}
#endif

#if defined(OSCAP_FTS_DEBUG)
dD("New OVAL_FTSENT: file: '%s', path: '%s'.", ofts_ent->file, ofts_ent->path);
#endif
Expand Down
6 changes: 5 additions & 1 deletion src/OVAL/probes/unix/file_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,11 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr,
return 0;
}

char *st_path_with_prefix = oscap_path_join(prefix, st_path);
char *st_path_with_prefix = oscap_path_in_root(prefix, st_path, false);
if (st_path_with_prefix == NULL) {
dD("Cannot resolve %s in the probe root: errno=%u, %s.", st_path, errno, strerror(errno));
return 0;
}
if (lstat(st_path_with_prefix, &st) == -1) {
dD("lstat failed when processing %s: errno=%u, %s.", st_path, errno, strerror (errno));
/*
Expand Down
5 changes: 4 additions & 1 deletion src/OVAL/probes/unix/fileextendedattribute_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,10 @@ static int file_cb(const char *prefix, const char *p, const char *f, void *ptr,
return 0;
}

char *st_path_with_prefix = oscap_path_join(prefix, st_path);
char *st_path_with_prefix = oscap_path_in_root(prefix, st_path, false);
if (st_path_with_prefix == NULL) {
goto exit;
}
do {
/* estimate the size of the buffer */
xattr_count = llistxattr(st_path_with_prefix, NULL, 0);
Expand Down
26 changes: 25 additions & 1 deletion src/OVAL/probes/unix/linux/partition_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,30 @@ int patition_probe_offline_mode_supported(void)
return PROBE_OFFLINE_OWN;
}

#if defined(OS_LINUX)
/*
* open_mounts opens the mount table at path. Under a probe root it opens
* the mounts of the init process of the root when the root has them, and
* puts their path in path: MTAB_PATH lists the mounts of the reading
* process, which for a probe in a container are those of the container.
*/
static int open_mounts(const char *prefix, char *path)
{
if (prefix != NULL) {
char init_path[PATH_MAX];
int fd;

snprintf(init_path, PATH_MAX, "%s/proc/1/mounts", prefix);
fd = open(init_path, O_RDONLY);
if (fd >= 0 || errno != ENOENT) {
snprintf(path, PATH_MAX, "%s", init_path);
return fd;
}
}
return open(path, O_RDONLY);
}
#endif

int partition_probe_main(probe_ctx *ctx, void *probe_arg)
{
int probe_ret = 0;
Expand All @@ -278,7 +302,7 @@ int partition_probe_main(probe_ctx *ctx, void *probe_arg)
int mnt_fd;
struct statfs stfs;

mnt_fd = open(mnt_path, O_RDONLY);
mnt_fd = open_mounts(prefix, mnt_path);

if (mnt_fd < 0) {
if (!prefix)
Expand Down
6 changes: 5 additions & 1 deletion src/OVAL/probes/unix/linux/selinuxsecuritycontext_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ static int selinuxsecuritycontext_file_cb(const char *prefix, const char *p, con

pbuf[plen+flen] = '\0';

char *path_with_prefix = oscap_path_join(prefix, pbuf);
char *path_with_prefix = oscap_path_in_root(prefix, pbuf, true);
if (path_with_prefix == NULL) {
dD("Cannot resolve %s in the probe root: errno=%d, %s.", pbuf, errno, strerror(errno));
return 0;
}
if (access(path_with_prefix, F_OK) == -1 ) {
dD("File does not exists anymore (could happen to /dev/fd/X)");
free(path_with_prefix);
Expand Down
91 changes: 89 additions & 2 deletions src/common/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
#include <stdlib.h>
#include <windows.h>
#else
#include <errno.h>
#include <libgen.h>
#include <strings.h>
#include <unistd.h>
#endif

#define PATH_SEPARATOR '/'
Expand Down Expand Up @@ -380,12 +382,97 @@ char *oscap_path_join(const char *path1, const char *path2)
}

#ifndef OS_WINDOWS
/* The limit of symbolic links in one resolution, as on Linux. */
#define MAX_SYMLINKS 40

char *oscap_path_in_root(const char *root, const char *path, bool follow)
{
char out[PATH_MAX], rest[PATH_MAX], full[PATH_MAX], target[PATH_MAX];
size_t rootlen, outlen = 0, len;
int links = 0;
char *p, *end;
bool last;

if (root == NULL)
return oscap_strdup(path);
rootlen = strlen(root);
while (rootlen > 0 && root[rootlen - 1] == PATH_SEPARATOR)
rootlen--;
if (snprintf(rest, sizeof(rest), "%s", path) >= (int)sizeof(rest))
goto toolong;
out[0] = '\0';
p = rest;
for (;;) {
while (*p == PATH_SEPARATOR)
p++;
if (*p == '\0')
break;
end = strchr(p, PATH_SEPARATOR);
len = end != NULL ? (size_t)(end - p) : strlen(p);
end = p + len;
last = end[strspn(end, "/")] == '\0';
if (len == 1 && p[0] == '.') {
p = end;
continue;
}
if (len == 2 && p[0] == '.' && p[1] == '.') {
while (outlen > 0 && out[outlen - 1] != PATH_SEPARATOR)
outlen--;
if (outlen > 0)
outlen--;
out[outlen] = '\0';
p = end;
continue;
}
if (outlen + 1 + len >= sizeof(out))
goto toolong;
out[outlen] = PATH_SEPARATOR;
memcpy(out + outlen + 1, p, len);
out[outlen + 1 + len] = '\0';
if (last && !follow && *end == '\0') {
outlen += 1 + len;
break;
}
if (snprintf(full, sizeof(full), "%.*s%s", (int)rootlen, root, out) >= (int)sizeof(full))
goto toolong;
/* readlink fails with EINVAL for a file that is not a link */
ssize_t n = readlink(full, target, sizeof(target) - 1);
if (n >= 0 && ++links > MAX_SYMLINKS) {
errno = ELOOP;
return NULL;
}
if (n < 0) {
/* Not a symbolic link, or one that cannot be read:
keep the component as it is. */
outlen += 1 + len;
p = end;
continue;
}
target[n] = '\0';
/* The target replaces the component, relative to the
directory resolved so far, or to root when absolute. */
if (target[0] == PATH_SEPARATOR)
outlen = 0;
out[outlen] = '\0';
if (strlen(target) + strlen(end) >= sizeof(rest))
goto toolong;
memmove(rest + strlen(target), end, strlen(end) + 1);
memcpy(rest, target, strlen(target));
p = rest;
}
return oscap_sprintf("%.*s%s", (int)rootlen, root, outlen > 0 ? out : "/");

toolong:
errno = ENAMETOOLONG;
return NULL;
}

FILE *oscap_fopen_with_prefix(const char *prefix, const char *path)
{
FILE *fp;
if (prefix != NULL) {
char *path_with_prefix = oscap_sprintf("%s%s", prefix, path);
fp = fopen(path_with_prefix, "r");
char *path_with_prefix = oscap_path_in_root(prefix, path, true);
fp = path_with_prefix != NULL ? fopen(path_with_prefix, "r") : NULL;
free(path_with_prefix);
} else {
fp = fopen(path, "r");
Expand Down
18 changes: 18 additions & 0 deletions src/common/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,24 @@ char *oscap_generate_random_string(size_t len, char *charset);
*/
char *oscap_path_join(const char *path1, const char *path2);

#ifndef OS_WINDOWS
/**
* Find the file that a path names when another directory is the root.
* Symbolic links resolve inside root, an absolute target from root
* itself, and ".." stops at root. A component that does not exist or
* is not a symbolic link is kept as it is.
* Caller is responsible for freeing the returned pointer.
* @param root the root directory, or NULL for the real root
* @param path an absolute path in root
* @param follow whether a symbolic link in the last component resolves
* too, as for stat(2), or stays, as for lstat(2), which also resolves it
* when the path ends in a slash
* @return the path of the file from the real root, or NULL with errno
* set to ELOOP or ENAMETOOLONG
*/
char *oscap_path_in_root(const char *root, const char *path, bool follow);
#endif

/// In a list of key-value pairs (odd indicies are keys, even values), find a value for given key
const char *oscap_strlist_find_value(char ** const kvalues, const char *key);
/// Right trim @a ch characters (modifies its first argument!)
Expand Down
32 changes: 14 additions & 18 deletions tests/probes/system_info/test_probes_system_info_offline_mode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@
set -e -o pipefail

function test_offline_mode_system_info_offline {
# This test is dependent on /etc/os-release being present, so skip this test if it doesn't exist.
[ -f "/etc/os-release" ] || return 255
os_name="Offline Linux"
os_version="1.0 (Offline)"
host_name="offline.example.com"

# A root of its own, as a probe root is: its /etc/os-release links to
# /usr/lib/os-release, as on most systems, and the link resolves in the
# root.
temp_dir="$(mktemp -d)"

ln -s /etc $temp_dir
mkdir -p "$temp_dir/etc" "$temp_dir/usr/lib"
printf 'NAME="%s"\nVERSION="%s"\n' "$os_name" "$os_version" > "$temp_dir/usr/lib/os-release"
ln -s /usr/lib/os-release "$temp_dir/etc/os-release"
echo "$host_name" > "$temp_dir/etc/hostname"
echo "hostname=\"$host_name\"" > "$temp_dir/etc/rc.conf"

result="$(mktemp)"

Expand All @@ -30,22 +37,11 @@ function test_offline_mode_system_info_offline {

[ -s "$result" ]

. /etc/os-release

case $(uname) in
FreeBSD)
HOSTNAME=`grep hostname= /etc/rc.conf | cut -d '"' -f 2`
;;
*)
HOSTNAME=`cat /etc/hostname`
;;
esac

assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_info'
assert_exists 1 "/oval_results/results/system/oval_system_characteristics/system_info/os_name[text()=\"${NAME}\"]"
assert_exists 1 "/oval_results/results/system/oval_system_characteristics/system_info/os_version[text()=\"${VERSION}\"]"
assert_exists 1 "/oval_results/results/system/oval_system_characteristics/system_info/os_name[text()=\"${os_name}\"]"
assert_exists 1 "/oval_results/results/system/oval_system_characteristics/system_info/os_version[text()=\"${os_version}\"]"
assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_info/architecture[text()="Unknown"]'
assert_exists 1 "/oval_results/results/system/oval_system_characteristics/system_info/primary_host_name[text()=\"${HOSTNAME}\"]"
assert_exists 1 "/oval_results/results/system/oval_system_characteristics/system_info/primary_host_name[text()=\"${host_name}\"]"

assert_exists 1 '/oval_results/results/system/oval_system_characteristics/system_info/interfaces'
# Getting network interfaces information from the guest is not implemented,
Expand Down
1 change: 1 addition & 0 deletions tests/probes/textfilecontent54/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ if(ENABLE_PROBES_INDEPENDENT)
add_oscap_test("test_behavior_multiline.sh" LABELS independent)
add_oscap_test("test_filecontent_non_utf.sh" LABELS independent)
add_oscap_test("test_offline_mode_textfilecontent54.sh" LABELS independent)
add_oscap_test("test_offline_mode_textfilecontent54_symlink.sh" LABELS independent)
add_oscap_test("test_probes_textfilecontent54.sh" LABELS independent)
add_oscap_test("test_recursion_limit.sh" LABELS independent)
add_oscap_test("test_symlinks.sh" LABELS independent)
Expand Down
Loading
Loading