libselinux: utils: new file context regex compiler
This is a new 'compiler' which tranforms the file context database into a binary format. This binary format may be mmap'd in later removing the need to compile the regular expression at run time. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Dan Walsh <dwalsh@redhat.com>
This commit is contained in:
parent
a29f6820c5
commit
dac8b32c17
|
@ -13,6 +13,7 @@ getsebool
|
|||
getseuser
|
||||
matchpathcon
|
||||
policyvers
|
||||
sefcontext_compile
|
||||
selinux_check_securetty_context
|
||||
selinuxenabled
|
||||
selinuxexeccon
|
||||
|
|
|
@ -28,6 +28,7 @@ LDLIBS += -L../src -lselinux -L$(LIBDIR)
|
|||
|
||||
TARGETS=$(patsubst %.c,%,$(wildcard *.c))
|
||||
|
||||
sefcontext_compile: LDLIBS += -lpcre
|
||||
|
||||
ifeq ($(DISABLE_AVC),y)
|
||||
UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <pcre.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include "../src/label_file.h"
|
||||
|
||||
static int process_file(struct saved_data *data, const char *filename)
|
||||
{
|
||||
struct spec *spec;
|
||||
unsigned int line_num;
|
||||
char *line_buf = NULL;
|
||||
size_t line_len;
|
||||
ssize_t len;
|
||||
FILE *context_file;
|
||||
|
||||
context_file = fopen(filename, "r");
|
||||
if (!context_file)
|
||||
return -1;
|
||||
|
||||
line_num = 0;
|
||||
while ((len = getline(&line_buf, &line_len, context_file)) != -1) {
|
||||
char *context;
|
||||
char *mode;
|
||||
char *regex;
|
||||
char *cp, *anchored_regex;
|
||||
char *buf_p;
|
||||
pcre *re;
|
||||
pcre_extra *sd;
|
||||
const char *err;
|
||||
int items, erroff, rc;
|
||||
size_t regex_len;
|
||||
int32_t stem_id;
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
items = sscanf(line_buf, "%ms %ms %ms", ®ex, &mode, &context);
|
||||
if (items < 2 || items > 3) {
|
||||
fprintf(stderr, "invalid entry, skipping:%s", line_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (items == 2) {
|
||||
context = mode;
|
||||
mode = NULL;
|
||||
}
|
||||
|
||||
rc = grow_specs(data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
spec = &data->spec_arr[data->nspec];
|
||||
|
||||
spec->lr.ctx_raw = context;
|
||||
spec->mode = string_to_mode(mode);
|
||||
if (spec->mode == -1) {
|
||||
fprintf(stderr, "%s: line %d has invalid file type %s\n",
|
||||
regex, line_num + 1, mode);
|
||||
spec->mode = 0;
|
||||
}
|
||||
free(mode);
|
||||
spec->regex_str = regex;
|
||||
|
||||
stem_id = find_stem_from_spec(data, regex);
|
||||
spec->stem_id = stem_id;
|
||||
/* skip past the fixed stem part */
|
||||
if (stem_id != -1)
|
||||
regex += data->stem_arr[stem_id].len;
|
||||
|
||||
regex_len = strlen(regex);
|
||||
cp = anchored_regex = malloc(regex_len + 3);
|
||||
if (!cp)
|
||||
return -1;
|
||||
|
||||
*cp++ = '^';
|
||||
memcpy(cp, regex, regex_len);
|
||||
cp += regex_len;
|
||||
*cp++ = '$';
|
||||
*cp = '\0';
|
||||
|
||||
spec_hasMetaChars(spec);
|
||||
|
||||
re = pcre_compile(anchored_regex, 0, &err, &erroff, NULL);
|
||||
if (!re) {
|
||||
fprintf(stderr, "PCRE compilation failed for %s at offset %d: %s\n", anchored_regex, erroff, err);
|
||||
return -1;
|
||||
}
|
||||
spec->regex = re;
|
||||
|
||||
sd = pcre_study(re, 0, &err);
|
||||
if (!sd) {
|
||||
fprintf(stderr, "PCRE study failed for %s: %s\n", anchored_regex, err);
|
||||
return -1;
|
||||
}
|
||||
free(anchored_regex);
|
||||
spec->sd = sd;
|
||||
|
||||
line_num++;
|
||||
data->nspec++;
|
||||
}
|
||||
|
||||
free(line_buf);
|
||||
fclose(context_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* File Format
|
||||
*
|
||||
* u32 - magic number
|
||||
* u32 - version
|
||||
* 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.
|
||||
* mode_t - mode bits
|
||||
* s32 - stemid associated with the regex
|
||||
* u32 - spec has meta characters
|
||||
* 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, char *filename)
|
||||
{
|
||||
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;
|
||||
|
||||
bin_file = fopen(filename, "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)
|
||||
return -1;
|
||||
|
||||
/* write the version */
|
||||
section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS;
|
||||
len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
/* write the number of stems coming */
|
||||
section_len = data->num_stems;
|
||||
len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
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)
|
||||
return -1;
|
||||
|
||||
/* include the nul in the file */
|
||||
stem_len += 1;
|
||||
len = fwrite(stem, sizeof(char), stem_len, bin_file);
|
||||
if (len != stem_len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* write the number of regexes coming */
|
||||
section_len = data->nspec;
|
||||
len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
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;
|
||||
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;
|
||||
int rc;
|
||||
|
||||
/* 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)
|
||||
return -1;
|
||||
|
||||
/* original context strin (including nul) */
|
||||
len = fwrite(context, sizeof(char), to_write, bin_file);
|
||||
if (len != to_write)
|
||||
return -1;
|
||||
|
||||
/* 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)
|
||||
return -1;
|
||||
|
||||
/* original regex string */
|
||||
len = fwrite(regex_str, sizeof(char), to_write, bin_file);
|
||||
if (len != to_write)
|
||||
return -1;
|
||||
|
||||
/* binary F_MODE bits */
|
||||
len = fwrite(&mode, sizeof(mode), 1, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
/* stem for this regex (could be -1) */
|
||||
len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
/* does this spec have a metaChar? */
|
||||
to_write = specs[i].hasMetaChars;
|
||||
len = fwrite(&to_write, sizeof(to_write), 1, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
/* determine the size of the pcre data in bytes */
|
||||
rc = pcre_fullinfo(re, 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, bin_file);
|
||||
if (len != 1)
|
||||
return -1;
|
||||
|
||||
/* write the actual pcre data as a char array */
|
||||
len = fwrite(re, 1, to_write, bin_file);
|
||||
if (len != to_write)
|
||||
return -1;
|
||||
|
||||
/* determine the size of the pcre study info */
|
||||
rc = pcre_fullinfo(re, sd, PCRE_INFO_STUDYSIZE, &size);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
/* 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)
|
||||
return -1;
|
||||
|
||||
/* write the actual pcre study data as a char array */
|
||||
len = fwrite(sd->study_data, 1, to_write, bin_file);
|
||||
if (len != to_write)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(bin_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int free_specs(struct saved_data *data)
|
||||
{
|
||||
struct spec *specs = data->spec_arr;
|
||||
unsigned int num_entries = data->nspec;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
free(specs[i].lr.ctx_raw);
|
||||
free(specs[i].lr.ctx_trans);
|
||||
free(specs[i].regex_str);
|
||||
pcre_free(specs[i].regex);
|
||||
pcre_free_study(specs[i].sd);
|
||||
}
|
||||
free(specs);
|
||||
|
||||
num_entries = data->num_stems;
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
free(data->stem_arr[i].buf);
|
||||
}
|
||||
free(data->stem_arr);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct saved_data data;
|
||||
const char *path;
|
||||
char stack_path[PATH_MAX + 1];
|
||||
int rc;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s input_file\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
path = argv[1];
|
||||
|
||||
rc = process_file(&data, path);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sort_specs(&data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
|
||||
if (rc < 0 || rc >= sizeof(stack_path))
|
||||
return rc;
|
||||
rc = write_binary_file(&data, stack_path);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = free_specs(&data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue