mirror of
https://github.com/SELinuxProject/selinux
synced 2024-12-24 15:02:44 +00:00
70b23853a8
Currently the compiled file context files can end up with different permissions then the original. This can lead to non priv users not being able to read the compiled versions.
399 lines
8.8 KiB
C
399 lines
8.8 KiB
C
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <pcre.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.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) {
|
|
fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno));
|
|
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) {
|
|
fprintf(stderr, "grow_specs failed: %s\n", strerror(errno));
|
|
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) {
|
|
fprintf(stderr, "Malloc Failed: %s\n", strerror(errno));
|
|
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 - 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.
|
|
* 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, 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;
|
|
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 */
|
|
len = fwrite(&mode, sizeof(mode), 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;
|
|
|
|
/* 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 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;
|
|
char *tmp= NULL;
|
|
int fd;
|
|
struct stat buf;
|
|
|
|
if (argc != 2) {
|
|
fprintf(stderr, "usage: %s input_file\n", argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
path = argv[1];
|
|
|
|
if (stat(path, &buf) < 0) {
|
|
fprintf(stderr, "Can not stat: %s: %m\n", path);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
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;
|
|
|
|
if (asprintf(&tmp, "%sXXXXXX", stack_path) < 0)
|
|
return -1;
|
|
|
|
fd = mkstemp(tmp);
|
|
if (fd < 0)
|
|
goto err;
|
|
|
|
rc = fchmod(fd, buf.st_mode);
|
|
if (rc < 0) {
|
|
perror("fchmod failed to set permission on compiled regexs");
|
|
goto err;
|
|
}
|
|
|
|
rc = write_binary_file(&data, fd);
|
|
|
|
if (rc < 0)
|
|
goto err;
|
|
|
|
rename(tmp, stack_path);
|
|
rc = free_specs(&data);
|
|
if (rc < 0)
|
|
goto err;
|
|
|
|
rc = 0;
|
|
out:
|
|
free(tmp);
|
|
return rc;
|
|
err:
|
|
rc = -1;
|
|
goto out;
|
|
}
|