Skip to content

Commit 3972b2a

Browse files
committed
Detect YAML types
We will detect booleans, floats and integers using YAML 1.2 Core Schema (https://yaml.org/spec/1.2/spec.html#id2804923) and we will treat every other scalar as string.
1 parent 7dc6684 commit 3972b2a

File tree

5 files changed

+588
-6
lines changed

5 files changed

+588
-6
lines changed

src/OVAL/probes/independent/yamlfilecontent_probe.c

Lines changed: 111 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#include <config.h>
2525
#endif
2626

27+
#include <math.h>
2728
#include <errno.h>
29+
#include <pcre.h>
2830
#include <yaml.h>
2931
#include <yaml-path.h>
3032

@@ -35,11 +37,107 @@
3537
#include "list.h"
3638
#include "probe/probe.h"
3739

40+
#define OSCAP_YAML_STRING_TAG "tag:yaml.org,2002:str"
41+
#define OSCAP_YAML_BOOL_TAG "tag:yaml.org,2002:bool"
42+
#define OSCAP_YAML_FLOAT_TAG "tag:yaml.org,2002:float"
43+
#define OSCAP_YAML_INT_TAG "tag:yaml.org,2002:int"
44+
45+
#define OVECCOUNT 30 /* should be a multiple of 3 */
46+
3847
int yamlfilecontent_probe_offline_mode_supported()
3948
{
4049
return PROBE_OFFLINE_OWN;
4150
}
4251

52+
static bool match_regex(const char *pattern, const char *value)
53+
{
54+
const char *errptr;
55+
int erroroffset;
56+
pcre *re = pcre_compile(pattern, 0, &errptr, &erroroffset, NULL);
57+
if (re == NULL) {
58+
dE("pcre_compile failed on pattern '%s': %s at %d", pattern,
59+
errptr, erroroffset);
60+
return false;
61+
}
62+
int ovector[OVECCOUNT];
63+
int rc = pcre_exec(re, NULL, value, strlen(value), 0, 0, ovector, OVECCOUNT);
64+
if (rc > 0) {
65+
return true;
66+
}
67+
return false;
68+
}
69+
70+
static SEXP_t *yaml_scalar_event_to_sexp(yaml_event_t event)
71+
{
72+
char *tag = (char *) event.data.scalar.tag;
73+
char *value = (char *) event.data.scalar.value;
74+
75+
/* nodes lacking an explicit tag are given a non-specific tag:
76+
* “!” for non-plain scalars, and “?” for all other nodes
77+
*/
78+
if (tag == NULL) {
79+
if (event.data.scalar.style != YAML_PLAIN_SCALAR_STYLE) {
80+
tag = "!";
81+
} else {
82+
tag = "?";
83+
}
84+
}
85+
86+
/* Nodes with "!" tag can be sequences, maps or strings, but we process
87+
* only scalars in this functions, so they can only be strings. */
88+
if (!strcmp(tag, "!")) {
89+
tag = OSCAP_YAML_STRING_TAG;
90+
}
91+
92+
bool question = !strcmp(tag, "?");
93+
94+
/* Regular expressions based on https://yaml.org/spec/1.2/spec.html#id2804923 */
95+
96+
if (question || !strcmp(tag, OSCAP_YAML_BOOL_TAG)) {
97+
if (match_regex("^true|True|TRUE$", value)) {
98+
return SEXP_number_newb(true);
99+
} else if (match_regex("^false|False|FALSE$", value)) {
100+
return SEXP_number_newb(false);
101+
} else if (!question) {
102+
return NULL;
103+
}
104+
}
105+
if (question || !strcmp(tag, OSCAP_YAML_INT_TAG)) {
106+
if (match_regex("^[+-]?[0-9]+$", value)) {
107+
int int_value = strtol(value, NULL, 10);
108+
return SEXP_number_newi(int_value);
109+
} else if (match_regex("^0o[0-7]+$", value)) {
110+
/* strtol doesn't understand 0o as octal prefix, it wants 0 */
111+
int int_value = strtol(value + 2, NULL, 8);
112+
return SEXP_number_newi(int_value);
113+
} else if (match_regex("^0x[0-9a-fA-F]+$", value)) {
114+
int int_value = strtol(value, NULL, 16);
115+
return SEXP_number_newi(int_value);
116+
} else if (!question) {
117+
return NULL;
118+
}
119+
}
120+
if (question || !strcmp(tag, OSCAP_YAML_FLOAT_TAG)) {
121+
if (match_regex("^[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?$", value)) {
122+
double double_value = strtod(value, NULL);
123+
return SEXP_number_newf(double_value);
124+
} else if (match_regex("^[-+]?(\\.inf|\\.Inf|\\.INF)$", value)) {
125+
double double_value = INFINITY;
126+
if (value[0] == '-') {
127+
double_value = -INFINITY;
128+
}
129+
return SEXP_number_newf(double_value);
130+
} else if (match_regex("^\\.nan|\\.NaN|\\.NAN$", value)) {
131+
double double_value = NAN;
132+
return SEXP_number_newf(double_value);
133+
} else if (!question) {
134+
return NULL;
135+
}
136+
}
137+
138+
return SEXP_string_new(value, strlen(value));
139+
}
140+
43141
static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, struct oscap_list *values, probe_ctx *ctx)
44142
{
45143
int ret = 0;
@@ -118,7 +216,17 @@ static int yaml_path_query(const char *filepath, const char *yaml_path_cstr, str
118216
}
119217
}
120218
if (event.type == YAML_SCALAR_EVENT) {
121-
oscap_list_add(values, (void *) strdup((const char *) event.data.scalar.value));
219+
SEXP_t *sexp = yaml_scalar_event_to_sexp(event);
220+
if (sexp == NULL) {
221+
SEXP_t *msg = probe_msg_creatf(OVAL_MESSAGE_LEVEL_ERROR,
222+
"Can't convert '%s' to SEXP", event.data.scalar.tag);
223+
probe_cobj_add_msg(probe_ctx_getresult(ctx), msg);
224+
SEXP_free(msg);
225+
probe_cobj_set_flag(probe_ctx_getresult(ctx), SYSCHAR_FLAG_ERROR);
226+
ret = -1;
227+
goto cleanup;
228+
}
229+
oscap_list_add(values, sexp);
122230
}
123231
} while (event.type != YAML_STREAM_END_EVENT);
124232

@@ -157,18 +265,15 @@ static int process_yaml_file(const char *prefix, const char *path, const char *f
157265
NULL
158266
);
159267
while (oscap_iterator_has_more(values_it)) {
160-
char *value = oscap_iterator_next(values_it);
161-
/* TODO: type conversion of 'value' data */
162-
SEXP_t *value_sexp = SEXP_string_new(value, strlen(value));
268+
SEXP_t *value_sexp = oscap_iterator_next(values_it);
163269
probe_item_ent_add(item, "value_of", NULL, value_sexp);
164-
SEXP_free(value_sexp);
165270
}
166271
probe_item_collect(ctx, item);
167272
}
168273
oscap_iterator_free(values_it);
169274

170275
cleanup:
171-
oscap_list_free(values, free);
276+
oscap_list_free(values, (oscap_destruct_func) SEXP_free);
172277
free(filepath_with_prefix);
173278
free(filepath);
174279
return ret;

tests/probes/yamlfilecontent/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ if(ENABLE_PROBES_INDEPENDENT)
22
add_oscap_test("test_probes_yamlfilecontent_key.sh")
33
add_oscap_test("test_probes_yamlfilecontent_array.sh")
44
add_oscap_test("test_probes_yamlfilecontent_offline_mode.sh")
5+
add_oscap_test("test_probes_yamlfilecontent_types.sh")
56
endif()
67

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/bash
2+
3+
. $builddir/tests/test_common.sh
4+
5+
set -e -o pipefail
6+
7+
function test_probes_yamlfilecontent_types {
8+
9+
probecheck "yamlfilecontent" || return 255
10+
11+
local ret_val=0
12+
local oval_file="${srcdir}/test_probes_yamlfilecontent_types.xml"
13+
local result="results.xml"
14+
15+
[ -f $result ] && rm -f $result
16+
17+
cp "${srcdir}/types.yaml" /tmp
18+
19+
local YAML_FILE="/tmp/types.yaml"
20+
21+
$OSCAP oval eval --results $result $oval_file
22+
23+
[ -f $result ]
24+
25+
sd='/oval_results/results/system/oval_system_characteristics/system_data/'
26+
assert_exists 8 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="boolean"]'
27+
assert_exists 5 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="int"]'
28+
assert_exists 7 $sd'/ind-sys:yamlfilecontent_item/ind-sys:value_of[@datatype="float"]'
29+
30+
rm -f $result
31+
rm -f $YAML_FILE
32+
33+
}
34+
35+
test_probes_yamlfilecontent_types

0 commit comments

Comments
 (0)