|
234 | 234 | DATA FLOW: |
235 | 235 | ========== |
236 | 236 |
|
237 | | - Each object extracts the FULL line (or array) as `subexpression`. |
238 | | - Each state uses `pattern match` to check if `arg=value` appears in that captured text. |
239 | | - All `grub`-location tests share one state; `bootc` has its own (quotes around value). |
240 | | - |
241 | | - [VISUAL DIAGRAM: 6 object boxes on the left (one per config file location) with |
242 | | - arrows pointing to 3 state boxes on the right (shared grub state, bootc state, |
243 | | - and kernelopts state). Shows which objects feed which states.] |
244 | | - |
245 | | - OBJECTS STATES |
246 | | - ═══════ ══════ |
247 | | - |
248 | | - ┌─ /boot/loader/entries/ ──────────────────┐ |
249 | | - │ path: /boot/loader/entries/ │ |
250 | | - │ filename: ^.*\.conf$ │ ┌─ state_grub2_{ARG}_argument ───────────────┐ |
251 | | - │ pattern: ^options (.*)$ │─>│ │ |
252 | | - │ filter: exclude *rescue.conf │ │ ^(?:.*\s)?{ARG_NAME_VALUE}(?:\s.*)?$ │ |
253 | | - │ (uses_boot_loader_entries) │ │ │ |
254 | | - └──────────────────────────────────────────┘ │ Shared by ALL objects in this column. │ |
255 | | - │ Pattern match: is `{ARG_NAME_VALUE}` │ |
256 | | - ┌─ {grub2_boot_path}/grubenv ─────────────┐ │ present as a standalone word in the │ |
257 | | - │ filepath: {grub2_boot_path}/grubenv │ │ captured line? The regex enforces │ |
258 | | - │ pattern: ^kernelopts=(.*)$ │─>│ whitespace/start/end boundaries. │ |
259 | | - │ (uses_kernelopts) │ │ │ |
260 | | - └──────────────────────────────────────────┘ │ When `ARG_VARIABLE` is set, the regex │ |
261 | | - │ cannot be hardcoded at build time (the │ |
262 | | - │ value is not known yet). Instead, `oscap` │ |
263 | | - │ assembles it at runtime: an `external_ │ |
264 | | - │ variable` receives the value from the │ |
265 | | - │ `XCCDF` profile, a `local_variable` uses │ |
266 | | - │ `<concat>` to join fixed regex fragments │ |
267 | | - │ around that value, and the state references │ |
268 | | - │ the resulting string via `var_ref`. │ |
269 | | - │ │ |
270 | | - ┌─ {grub2_boot_path}/grub.cfg ────────────┐ │ │ |
271 | | - │ filepath: {grub2_boot_path}/grub.cfg │ │ │ |
272 | | - │ pattern: ^.*/vmlinuz.*(root=.*)$ │─>│ │ |
273 | | - │ (uses_grub_cfg) │ │ │ |
274 | | - └──────────────────────────────────────────┘ │ │ |
275 | | - │ │ |
276 | | - ┌─ /etc/default/grub ─────────────────────┐ │ │ |
277 | | - │ filepath: /etc/default/grub │ │ │ |
278 | | - │ pattern: ^\s*GRUB_CMDLINE_LINUX= │ │ │ |
279 | | - │ "(.*)"$ │─>│ │ |
280 | | - │ (all products) │ │ │ |
281 | | - │ + same for GRUB_CMDLINE_LINUX_DEFAULT │─>│ │ |
282 | | - └──────────────────────────────────────────┘ │ │ |
283 | | - │ │ |
284 | | - ┌─ /etc/default/grub.d/*.cfg ─────────────┐ │ │ |
285 | | - │ filepath: /etc/default/grub.d/[^/]+\.cfg│ │ │ |
286 | | - │ pattern: ^\s*GRUB_CMDLINE_LINUX= │ │ │ |
287 | | - │ "(.*)"$ │─>│ │ |
288 | | - │ (Ubuntu — uses_etc_default_grub_d) │ │ │ |
289 | | - │ + same for GRUB_CMDLINE_LINUX_DEFAULT │─>│ │ |
290 | | - └──────────────────────────────────────────┘ └─────────────────────────────────────────────┘ |
291 | | - |
292 | | - ┌─ /usr/lib/bootc/kargs.d/*.toml ─────────┐ ┌─ state_grub2_{ARG}_usr_lib_bootc_kargs_d ──┐ |
293 | | - │ path: /usr/lib/bootc/kargs.d/ │ │ │ |
294 | | - │ filename: ^.*\.toml$ │ │ ^.*"{ARG_NAME_VALUE}".*$ │ |
295 | | - │ pattern: ^kargs = \[([^\]]+)\]$ │─>│ │ |
296 | | - │ (bootable_containers_supported) │ │ Separate state: `TOML` wraps values in │ |
297 | | - └──────────────────────────────────────────┘ │ double quotes. │ |
298 | | - └─────────────────────────────────────────────┘ |
299 | | - |
300 | | - (uses_kernelopts) -- additional state used with `state_operator` = `OR`: |
301 | | - ┌─ state_grub2_{ARG}_argument_is_kernelopts ─┐ |
302 | | - │ ^(?:.*\s)?\$kernelopts(?:\s.*)?$ │ |
303 | | - │ │ |
304 | | - │ Pattern match: is `$kernelopts` present │ |
305 | | - │ as a standalone word in the captured │ |
306 | | - │ `options` line from │ |
307 | | - │ `/boot/loader/entries/*.conf`? │ |
308 | | - │ │ |
309 | | - │ The RHEL 8 BLS test applies BOTH │ |
310 | | - │ `state_grub2_{ARG}_argument` and this │ |
311 | | - │ state with `state_operator` = `OR`: │ |
312 | | - │ an entry passes if its `options` line │ |
313 | | - │ contains `{ARG_NAME_VALUE}` OR contains │ |
314 | | - │ `$kernelopts`. │ |
315 | | - │ │ |
316 | | - │ Same `uses_kernelopts` flag as the │ |
317 | | - │ `{grub2_boot_path}/grubenv` object -- │ |
318 | | - │ both exist only on RHEL 8 / OL8. │ |
319 | | - └─────────────────────────────────────────────┘ |
320 | | - |
321 | | - LONG DESCRIPTION (text equivalent of the diagram; same information, no box-drawing): |
322 | | - ────────────────────────────────────────────────────────────────────────────────────── |
323 | | - |
324 | | - There are 6 objects (data collectors) and 3 states (pass/fail conditions). |
325 | | - |
326 | | - OBJECTS -- each extracts a line of text from a config file: |
327 | | - |
328 | | - A. `/boot/loader/entries/*.conf` (RHEL 8/9/10, Fedora, OL8/9 — `uses_boot_loader_entries`) |
329 | | - OVAL element: `ind:path` + `ind:filename` with `operation` = `pattern match` |
330 | | - Pattern: `^options (.*)$` -- captures the kernel arg list after `options `. |
331 | | - Filter: excludes filenames matching `*rescue.conf`. |
332 | | - Tested against: `state_grub2_{ARG}_argument`. |
333 | | - |
334 | | - B. `{grub2_boot_path}/grubenv` (RHEL 8, OL8 — `uses_kernelopts`) |
335 | | - OVAL element: `ind:filepath` |
336 | | - Pattern: `^kernelopts=(.*)$` -- captures the arg list after `kernelopts=`. |
337 | | - Tested against: `state_grub2_{ARG}_argument`. |
338 | | - |
339 | | - C. `{grub2_boot_path}/grub.cfg` (OL7, Ubuntu — `uses_grub_cfg`) |
340 | | - OVAL element: `ind:filepath` |
341 | | - Pattern: `^.*/vmlinuz.*(root=.*)$` -- captures from `root=` to end of line. |
342 | | - Tested against: `state_grub2_{ARG}_argument`. |
343 | | - |
344 | | - D. `/etc/default/grub` (all products) |
345 | | - OVAL element: `ind:filepath` |
346 | | - Pattern: `^\s*GRUB_CMDLINE_LINUX="(.*)"$` -- captures contents between quotes. |
347 | | - Same pattern repeated for `GRUB_CMDLINE_LINUX_DEFAULT`. |
348 | | - Tested against: `state_grub2_{ARG}_argument`. |
349 | | - |
350 | | - E. `/etc/default/grub.d/*.cfg` (Ubuntu — `uses_etc_default_grub_d`) |
351 | | - OVAL element: `ind:filepath` with `operation` = `pattern match` |
352 | | - Pattern: same as D. |
353 | | - Same pattern repeated for `GRUB_CMDLINE_LINUX_DEFAULT`. |
354 | | - Tested against: `state_grub2_{ARG}_argument`. |
355 | | - |
356 | | - F. `/usr/lib/bootc/kargs.d/*.toml` (RHEL 9+, RHEL 10 — `bootable_containers_supported`) |
357 | | - OVAL element: `ind:path` + `ind:filename` with `operation` = `pattern match` |
358 | | - Pattern: `^kargs = \[([^\]]+)\]$` -- captures array contents between brackets. |
359 | | - Tested against: `state_grub2_{ARG}_usr_lib_bootc_kargs_d`. |
360 | | - |
361 | | - STATES -- each checks the captured text: |
362 | | - |
363 | | - 1. `state_grub2_{ARG}_argument` (shared by objects A through E) |
364 | | - Checks if `{ARG_NAME_VALUE}` is present as a standalone word (bounded by |
365 | | - whitespace or start/end of string). |
366 | | - When `ARG_VARIABLE` is set, `oscap` assembles the check at runtime: it reads |
367 | | - the value from the `XCCDF` profile, a `local_variable` concatenates it into |
368 | | - the pattern, and the state references it via `var_ref`. |
369 | | - |
370 | | - 2. `state_grub2_{ARG}_usr_lib_bootc_kargs_d` (used by object F only) |
371 | | - Checks if `{ARG_NAME_VALUE}` appears double-quoted (as per `TOML` syntax). |
372 | | - |
373 | | - 3. `state_grub2_{ARG}_argument_is_kernelopts` (RHEL 8, OL8 — `uses_kernelopts`) |
374 | | - Checks if `$kernelopts` is present as a standalone word. |
375 | | - Used ONLY by the RHEL 8 BLS test, which applies both state 1 and state 3 |
376 | | - with `state_operator="OR"`: an entry passes if it contains `{ARG_NAME_VALUE}` |
377 | | - OR contains `$kernelopts`. |
378 | | - |
379 | | - REGEX SEMANTICS (what each `pattern` captures as `subexpression`): |
380 | | - ───────────────────────────────────────────────────────────────── |
381 | | - |
382 | | - 1. ^options (.*)$ |
383 | | - Source: `/boot/loader/entries/*.conf` |
384 | | - Input: `options root=UUID=abc ro quiet audit_backlog_limit=8192` |
385 | | - Capture: `root=UUID=abc ro quiet audit_backlog_limit=8192` |
386 | | - (everything after `options ` -- the full space-separated kernel arg list) |
387 | | - |
388 | | - 2. ^kernelopts=(.*)$ |
389 | | - Source: `{grub2_boot_path}/grubenv` |
390 | | - Input: `kernelopts=root=UUID=abc ro quiet audit_backlog_limit=8192` |
391 | | - Capture: `root=UUID=abc ro quiet audit_backlog_limit=8192` |
392 | | - (everything after `kernelopts=` -- same format as #1) |
393 | | - |
394 | | - 3. ^.*/vmlinuz.*(root=.*)$ |
395 | | - Source: `{grub2_boot_path}/grub.cfg` |
396 | | - Input: ` linux /vmlinuz-5.14 root=UUID=abc ro quiet audit_backlog_limit=8192` |
397 | | - Capture: `root=UUID=abc ro quiet audit_backlog_limit=8192` |
398 | | - NOTE: the second `.*` is greedy -- it backtracks to the LAST `root=` in the line. |
399 | | - Only arguments AT or AFTER `root=` are captured. Arguments before `root=` are invisible. |
400 | | - |
401 | | - 4. ^\s*GRUB_CMDLINE_LINUX="(.*)"$ |
402 | | - Source: `/etc/default/grub` (or `/etc/default/grub.d/*.cfg`) |
403 | | - Input: `GRUB_CMDLINE_LINUX="ro quiet audit_backlog_limit=8192"` |
404 | | - Capture: `ro quiet audit_backlog_limit=8192` |
405 | | - (everything between the double quotes -- the full arg list) |
406 | | - Same pattern for `GRUB_CMDLINE_LINUX_DEFAULT`. |
407 | | - |
408 | | - 5. ^kargs = \[([^\]]+)\]$ |
409 | | - Source: `/usr/lib/bootc/kargs.d/*.toml` |
410 | | - Input: `kargs = ["audit_backlog_limit=8192", "nosmt"]` |
411 | | - Capture: `"audit_backlog_limit=8192", "nosmt"` |
412 | | - (everything between `[` and `]` -- quoted comma-separated values) |
413 | | - |
414 | | - STATE MATCHING (applied to the captured `subexpression`): |
415 | | - ───────────────────────────────────────────────────────── |
416 | | - |
417 | | - state_grub2_{ARG}_argument: |
418 | | - ^(?:.*\s)?{ARG_NAME_VALUE}(?:\s.*)?$ |
419 | | - Checks if `arg=value` appears as a WHOLE WORD (bounded by start/end or whitespace). |
420 | | - Example: `^(?:.*\s)?audit_backlog_limit=8192(?:\s.*)?$` |
421 | | - Matches: `root=UUID=abc ro quiet audit_backlog_limit=8192` (at end) |
422 | | - Matches: `audit_backlog_limit=8192 ro quiet` (at start) |
423 | | - Matches: `ro audit_backlog_limit=8192 quiet` (in middle) |
424 | | - NO match: `foo_audit_backlog_limit=8192` (not word-bounded on left) |
425 | | - |
426 | | - state_grub2_{ARG}_usr_lib_bootc_kargs_d: |
427 | | - ^.*"{ARG_NAME_VALUE}".*$ |
428 | | - Checks if `"arg=value"` appears anywhere (double-quoted, as per `TOML` syntax). |
429 | | - Example: `^.*"audit_backlog_limit=8192".*$` |
430 | | - Matches: `"audit_backlog_limit=8192", "nosmt"` |
431 | | - |
432 | | - state_grub2_{ARG}_argument_is_kernelopts: |
433 | | - ^(?:.*\s)?\$kernelopts(?:\s.*)?$ |
434 | | - Checks if `$kernelopts` appears as a whole word (same word-boundary logic). |
435 | | - Used by RHEL 8 BLS test with `state_operator="OR"`: entry passes if it has |
436 | | - the arg itself OR contains `$kernelopts` (which gets expanded at boot time). |
437 | | - |
438 | | - The `uses_*` flags control which locations are verified per product. |
| 237 | + Each object extracts ONLY THE ARGUMENT VALUE via a capturing group. |
| 238 | + Each state compares that value using OVAL-native operation and datatype |
| 239 | + (equals, greater than or equal, pattern match; string or int). |
| 240 | + No local_variable, no concat, no runtime regex assembly. |
| 241 | + All grub-location tests share one state; bootc shares it too (value |
| 242 | + extracted from TOML quotes in the object pattern). |
| 243 | + |
| 244 | + Exception: the RHEL 8 coverage path still captures the full options |
| 245 | + line and checks for the argument name via pattern match (needed to |
| 246 | + verify coverage across entries that may use $kernelopts). |
| 247 | + |
| 248 | + OBJECTS -- each extracts the value after {ARG_NAME}= from a config file: |
| 249 | + |
| 250 | + A. /boot/loader/entries/*.conf (RHEL 8/9/10, Fedora, OL8/9) |
| 251 | + Pattern: ^options\s+(?:.*\s)?{ARG_NAME}=(\S+) |
| 252 | + Captures: just the value (e.g. 8192) |
| 253 | + |
| 254 | + B. {grub2_boot_path}/grubenv (RHEL 8, OL8) |
| 255 | + Pattern: ^kernelopts=(?:.*\s)?{ARG_NAME}=(\S+) |
| 256 | + Captures: just the value |
| 257 | + |
| 258 | + C. {grub2_boot_path}/grub.cfg (OL7, Ubuntu) |
| 259 | + Pattern: ^.*/vmlinuz.*\s{ARG_NAME}=(\S+) |
| 260 | + Captures: just the value |
| 261 | + |
| 262 | + D. /etc/default/grub (all products) |
| 263 | + Pattern: ^\s*GRUB_CMDLINE_LINUX="(?:.*\s)?{ARG_NAME}=([^\s"]+) |
| 264 | + Captures: just the value (stops at whitespace or closing quote) |
| 265 | + |
| 266 | + E. /etc/default/grub.d/*.cfg (Ubuntu) |
| 267 | + Same patterns as D. |
| 268 | + |
| 269 | + F. /usr/lib/bootc/kargs.d/*.toml (RHEL 9+, RHEL 10 — bootc) |
| 270 | + Pattern: ^kargs\s*=\s*\[.*"{ARG_NAME}=([^"]+)".*\]$ |
| 271 | + Captures: just the value (from within TOML quotes) |
| 272 | + |
| 273 | + For no-value arguments (e.g. nousb), patterns check presence only |
| 274 | + (no capturing group, no state). |
| 275 | + |
| 276 | + STATES -- compare the captured value: |
| 277 | + |
| 278 | + 1. state_grub2_{ARG}_argument (shared by all objects) |
| 279 | + Uses operation and datatype from rule.yml. |
| 280 | + arg_value rules: literal comparison (e.g. equals "1") |
| 281 | + arg_variable rules: var_ref to XCCDF variable (resolved at scan time) |
| 282 | + |
| 283 | + 2. state_grub2_{ARG}_argument_is_kernelopts (RHEL 8, OL8 only) |
| 284 | + Pattern match: checks if $kernelopts appears in the full options line. |
| 285 | + Used by the RHEL 8 coverage test with state_operator="OR". |
| 286 | + |
| 287 | + The uses_* flags control which locations are verified per product. |
439 | 288 | -#}} |
440 | 289 |
|
441 | 290 | {{% set uses_boot_loader_entries = product in ["fedora", "ol8", "ol9", "rhel8", "rhel9", "rhel10"] %}} |
|
699 | 548 | {{{ etc_default_grub_object_and_test("GRUB_CMDLINE_LINUX_DEFAULT") }}} |
700 | 549 |
|
701 | 550 |
|
702 | | -{{# RHEL 8/9/10, Fedora, OL8/9 — uses_boot_loader_entries #}} |
| 551 | +{{# RHEL 8/9/10, Fedora, OL8/9 — uses_boot_loader_entries |
| 552 | + ID uses _RULE_ID (not ARG_NAME_UNDERSCORED) to guarantee uniqueness across rules. #}} |
703 | 553 | {{% if uses_boot_loader_entries %}} |
704 | 554 | <ind:textfilecontent54_state id="state_grub2_{{{ _RULE_ID }}}_is_rescue_entry" version="1" |
705 | 555 | comment="Match /boot/loader/entries/*rescue.conf filenames for exclusion"> |
|
796 | 646 | Used negated in criteria: if no entry has $kernelopts, grubenv check is skipped. #}} |
797 | 647 | <ind:textfilecontent54_test id="test_grub2_{{{ ARG_NAME_UNDERSCORED }}}_kernelopts_in_any_boot_loader_entry" |
798 | 648 | comment="Check if any /boot/loader/entries/*.conf references $kernelopts" |
799 | | - check="all" check_existence="at_least_one_exists" version="1"> |
| 649 | + check="at least one" check_existence="at_least_one_exists" version="1"> |
800 | 650 | <ind:object object_ref="obj_grub2_{{{ ARG_NAME_UNDERSCORED }}}_bls_entries" /> |
801 | 651 | <ind:state state_ref="state_grub2_{{{ ARG_NAME_UNDERSCORED }}}_argument_is_kernelopts" /> |
802 | 652 | </ind:textfilecontent54_test> |
|
846 | 696 | <ind:path>/usr/lib/bootc/kargs.d/</ind:path> |
847 | 697 | <ind:filename operation="pattern match">^.*\.toml$</ind:filename> |
848 | 698 | {{%- if has_value %}} |
849 | | - <ind:pattern operation="pattern match">^kargs\s*=\s*\[.*"{{{ ARG_NAME }}}=([^"]+)".*\]$</ind:pattern> |
| 699 | + <ind:pattern operation="pattern match">^kargs\s*=\s*\[.*"{{{ ARG_NAME_ESCAPED_DOTS }}}=([^"]+)".*\]$</ind:pattern> |
850 | 700 | {{%- else %}} |
851 | | - <ind:pattern operation="pattern match">^kargs\s*=\s*\[.*"{{{ ARG_NAME }}}".*\]$</ind:pattern> |
| 701 | + <ind:pattern operation="pattern match">^kargs\s*=\s*\[.*"{{{ ARG_NAME_ESCAPED_DOTS }}}".*\]$</ind:pattern> |
852 | 702 | {{%- endif %}} |
853 | 703 | <ind:instance datatype="int" operation="greater than or equal">1</ind:instance> |
854 | 704 | </ind:textfilecontent54_object> |
|
0 commit comments