libselinux: clean up process file
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@intel.com>
This commit is contained in:
parent
c1d873e971
commit
5e15a52aaa
1 changed files with 174 additions and 152 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
struct file_details {
|
||||
const char *suffix;
|
||||
struct stat sb;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fdetails); i++) {
|
||||
|
||||
/* This handles the case if suffix is null */
|
||||
path = rolling_append(stack_path, fdetails[i].suffix,
|
||||
sizeof(stack_path));
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
rc = stat(path, &fdetails[i].sb);
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
/* first file thing found, just take it */
|
||||
if (!found) {
|
||||
strcpy(save_path, path);
|
||||
found = &fdetails[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (fdetails[i].sb.st_mtime >= found->sb.st_mtime) {
|
||||
found = &fdetails[i];
|
||||
strcpy(save_path, path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(sb, &found->sb, sizeof(*sb));
|
||||
return fopen(save_path, "r");
|
||||
}
|
||||
|
||||
static int process_file(const char *path, const char *suffix,
|
||||
struct selabel_handle *rec,
|
||||
const char *prefix, struct selabel_digest *digest)
|
||||
{
|
||||
FILE *fp;
|
||||
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;
|
||||
uint32_t magic;
|
||||
struct stat sb;
|
||||
FILE *fp = NULL;
|
||||
char found_path[PATH_MAX];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
fp = open_file(path, suffix, found_path, sizeof(found_path), &sb);
|
||||
if (fp == NULL)
|
||||
return -1;
|
||||
|
||||
/* Open the specification file. */
|
||||
fp = fopen(path, "r");
|
||||
if (fp) {
|
||||
__fsetlocking(fp, FSETLOCKING_BYCALLER);
|
||||
|
||||
if (fstat(fileno(fp), &sb) < 0)
|
||||
return -1;
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
magic = 0;
|
||||
if (fread(&magic, sizeof magic, 1, fp) != 1) {
|
||||
if (ferror(fp)) {
|
||||
errno = EINVAL;
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
clearerr(fp);
|
||||
}
|
||||
|
||||
if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) {
|
||||
/* file_contexts.bin format */
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
isbinary = true;
|
||||
} else {
|
||||
rewind(fp);
|
||||
}
|
||||
} 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().
|
||||
*/
|
||||
sb.st_mtime = 0;
|
||||
}
|
||||
|
||||
rc = load_mmap(rec, path, &sb, isbinary, digest);
|
||||
if (rc == 0)
|
||||
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;
|
||||
|
||||
if (!fp)
|
||||
return -1; /* no text or bin file */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
rc = digest_add_specfile(digest, fp, NULL, sb.st_size, path);
|
||||
|
||||
rc = digest_add_specfile(digest, fp, NULL, sb.st_size, found_path);
|
||||
out:
|
||||
free(line_buf);
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue