Page MenuHomeFreeBSD

D59585.id186449.diff
No OneTemporary

D59585.id186449.diff

diff --git a/sys/security/mac_do/mac_do.c b/sys/security/mac_do/mac_do.c
--- a/sys/security/mac_do/mac_do.c
+++ b/sys/security/mac_do/mac_do.c
@@ -204,6 +204,7 @@
struct id_spec *gids;
u_int exec_paths_nb;
char **exec_paths;
+ char **exec_parents;
bool exec_is_blacklist;
};
@@ -395,9 +396,12 @@
STAILQ_FOREACH_SAFE(rule, head, r_entries, rule_next) {
free(rule->uids, M_MAC_DO);
free(rule->gids, M_MAC_DO);
- for (u_int i = 0; i < rule->exec_paths_nb; i++)
+ for (u_int i = 0; i < rule->exec_paths_nb; i++) {
free(rule->exec_paths[i], M_MAC_DO);
+ free(rule->exec_parents[i], M_MAC_DO);
+ }
free(rule->exec_paths, M_MAC_DO);
+ free(rule->exec_parents, M_MAC_DO);
free(rule, M_MAC_DO);
}
@@ -950,7 +954,7 @@
parse_rule_exec(char *exec_str, struct rule *const rule,
const char *const start, struct parse_error **const parse_error)
{
- char **paths, *p, *path_p, *tok, *key;
+ char **paths, **parents, *p, *path_p, *group, *key;
u_int nb, capacity;
bool negated;
@@ -1004,22 +1008,74 @@
* replacing ':' with '\0'. Not worth the trouble.
*/
paths = malloc(capacity * sizeof(char *), M_MAC_DO, M_WAITOK);
+ parents = malloc(capacity * sizeof(char *), M_MAC_DO, M_WAITOK);
path_p = p;
- while ((tok = strsep_noblanks(&path_p, ":")) != NULL) {
- if (*tok == '\0')
+ while ((group = strsep_noblanks(&path_p, ":")) != NULL) {
+ char *child_p, *parent, *tok, *sep;
+ bool suppress;
+
+ if (*group == '\0')
continue;
- if (tok[0] != '/') {
- make_parse_error(parse_error, tok - start,
- "Exec path '%s' is not absolute.", tok);
+
+ suppress = false;
+ if (*group == '~') {
+ if (negated) {
+ make_parse_error(parse_error, group - start,
+ "'~' is not allowed in an exec blacklist.");
+ goto einval;
+ }
+ suppress = true;
+ group++;
+ if (*group == '\0') {
+ make_parse_error(parse_error, group - 1 - start,
+ "Empty exec path after '~'.");
+ goto einval;
+ }
+ }
+
+ sep = strchr(group, '|');
+ if (sep != NULL && negated) {
+ make_parse_error(parse_error, sep - start,
+ "Scoped exec paths ('|') are not allowed in an "
+ "exec blacklist.");
+ goto einval;
+ }
+ if (sep == NULL && suppress) {
+ make_parse_error(parse_error, group - 1 - start,
+ "'~' has no effect without scoped paths ('|').");
goto einval;
}
- if (nb >= capacity) {
- capacity *= 2;
- paths = realloc(paths,
- capacity * sizeof(char *), M_MAC_DO, M_WAITOK);
+
+ child_p = group;
+ parent = NULL;
+ for (u_int j = 0;
+ (tok = strsep_noblanks(&child_p, "|")) != NULL; j++) {
+ if (*tok == '\0') {
+ make_parse_error(parse_error, tok - start,
+ "Empty exec path.");
+ goto einval;
+ }
+ if (tok[0] != '/') {
+ make_parse_error(parse_error, tok - start,
+ "Exec path '%s' is not absolute.", tok);
+ goto einval;
+ }
+ if (j == 0) {
+ parent = tok;
+ if (suppress)
+ continue;
+ }
+ if (nb >= capacity) {
+ capacity *= 2;
+ paths = realloc(paths,
+ capacity * sizeof(char *), M_MAC_DO, M_WAITOK);
+ parents = realloc(parents,
+ capacity * sizeof(char *), M_MAC_DO, M_WAITOK);
+ }
+ paths[nb] = strdup(tok, M_MAC_DO);
+ parents[nb] = j != 0 ? strdup(parent, M_MAC_DO) : NULL;
+ nb++;
}
- paths[nb] = strdup(tok, M_MAC_DO);
- nb++;
}
if (nb == 0) {
@@ -1028,14 +1084,17 @@
goto einval;
}
- /* Shrink allocation to actual size. */
+ /* Shrink allocations to actual size. */
rule->exec_paths = realloc(paths, nb * sizeof(char *),
M_MAC_DO, M_WAITOK);
+ rule->exec_parents = realloc(parents, nb * sizeof(char *),
+ M_MAC_DO, M_WAITOK);
rule->exec_paths_nb = nb;
return (0);
einval:
rule->exec_paths = paths;
+ rule->exec_parents = parents;
rule->exec_paths_nb = nb;
return (EINVAL);
}
@@ -1207,9 +1266,12 @@
return (0);
einval:
- for (u_int i = 0; i < new->exec_paths_nb; i++)
+ for (u_int i = 0; i < new->exec_paths_nb; i++) {
free(new->exec_paths[i], M_MAC_DO);
+ free(new->exec_parents[i], M_MAC_DO);
+ }
free(new->exec_paths, M_MAC_DO);
+ free(new->exec_parents, M_MAC_DO);
free(new->gids, M_MAC_DO);
free(new->uids, M_MAC_DO);
free(new, M_MAC_DO);
@@ -1607,9 +1669,14 @@
if (src_rule->exec_paths_nb > 0) {
dst_rule->exec_paths = malloc(
src_rule->exec_paths_nb * sizeof(char *), M_MAC_DO, M_WAITOK);
- for (u_int i = 0; i < src_rule->exec_paths_nb; i++)
+ dst_rule->exec_parents = malloc(
+ src_rule->exec_paths_nb * sizeof(char *), M_MAC_DO, M_WAITOK);
+ for (u_int i = 0; i < src_rule->exec_paths_nb; i++) {
dst_rule->exec_paths[i] = strdup(src_rule->exec_paths[i],
M_MAC_DO);
+ dst_rule->exec_parents[i] = src_rule->exec_parents[i] != NULL ?
+ strdup(src_rule->exec_parents[i], M_MAC_DO) : NULL;
+ }
dst_rule->exec_paths_nb = src_rule->exec_paths_nb;
dst_rule->exec_is_blacklist = src_rule->exec_is_blacklist;
}
@@ -2898,7 +2965,8 @@
{
struct mac_do_exec_data *data;
const char *path;
- char *to_free;
+ char *to_free, *parent_path, *parent_free;
+ bool parent_resolved;
int error;
if (do_enabled == 0)
@@ -2956,14 +3024,19 @@
*
* - Rule with no exec constraint (paths_nb == 0, not blacklist):
* allows any exec.
- * - Whitelist rule: allows if path is in the list.
- * - Blacklist rule: allows if path is NOT in the list.
- *
+ * - Whitelist rule: allows if path is in the list. A scoped entry
+ * (one with a non-NULL parent path) additionally requires the
+ * executable performing this exec to be at that parent path.
+ * - Blacklist rule: allows if path is NOT in the list (scoped
+ * entries are rejected at parse time, so parents are always NULL).
+ *
* The constraint persists across multiple exec calls — it is NOT
* cleared here. Only a new setcred(), thread exit, or module
* unload clears it.
*/
error = EPERM; /* Default deny. */
+ parent_resolved = false;
+ parent_free = NULL;
for (u_int r = 0; r < data->nb_rules; r++) {
const struct rule *rule = data->rules[r];
@@ -2974,7 +3047,28 @@
bool path_match = false;
for (u_int i = 0; i < rule->exec_paths_nb; i++) {
- if (strcmp(rule->exec_paths[i], path) == 0) {
+ if (strcmp(rule->exec_paths[i], path) != 0)
+ continue;
+ if (rule->exec_parents[i] == NULL) {
+ path_match = true; /* Unscoped entry. */
+ break;
+ }
+
+ /*
+ * Scoped entry: also requires the executable
+ * performing this exec (the old text image) to be
+ * at the entry's parent path. Resolved lazily,
+ * only when some scoped entry matches the exec'd
+ * path; resolution failure matches nothing.
+ */
+ if (!parent_resolved) {
+ parent_resolved = true;
+ if (vn_fullpath_jail(curproc->p_textvp,
+ &parent_path, &parent_free) != 0)
+ parent_path = NULL;
+ }
+ if (parent_path != NULL &&
+ strcmp(rule->exec_parents[i], parent_path) == 0) {
path_match = true;
break;
}
@@ -2993,6 +3087,7 @@
}
}
+ free(parent_free, M_TEMP);
free(to_free, M_TEMP);
return (error);
}

File Metadata

Mime Type
text/plain
Expires
Sat, Sep 12, 10:52 AM (14 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38783159
Default Alt Text
D59585.id186449.diff (6 KB)

Event Timeline