int compat_validate(struct selabel_handle *rec, struct selabel_lookup_rec *contexts, const char *path, unsigned lineno) { int rc; char **ctx = &contexts->ctx_raw; if (myinvalidcon) rc = myinvalidcon(path, lineno, *ctx); else if (mycanoncon) rc = mycanoncon(path, lineno, ctx); else { rc = selabel_validate(rec, contexts); if (rc < 0) { if (lineno) { COMPAT_LOG(SELINUX_WARNING, "%s: line %u has invalid context %s\n", path, lineno, *ctx); } else { COMPAT_LOG(SELINUX_WARNING, "%s: has invalid context %s\n", path, *ctx); } } } return rc ? -1 : 0; }
/* * Warn about duplicate specifications. */ static int nodups_specs(struct saved_data *data, const char *path) { int rc = 0; unsigned int ii, jj; struct spec *curr_spec, *spec_arr = data->spec_arr; for (ii = 0; ii < data->nspec; ii++) { curr_spec = &spec_arr[ii]; for (jj = ii + 1; jj < data->nspec; jj++) { if ((!strcmp (spec_arr[jj].regex_str, curr_spec->regex_str)) && (!spec_arr[jj].mode || !curr_spec->mode || spec_arr[jj].mode == curr_spec->mode)) { rc = -1; errno = EINVAL; if (strcmp (spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) { COMPAT_LOG (SELINUX_ERROR, "%s: Multiple different specifications for %s (%s and %s).\n", path, curr_spec->regex_str, spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw); } else { COMPAT_LOG (SELINUX_ERROR, "%s: Multiple same specifications for %s.\n", path, curr_spec->regex_str); } } } } return rc; }
static void stats(struct selabel_handle *rec) { struct saved_data *data = (struct saved_data *)rec->data; unsigned int i, nspec = data->nspec; spec_t *spec_arr = data->spec_arr; for (i = 0; i < nspec; i++) { if (spec_arr[i].matches == 0) { if (spec_arr[i].type_str) { COMPAT_LOG(SELINUX_WARNING, "Warning! No matches for (%s, %s, %s)\n", spec_arr[i].regex_str, spec_arr[i].type_str, spec_arr[i].lr.ctx_raw); } else { COMPAT_LOG(SELINUX_WARNING, "Warning! No matches for (%s, %s)\n", spec_arr[i].regex_str, spec_arr[i].lr.ctx_raw); } } } }
static int process_line(struct selabel_handle *rec, const char *path, const char *prefix, char *line_buf, int pass, unsigned lineno) { int items, len; char *buf_p, *regex, *type, *context; struct saved_data *data = (struct saved_data *)rec->data; spec_t *spec_arr = data->spec_arr; unsigned int nspec = data->nspec; len = strlen(line_buf); if (line_buf[len - 1] == '\n') line_buf[len - 1] = 0; buf_p = line_buf; while (isspace(*buf_p)) buf_p++; /* Skip comment lines and empty lines. */ if (*buf_p == '#' || *buf_p == 0) return 0; items = sscanf(line_buf, "%as %as %as", ®ex, &type, &context); if (items < 2) { COMPAT_LOG(SELINUX_WARNING, "%s: line %d is missing fields, skipping\n", path, lineno); if (items == 1) free(regex); return 0; } else if (items == 2) { /* The type field is optional. */ free(context); context = type; type = 0; } len = get_stem_from_spec(regex); if (len && prefix && strncmp(prefix, regex, len)) { /* Stem of regex does not match requested prefix, discard. */ free(regex); free(type); free(context); return 0; } if (pass == 1) { /* On the second pass, process and store the specification in spec. */ char *errbuf = NULL; spec_arr[nspec].stem_id = find_stem_from_spec(data, regex); spec_arr[nspec].regex_str = regex; if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) { COMPAT_LOG(SELINUX_WARNING, "%s: line %d has invalid regex %s: %s\n", path, lineno, regex, (errbuf ? errbuf : "out of memory")); } /* Convert the type string to a mode format */ spec_arr[nspec].type_str = type; spec_arr[nspec].mode = 0; if (!type) goto skip_type; len = strlen(type); if (type[0] != '-' || len != 2) { COMPAT_LOG(SELINUX_WARNING, "%s: line %d has invalid file type %s\n", path, lineno, type); return 0; } switch (type[1]) { case 'b': spec_arr[nspec].mode = S_IFBLK; break; case 'c': spec_arr[nspec].mode = S_IFCHR; break; case 'd': spec_arr[nspec].mode = S_IFDIR; break; case 'p': spec_arr[nspec].mode = S_IFIFO; break; case 'l': spec_arr[nspec].mode = S_IFLNK; break; case 's': spec_arr[nspec].mode = S_IFSOCK; break; case '-': spec_arr[nspec].mode = S_IFREG; break; default: COMPAT_LOG(SELINUX_WARNING, "%s: line %d has invalid file type %s\n", path, lineno, type); return 0; } skip_type: spec_arr[nspec].lr.ctx_raw = context; /* Determine if specification has * any meta characters in the RE */ spec_hasMetaChars(&spec_arr[nspec]); if (strcmp(context, "<<none>>") && rec->validating) compat_validate(rec, &spec_arr[nspec].lr, path, lineno); } data->nspec = ++nspec; if (pass == 0) { free(regex); if (type) free(type); free(context); } return 0; }