On 09/09/2016 01:44 PM, william.c.roberts@xxxxxxxxx wrote: > From: William Roberts <william.c.roberts@xxxxxxxxx> > > The current process_file() code will open the file > twice on the case of a binary file, correct this. > > The general flow through process_file() was a bit > difficult to read, streamline the routine to be > more readable. > > Detailed statistics of before and after: > > Source lines of code reported by cloc on modified files: > before: 735 > after: 742 > > Object size difference: > before: 195530 bytes > after: 195485 bytes > > Signed-off-by: William Roberts <william.c.roberts@xxxxxxxxx> Thanks, applied, with some whitespace and other fixes on top (scripts/checkpatch.pl from the kernel tree would have noted them). > --- > libselinux/src/label_file.c | 310 ++++++++++++++++++++++++-------------------- > 1 file changed, 166 insertions(+), 144 deletions(-) > > diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c > index c89bb35..94b7627 100644 > --- a/libselinux/src/label_file.c > +++ b/libselinux/src/label_file.c > @@ -97,62 +97,40 @@ static int nodups_specs(struct saved_data *data, const char *path) > return rc; > } > > -static int load_mmap(struct selabel_handle *rec, const char *path, > - struct stat *sb, bool isbinary, > - struct selabel_digest *digest) > +static int process_text_file(FILE *fp, const char *prefix, struct selabel_handle *rec, const char *path) > +{ > + int rc; > + size_t line_len; > + unsigned lineno = 0; > + char *line_buf = NULL; > + > + while (getline(&line_buf, &line_len, fp) > 0) { > + rc = process_line(rec, path, prefix, line_buf, ++lineno); > + if (rc) > + goto out; > + } > + rc = 0; > +out: > + free(line_buf); > + return rc; > +} > + > +static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec, const char *path) > { > struct saved_data *data = (struct saved_data *)rec->data; > - char mmap_path[PATH_MAX + 1]; > - int mmapfd; > int rc; > - struct stat mmap_stat; > char *addr, *str_buf; > - size_t len; > int *stem_map; > struct mmap_area *mmap_area; > uint32_t i, magic, version; > uint32_t entry_len, stem_map_len, regex_array_len; > > - if (isbinary) { > - len = strlen(path); > - if (len >= sizeof(mmap_path)) > - return -1; > - strcpy(mmap_path, path); > - } else { > - rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path); > - if (rc >= (int)sizeof(mmap_path)) > - return -1; > - } > - > - mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC); > - if (mmapfd < 0) > - return -1; > - > - rc = fstat(mmapfd, &mmap_stat); > - if (rc < 0) { > - close(mmapfd); > - return -1; > - } > - > - /* if mmap is old, ignore it */ > - if (mmap_stat.st_mtime < sb->st_mtime) { > - close(mmapfd); > - return -1; > - } > - > - /* ok, read it in... */ > - len = mmap_stat.st_size; > - len += (sysconf(_SC_PAGE_SIZE) - 1); > - len &= ~(sysconf(_SC_PAGE_SIZE) - 1); > - > mmap_area = malloc(sizeof(*mmap_area)); > if (!mmap_area) { > - close(mmapfd); > return -1; > } > > - addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0); > - close(mmapfd); > + addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0); > if (addr == MAP_FAILED) { > free(mmap_area); > perror("mmap"); > @@ -227,7 +205,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t)); > if (rc < 0 || !stem_len) { > rc = -1; > - goto err; > + goto out; > } > > /* Check for stem_len wrap around. */ > @@ -236,15 +214,15 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > /* Check if over-run before null check. */ > rc = next_entry(NULL, mmap_area, (stem_len + 1)); > if (rc < 0) > - goto err; > + goto out; > > if (buf[stem_len] != '\0') { > rc = -1; > - goto err; > + goto out; > } > } else { > rc = -1; > - goto err; > + goto out; > } > > /* store the mapping between old and new */ > @@ -253,7 +231,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > newid = store_stem(data, buf, stem_len); > if (newid < 0) { > rc = newid; > - goto err; > + goto out; > } > data->stem_arr[newid].from_mmap = 1; > } > @@ -264,7 +242,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > rc = next_entry(®ex_array_len, mmap_area, sizeof(uint32_t)); > if (rc < 0 || !regex_array_len) { > rc = -1; > - goto err; > + goto out; > } > > for (i = 0; i < regex_array_len; i++) { > @@ -274,7 +252,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > > rc = grow_specs(data); > if (rc < 0) > - goto err; > + goto out; > > spec = &data->spec_arr[data->nspec]; > spec->from_mmap = 1; > @@ -284,30 +262,30 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); > if (rc < 0 || !entry_len) { > rc = -1; > - goto err; > + goto out; > } > > str_buf = malloc(entry_len); > if (!str_buf) { > rc = -1; > - goto err; > + goto out; > } > rc = next_entry(str_buf, mmap_area, entry_len); > if (rc < 0) > - goto err; > + goto out; > > if (str_buf[entry_len - 1] != '\0') { > free(str_buf); > rc = -1; > - goto err; > + goto out; > } > spec->lr.ctx_raw = str_buf; > > if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) { > if (selabel_validate(rec, &spec->lr) < 0) { > selinux_log(SELINUX_ERROR, > - "%s: context %s is invalid\n", mmap_path, spec->lr.ctx_raw); > - goto err; > + "%s: context %s is invalid\n", path, spec->lr.ctx_raw); > + goto out; > } > } > > @@ -315,17 +293,17 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); > if (rc < 0 || !entry_len) { > rc = -1; > - goto err; > + goto out; > } > > spec->regex_str = (char *)mmap_area->next_addr; > rc = next_entry(NULL, mmap_area, entry_len); > if (rc < 0) > - goto err; > + goto out; > > if (spec->regex_str[entry_len - 1] != '\0') { > rc = -1; > - goto err; > + goto out; > } > > /* Process mode */ > @@ -334,14 +312,14 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > else > rc = next_entry(&mode, mmap_area, sizeof(mode_t)); > if (rc < 0) > - goto err; > + goto out; > > spec->mode = mode; > > /* map the stem id from the mmap file to the data->stem_arr */ > rc = next_entry(&stem_id, mmap_area, sizeof(int32_t)); > if (rc < 0) > - goto err; > + goto out; > > if (stem_id < 0 || stem_id >= (int32_t)stem_map_len) > spec->stem_id = -1; > @@ -351,7 +329,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > /* retrieve the hasMetaChars bit */ > rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t)); > if (rc < 0) > - goto err; > + goto out; > > spec->hasMetaChars = meta_chars; > /* and prefix length for use by selabel_lookup_best_match */ > @@ -359,7 +337,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > rc = next_entry(&prefix_len, mmap_area, > sizeof(uint32_t)); > if (rc < 0) > - goto err; > + goto out; > > spec->prefix_len = prefix_len; > } > @@ -368,25 +346,25 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); > if (rc < 0 || !entry_len) { > rc = -1; > - goto err; > + goto out; > } > spec->regex = (pcre *)mmap_area->next_addr; > rc = next_entry(NULL, mmap_area, entry_len); > if (rc < 0) > - goto err; > + goto out; > > /* Check that regex lengths match. pcre_fullinfo() > * also validates its magic number. */ > rc = pcre_fullinfo(spec->regex, NULL, PCRE_INFO_SIZE, &len); > if (rc < 0 || len != entry_len) { > rc = -1; > - goto err; > + goto out; > } > > rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t)); > if (rc < 0 || !entry_len) { > rc = -1; > - goto err; > + goto out; > } > > if (entry_len) { > @@ -394,119 +372,163 @@ static int load_mmap(struct selabel_handle *rec, const char *path, > spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA; > rc = next_entry(NULL, mmap_area, entry_len); > if (rc < 0) > - goto err; > + goto out; > > /* Check that study data lengths match. */ > rc = pcre_fullinfo(spec->regex, &spec->lsd, > PCRE_INFO_STUDYSIZE, &len); > if (rc < 0 || len != entry_len) { > rc = -1; > - goto err; > + goto out; > } > } > > data->nspec++; > } > > - rc = digest_add_specfile(digest, NULL, addr, mmap_stat.st_size, > - mmap_path); > - if (rc) > - goto err; > - > -err: > + rc = 0; > +out: > free(stem_map); > > return rc; > } > > -static int process_file(const char *path, const char *suffix, > - struct selabel_handle *rec, > - const char *prefix, struct selabel_digest *digest) > -{ > - FILE *fp; > +struct file_details { > + const char *suffix; > struct stat sb; > - unsigned int lineno; > - size_t line_len = 0; > - char *line_buf = NULL; > - int rc; > - char stack_path[PATH_MAX + 1]; > - bool isbinary = false; > +}; > + > +static char *rolling_append(char *current, const char *suffix, size_t max) > +{ > + size_t size; > + size_t suffix_size; > + size_t current_size; > + > + if (!suffix) > + return current; > + > + current_size = strlen(current); > + suffix_size = strlen(suffix); > + > + size = current_size + suffix_size; > + if (size < current_size || size < suffix_size) > + return NULL; > + > + /* ensure space for the '.' and the '\0' characters. */ > + if (size >= (SIZE_MAX - 2)) > + return NULL; > + > + size += 2; > + > + if (size > max) > + return NULL; > + > + /* Append any given suffix */ > + char *to = current + current_size; > + *to++ = '.'; > + strcpy(to, suffix); > + > + return current; > +} > + > +static bool fcontext_is_binary(FILE *fp) > +{ > uint32_t magic; > > - /* append the path suffix if we have one */ > - if (suffix) { > - rc = snprintf(stack_path, sizeof(stack_path), > - "%s.%s", path, suffix); > - if (rc >= (int)sizeof(stack_path)) { > - errno = ENAMETOOLONG; > - return -1; > - } > - path = stack_path; > + size_t len = fread(&magic, sizeof(magic), 1, fp); > + rewind(fp); > + > + return (len && (magic == SELINUX_MAGIC_COMPILED_FCONTEXT)); > +} > + > +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) > + > +static FILE *open_file(const char *path, const char *suffix, > + char *save_path, size_t len, struct stat *sb) > +{ > + unsigned i; > + int rc; > + char stack_path[len]; > + struct file_details *found = NULL; > + > + /* > + * Rolling append of suffix. Try to open with path.suffix then the > + * next as path.suffix.suffix and so forth. > + */ > + struct file_details fdetails[2] = { > + { .suffix = suffix }, > + { .suffix = "bin" } > + }; > + > + rc = snprintf(stack_path, sizeof(stack_path), "%s", path); > + if (rc >= (int) sizeof(stack_path)) { > + errno = ENAMETOOLONG; > + return NULL; > } > > - /* Open the specification file. */ > - fp = fopen(path, "r"); > - if (fp) { > - __fsetlocking(fp, FSETLOCKING_BYCALLER); > + for (i = 0; i < ARRAY_SIZE(fdetails); i++) { > > - if (fstat(fileno(fp), &sb) < 0) > - return -1; > - if (!S_ISREG(sb.st_mode)) { > - errno = EINVAL; > - return -1; > - } > + /* This handles the case if suffix is null */ > + path = rolling_append(stack_path, fdetails[i].suffix, > + sizeof(stack_path)); > + if (!path) > + return NULL; > > - magic = 0; > - if (fread(&magic, sizeof magic, 1, fp) != 1) { > - if (ferror(fp)) { > - errno = EINVAL; > - fclose(fp); > - return -1; > - } > - clearerr(fp); > - } > + rc = stat(path, &fdetails[i].sb); > + if (rc) > + continue; > > - if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) { > - /* file_contexts.bin format */ > - fclose(fp); > - fp = NULL; > - isbinary = true; > - } else { > - rewind(fp); > + /* first file thing found, just take it */ > + if (!found) { > + strcpy(save_path, path); > + found = &fdetails[i]; > + continue; > } > - } else { > + > /* > - * Text file does not exist, so clear the timestamp > - * so that we will always pass the timestamp comparison > - * with the bin file in load_mmap(). > + * Keep picking the newest file found. Where "newest" > + * includes equality. This provides a precedence on > + * secondary suffixes even when the timestamp is the > + * same. Ie choose file_contexts.bin over file_contexts > + * even if the time stamp is the same. > */ > - sb.st_mtime = 0; > + if (fdetails[i].sb.st_mtime >= found->sb.st_mtime) { > + found = &fdetails[i]; > + strcpy(save_path, path); > + } > } > > - rc = load_mmap(rec, path, &sb, isbinary, digest); > - if (rc == 0) > - goto out; > + if (!found) { > + errno = ENOENT; > + return NULL; > + } > > - if (!fp) > - return -1; /* no text or bin file */ > + memcpy(sb, &found->sb, sizeof(*sb)); > + return fopen(save_path, "r"); > +} > > - /* > - * Then do detailed validation of the input and fill the spec array > - */ > - lineno = 0; > - rc = 0; > - while (getline(&line_buf, &line_len, fp) > 0) { > - rc = process_line(rec, path, prefix, line_buf, ++lineno); > - if (rc) > - goto out; > - } > +static int process_file(const char *path, const char *suffix, > + struct selabel_handle *rec, > + const char *prefix, struct selabel_digest *digest) > +{ > + int rc; > + struct stat sb; > + FILE *fp = NULL; > + char found_path[PATH_MAX]; > > - rc = digest_add_specfile(digest, fp, NULL, sb.st_size, path); > + fp = open_file(path, suffix, found_path, sizeof(found_path), &sb); > + if (fp == NULL) > + return -1; > > + rc = fcontext_is_binary(fp) ? > + load_mmap(fp, sb.st_size, rec, found_path) : > + process_text_file(fp, prefix, rec, found_path); > + if (rc < 0) > + goto out; > + > + rc = digest_add_specfile(digest, fp, NULL, sb.st_size, found_path); > out: > - free(line_buf); > - if (fp) > - fclose(fp); > + fclose(fp); > return rc; > } > > _______________________________________________ Selinux mailing list Selinux@xxxxxxxxxxxxx To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx. To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.