Skip to content

Commit 3f994d3

Browse files
committed
Warn on deprecated dir=untrusted rules
The legacy dir=untrusted rule macro remained accepted after it had been superseded by explicit trust matching, but parsing those rules did not tell administrators that the compatibility path is obsolete and scheduled for removal. The parser now warns whenever a subject or object directory attribute resolves to the untrusted macro, including named sets. The existing positional subject/object compatibility check in check_object() is isolated behind a named helper with comments documenting why the obsolete behavior still exists. Regression coverage in rules_test now pins the subject and object dir=untrusted warning paths, set-based warning behavior, exe=untrusted non-warning behavior, and the trusted-object compatibility exception.
1 parent 0b9b492 commit 3f994d3

4 files changed

Lines changed: 172 additions & 8 deletions

File tree

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
1.6
2+
- Many internal changes
3+
- Mark dir=untrusted as deprecated in rules
24

35
1.5
46
- Increase the line length of config files (Renaud Métrich)

doc/fapolicyd.rules.5

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,13 @@ The \fIsystemdirs\fP option will match against the same list as \fIexecdirs\fP b
8383
.B untrusted
8484
The \fIuntrusted\fP option will look up the current executable's full path in the rpm database to see if the executable is known to the system. The rule will trigger if the file in question is not in the trust database. This option is
8585
.B deprecated
86-
in favor of using obj_trust with execute permission when writing rules.
86+
in favor of using object \fBtrust\fP with execute permission when writing rules.
87+
Rules that use \fBdir=untrusted\fP emit a deprecation warning when parsed,
88+
and this compatibility option will be removed in a future release.
89+
For compatibility with older policies, a subject \fBdir=untrusted\fP rule
90+
paired with a path object at the same rule field position will not match a
91+
trusted object. This subject/object cross-reference is obsolete; use explicit
92+
object trust rules for new policy.
8793
.RE
8894
.TP
8995
.B ftype

src/library/rules.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,29 @@ static int assign_subject(llist *l, lnode *n, int type,
7171
static int assign_object(llist *l, lnode *n, int type,
7272
const char *ptr2, int lineno) __wur;
7373

74+
/*
75+
* warn_deprecated_untrusted_dir - warn about the legacy dir=untrusted macro
76+
* @type: parsed subject or object attribute type.
77+
* @set: parsed attribute value set.
78+
* @lineno: rule line number used for diagnostics.
79+
* @side: rule side used to make the warning actionable.
80+
*
81+
* The untrusted directory macro was superseded by explicit trust attributes,
82+
* but it remains accepted for old rules. Warn when a directory attribute uses
83+
* it, including through a named set, so administrators have time to migrate
84+
* before a future release removes this compatibility path.
85+
*/
86+
static void warn_deprecated_untrusted_dir(int type, attr_sets_entry_t *set,
87+
int lineno, const char *side)
88+
{
89+
if ((type == EXE_DIR || type == ODIR) &&
90+
attr_set_check_str(set, "untrusted"))
91+
msg(LOG_WARNING,
92+
"rules: line:%d: %s dir=untrusted is deprecated and "
93+
"will be removed in a future release",
94+
lineno, side);
95+
}
96+
7497
int rules_create(llist *l)
7598
{
7699
l->head = NULL;
@@ -571,6 +594,7 @@ static int assign_subject(llist *l, lnode *n, int type,
571594
} // switch
572595

573596
finalize:
597+
warn_deprecated_untrusted_dir(type, n->s[i].set, lineno, "subject");
574598
n->s_count++;
575599
free(tmp);
576600
sanity_check_node(n, "assign_subject - 2");
@@ -721,6 +745,7 @@ static int assign_object(llist *l, lnode *n, int type,
721745

722746

723747
finalize:
748+
warn_deprecated_untrusted_dir(type, n->o[i].set, lineno, "object");
724749
n->o_count++;
725750
free(tmp);
726751
sanity_check_node(n, "assign_object - 2");
@@ -1497,6 +1522,32 @@ static int check_subject(lnode *r, event_t *e)
14971522
return 1;
14981523
}
14991524

1525+
/*
1526+
* legacy_untrusted_subject_path_blocked - preserve untrusted path exception
1527+
* @r: rule being evaluated.
1528+
* @idx: object attribute index currently being evaluated.
1529+
* @e: event containing already-owned decision attributes.
1530+
*
1531+
* Historical exe=untrusted and dir=untrusted subject rules also filtered a
1532+
* path object at the same rule-field index: trusted objects did not match the
1533+
* legacy untrusted exception. The positional cross-reference is obsolete, but
1534+
* remains here for compatibility until dir=untrusted support is removed.
1535+
*
1536+
* Returns: 1 when the legacy compatibility rule blocks this object match,
1537+
* otherwise 0.
1538+
*/
1539+
static int legacy_untrusted_subject_path_blocked(lnode *r, unsigned int idx,
1540+
event_t *e)
1541+
{
1542+
if (idx >= r->s_count)
1543+
return 0;
1544+
if (r->s[idx].type != EXE && r->s[idx].type != EXE_DIR)
1545+
return 0;
1546+
if (!attr_set_check_str(r->s[idx].set, "untrusted"))
1547+
return 0;
1548+
1549+
return is_obj_trusted(e);
1550+
}
15001551

15011552
// Returns 0 if no match, 1 if a match
15021553
__attribute__((hot))
@@ -1542,13 +1593,9 @@ static decision_t check_object(lnode *r, event_t *e)
15421593

15431594
case PATH:
15441595
// skip if fall through
1545-
if (type == PATH) {
1546-
if (r->s[cnt].type == EXE || r->s[cnt].type == EXE_DIR)
1547-
if (attr_set_check_str(r->s[cnt].set,
1548-
"untrusted"))
1549-
if (is_obj_trusted(e))
1550-
return 0;
1551-
}
1596+
if (type == PATH &&
1597+
legacy_untrusted_subject_path_blocked(r, cnt, e))
1598+
return 0;
15521599

15531600
// fall through
15541601

src/tests/rules_test.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,33 @@ static void prep_macro_event(event_t *e, const char *exe, const char *obj)
209209
e->type = 0;
210210
}
211211

212+
/*
213+
* add_trust_attrs - add cached subject and object trust values
214+
*
215+
* e: event to update
216+
* subj_trusted: subject trust value to cache
217+
* obj_trusted: object trust value to cache
218+
*
219+
* Returns: none
220+
*/
221+
static void add_trust_attrs(event_t *e, unsigned int subj_trusted,
222+
int obj_trusted)
223+
{
224+
subject_attr_t subj_trust = {
225+
.type = SUBJ_TRUST,
226+
.uval = subj_trusted
227+
};
228+
object_attr_t obj_trust = {
229+
.type = OBJ_TRUST,
230+
.val = obj_trusted
231+
};
232+
233+
if (subject_add(e->s, &subj_trust))
234+
error(1, 0, "subject_add trust failed");
235+
if (object_add(e->o, &obj_trust))
236+
error(1, 0, "object_add trust failed");
237+
}
238+
212239
/*
213240
* free_event - release memory from prep_event()
214241
*/
@@ -330,6 +357,88 @@ int main(void)
330357

331358
rules_clear(&l);
332359

360+
/* deprecated dir=untrusted warnings and compatibility */
361+
if (rules_create(&l))
362+
error(1, 0, "rules_create failed");
363+
364+
rc = append_capture(&l,
365+
"allow perm=any dir=untrusted : path=/tmp/payload", 1,
366+
err, sizeof(err));
367+
if (rc)
368+
error(1, 0, "subject untrusted dir parse failed: %s", err);
369+
if (strstr(err, "subject dir=untrusted is deprecated") == NULL)
370+
error(1, 0, "subject untrusted dir warning missing: %s", err);
371+
372+
prep_macro_event(&e, "/opt/untrusted-tool", "/tmp/payload");
373+
add_trust_attrs(&e, 0, 0);
374+
if (evaluate(&l, &e) != ALLOW)
375+
error(1, 0, "subject untrusted dir compatibility failed");
376+
free_event(&e);
377+
378+
prep_macro_event(&e, "/opt/untrusted-tool", "/tmp/payload");
379+
add_trust_attrs(&e, 0, 1);
380+
if (evaluate(&l, &e) != NO_OPINION)
381+
error(1, 0, "trusted object matched legacy exception");
382+
free_event(&e);
383+
384+
rules_clear(&l);
385+
386+
if (rules_create(&l))
387+
error(1, 0, "rules_create failed");
388+
389+
rc = append_capture(&l,
390+
"allow perm=any all : dir=untrusted", 1,
391+
err, sizeof(err));
392+
if (rc)
393+
error(1, 0, "object untrusted dir parse failed: %s", err);
394+
if (strstr(err, "object dir=untrusted is deprecated") == NULL)
395+
error(1, 0, "object untrusted dir warning missing: %s", err);
396+
397+
prep_macro_event(&e, "/usr/bin/bash", "/tmp/payload");
398+
add_trust_attrs(&e, 1, 0);
399+
if (evaluate(&l, &e) != ALLOW)
400+
error(1, 0, "object untrusted dir compatibility failed");
401+
free_event(&e);
402+
403+
prep_macro_event(&e, "/usr/bin/bash", "/tmp/payload");
404+
add_trust_attrs(&e, 1, 1);
405+
if (evaluate(&l, &e) != NO_OPINION)
406+
error(1, 0, "trusted object matched object untrusted dir");
407+
free_event(&e);
408+
409+
rules_clear(&l);
410+
411+
if (rules_create(&l))
412+
error(1, 0, "rules_create failed");
413+
414+
rc = append_capture(&l, "%legacy=untrusted", 1, err, sizeof(err));
415+
if (rc)
416+
error(1, 0, "legacy set parse failed: %s", err);
417+
if (strstr(err, "dir=untrusted is deprecated") != NULL)
418+
error(1, 0, "set definition emitted dir warning: %s", err);
419+
420+
rc = append_capture(&l,
421+
"allow perm=any all : dir=%legacy", 2, err, sizeof(err));
422+
if (rc)
423+
error(1, 0, "object untrusted dir set parse failed: %s", err);
424+
if (strstr(err, "object dir=untrusted is deprecated") == NULL)
425+
error(1, 0, "set-based untrusted dir warning missing: %s",
426+
err);
427+
428+
rules_clear(&l);
429+
430+
if (rules_create(&l))
431+
error(1, 0, "rules_create failed");
432+
433+
rc = append_capture(&l,
434+
"allow perm=any exe=untrusted : all", 1, err, sizeof(err));
435+
if (rc)
436+
error(1, 0, "exe untrusted rule parse failed: %s", err);
437+
if (strstr(err, "dir=untrusted is deprecated") != NULL)
438+
error(1, 0, "exe untrusted emitted dir warning: %s", err);
439+
440+
rules_clear(&l);
441+
333442
/* duplicate inline string values should remain harmless */
334443
if (rules_create(&l))
335444
error(1, 0, "rules_create failed");

0 commit comments

Comments
 (0)