int regex_writef(struct regex_data *regex, FILE *fp, int unused __attribute__((unused))) { int rc; size_t len; uint32_t to_write; size_t size; pcre_extra *sd = get_pcre_extra(regex); /* determine the size of the pcre data in bytes */ rc = pcre_fullinfo(regex->regex, NULL, PCRE_INFO_SIZE, &size); if (rc < 0) return -1; /* write the number of bytes in the pcre data */ to_write = size; len = fwrite(&to_write, sizeof(uint32_t), 1, fp); if (len != 1) return -1; /* write the actual pcre data as a char array */ len = fwrite(regex->regex, 1, to_write, fp); if (len != to_write) return -1; if (sd) { /* determine the size of the pcre study info */ rc = pcre_fullinfo(regex->regex, sd, PCRE_INFO_STUDYSIZE, &size); if (rc < 0) return -1; } else size = 0; /* write the number of bytes in the pcre study data */ to_write = size; len = fwrite(&to_write, sizeof(uint32_t), 1, fp); if (len != 1) return -1; if (sd) { /* write the actual pcre study data as a char array */ len = fwrite(sd->study_data, 1, to_write, fp); if (len != to_write) return -1; } return 0; }
int regex_match(struct regex_data *regex, char const *subject, int partial) { int rc; rc = pcre_exec(regex->regex, get_pcre_extra(regex), subject, strlen(subject), 0, partial ? PCRE_PARTIAL_SOFT : 0, NULL, 0); switch (rc) { case 0: return REGEX_MATCH; case PCRE_ERROR_PARTIAL: return REGEX_MATCH_PARTIAL; case PCRE_ERROR_NOMATCH: return REGEX_NO_MATCH; default: return REGEX_ERROR; } }
/* * File Format * * u32 - magic number * u32 - version * u32 - length of pcre version EXCLUDING nul * char - pcre version string EXCLUDING nul * u32 - number of stems * ** Stems * u32 - length of stem EXCLUDING nul * char - stem char array INCLUDING nul * u32 - number of regexs * ** Regexes * u32 - length of upcoming context INCLUDING nul * char - char array of the raw context * u32 - length of the upcoming regex_str * char - char array of the original regex string including the stem. * u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE * mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS * s32 - stemid associated with the regex * u32 - spec has meta characters * u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN * u32 - data length of the pcre regex * char - a bufer holding the raw pcre regex info * u32 - data length of the pcre regex study daya * char - a buffer holding the raw pcre regex study data */ static int write_binary_file(struct saved_data *data, int fd) { struct spec *specs = data->spec_arr; FILE *bin_file; size_t len; uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT; uint32_t section_len; uint32_t i; int rc; bin_file = fdopen(fd, "w"); if (!bin_file) { perror("fopen output_file"); exit(EXIT_FAILURE); } /* write some magic number */ len = fwrite(&magic, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* write the version */ section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS; len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* write the pcre version */ section_len = strlen(pcre_version()); len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; len = fwrite(pcre_version(), sizeof(char), section_len, bin_file); if (len != section_len) goto err; /* write the number of stems coming */ section_len = data->num_stems; len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; for (i = 0; i < section_len; i++) { char *stem = data->stem_arr[i].buf; uint32_t stem_len = data->stem_arr[i].len; /* write the strlen (aka no nul) */ len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* include the nul in the file */ stem_len += 1; len = fwrite(stem, sizeof(char), stem_len, bin_file); if (len != stem_len) goto err; } /* write the number of regexes coming */ section_len = data->nspec; len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; for (i = 0; i < section_len; i++) { char *context = specs[i].lr.ctx_raw; char *regex_str = specs[i].regex_str; mode_t mode = specs[i].mode; size_t prefix_len = specs[i].prefix_len; int32_t stem_id = specs[i].stem_id; pcre *re = specs[i].regex; pcre_extra *sd = get_pcre_extra(&specs[i]); uint32_t to_write; size_t size; /* length of the context string (including nul) */ to_write = strlen(context) + 1; len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* original context strin (including nul) */ len = fwrite(context, sizeof(char), to_write, bin_file); if (len != to_write) goto err; /* length of the original regex string (including nul) */ to_write = strlen(regex_str) + 1; len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* original regex string */ len = fwrite(regex_str, sizeof(char), to_write, bin_file); if (len != to_write) goto err; /* binary F_MODE bits */ to_write = mode; len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* stem for this regex (could be -1) */ len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file); if (len != 1) goto err; /* does this spec have a metaChar? */ to_write = specs[i].hasMetaChars; len = fwrite(&to_write, sizeof(to_write), 1, bin_file); if (len != 1) goto err; /* For SELINUX_COMPILED_FCONTEXT_PREFIX_LEN */ to_write = prefix_len; len = fwrite(&to_write, sizeof(to_write), 1, bin_file); if (len != 1) goto err; /* determine the size of the pcre data in bytes */ rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size); if (rc < 0) goto err; /* write the number of bytes in the pcre data */ to_write = size; len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* write the actual pcre data as a char array */ len = fwrite(re, 1, to_write, bin_file); if (len != to_write) goto err; /* determine the size of the pcre study info */ rc = pcre_fullinfo(re, sd, PCRE_INFO_STUDYSIZE, &size); if (rc < 0) goto err; /* write the number of bytes in the pcre study data */ to_write = size; len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); if (len != 1) goto err; /* write the actual pcre study data as a char array */ len = fwrite(sd->study_data, 1, to_write, bin_file); if (len != to_write) goto err; } rc = 0; out: fclose(bin_file); return rc; err: rc = -1; goto out; }
static struct spec *lookup_common(struct selabel_handle *rec, const char *key, int type, bool partial) { struct saved_data *data = (struct saved_data *)rec->data; struct spec *spec_arr = data->spec_arr; int i, rc, file_stem, pcre_options = 0; mode_t mode = (mode_t)type; const char *buf; struct spec *ret = NULL; char *clean_key = NULL; const char *prev_slash, *next_slash; unsigned int sofar = 0; if (!data->nspec) { errno = ENOENT; goto finish; } /* Remove duplicate slashes */ if ((next_slash = strstr(key, "//"))) { clean_key = (char *) malloc(strlen(key) + 1); if (!clean_key) goto finish; prev_slash = key; while (next_slash) { memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash); sofar += next_slash - prev_slash; prev_slash = next_slash + 1; next_slash = strstr(prev_slash, "//"); } strcpy(clean_key + sofar, prev_slash); key = clean_key; } buf = key; file_stem = find_stem_from_file(data, &buf); mode &= S_IFMT; if (partial) pcre_options |= PCRE_PARTIAL_SOFT; /* * Check for matching specifications in reverse order, so that * the last matching specification is used. */ for (i = data->nspec - 1; i >= 0; i--) { struct spec *spec = &spec_arr[i]; /* if the spec in question matches no stem or has the same * stem as the file AND if the spec in question has no mode * specified or if the mode matches the file mode then we do * a regex check */ if ((spec->stem_id == -1 || spec->stem_id == file_stem) && (!mode || !spec->mode || mode == spec->mode)) { if (compile_regex(data, spec, NULL) < 0) goto finish; if (spec->stem_id == -1) rc = pcre_exec(spec->regex, get_pcre_extra(spec), key, strlen(key), 0, pcre_options, NULL, 0); else rc = pcre_exec(spec->regex, get_pcre_extra(spec), buf, strlen(buf), 0, pcre_options, NULL, 0); if (rc == 0) { spec->matches++; break; } else if (partial && rc == PCRE_ERROR_PARTIAL) break; if (rc == PCRE_ERROR_NOMATCH) continue; errno = ENOENT; /* else it's an error */ goto finish; } } if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) { /* No matching specification. */ errno = ENOENT; goto finish; } errno = 0; ret = &spec_arr[i]; finish: free(clean_key); return ret; }