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", &regex, &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;
}
Пример #2
0
static int load_mmap(struct selabel_handle *rec, const char *path,
						    struct stat *sb)
{
	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;

	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);
	if (addr == MAP_FAILED) {
		free(mmap_area);
		perror("mmap");
		return -1;
	}

	/* save where we mmap'd the file to cleanup on close() */
	mmap_area->addr = addr;
	mmap_area->len = len;
	mmap_area->next = data->mmap_areas;
	data->mmap_areas = mmap_area;

	/* check if this looks like an fcontext file */
	rc = next_entry(&magic, mmap_area, sizeof(uint32_t));
	if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT)
		return -1;

	/* check if this version is higher than we understand */
	rc = next_entry(&version, mmap_area, sizeof(uint32_t));
	if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS)
		return -1;

	if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
		len = strlen(pcre_version());

		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0)
			return -1;

		/* Check version lengths */
		if (len != entry_len)
			return -1;

		/* Check if pcre version mismatch */
		str_buf = malloc(entry_len + 1);
		if (!str_buf)
			return -1;

		rc = next_entry(str_buf, mmap_area, entry_len);
		if (rc < 0) {
			free(str_buf);
			return -1;
		}

		str_buf[entry_len] = '\0';
		if ((strcmp(str_buf, pcre_version()) != 0)) {
			free(str_buf);
			return -1;
		}
		free(str_buf);
	}

	/* allocate the stems_data array */
	rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
	if (rc < 0 || !stem_map_len)
		return -1;

	/*
	 * map indexed by the stem # in the mmap file and contains the stem
	 * number in the data stem_arr
	 */
	stem_map = calloc(stem_map_len, sizeof(*stem_map));
	if (!stem_map)
		return -1;

	for (i = 0; i < stem_map_len; i++) {
		char *buf;
		uint32_t stem_len;
		int newid;

		/* the length does not inlude the nul */
		rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !stem_len) {
			rc = -1;
			goto err;
		}

		/* Check for stem_len wrap around. */
		if (stem_len < UINT32_MAX) {
			buf = (char *)mmap_area->addr;
			/* Check if over-run before null check. */
			rc = next_entry(NULL, mmap_area, (stem_len + 1));
			if (rc < 0)
				goto err;

			if (buf[stem_len] != '\0') {
				rc = -1;
				goto err;
			}
		} else {
			rc = -1;
			goto err;
		}

		/* store the mapping between old and new */
		newid = find_stem(data, buf, stem_len);
		if (newid < 0) {
			newid = store_stem(data, buf, stem_len);
			if (newid < 0) {
				rc = newid;
				goto err;
			}
			data->stem_arr[newid].from_mmap = 1;
		}
		stem_map[i] = newid;
	}

	/* allocate the regex array */
	rc = next_entry(&regex_array_len, mmap_area, sizeof(uint32_t));
	if (rc < 0 || !regex_array_len) {
		rc = -1;
		goto err;
	}

	for (i = 0; i < regex_array_len; i++) {
		struct spec *spec;
		int32_t stem_id, meta_chars;
		uint32_t mode = 0, prefix_len = 0;

		rc = grow_specs(data);
		if (rc < 0)
			goto err;

		spec = &data->spec_arr[data->nspec];
		spec->from_mmap = 1;
		spec->regcomp = 1;

		/* Process context */
		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !entry_len) {
			rc = -1;
			goto err;
		}

		str_buf = malloc(entry_len);
		if (!str_buf) {
			rc = -1;
			goto err;
		}
		rc = next_entry(str_buf, mmap_area, entry_len);
		if (rc < 0)
			goto err;

		if (str_buf[entry_len - 1] != '\0') {
			free(str_buf);
			rc = -1;
			goto err;
		}
		spec->lr.ctx_raw = str_buf;

		/* Process regex string */
		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !entry_len) {
			rc = -1;
			goto err;
		}

		spec->regex_str = (char *)mmap_area->addr;
		rc = next_entry(NULL, mmap_area, entry_len);
		if (rc < 0)
			goto err;

		if (spec->regex_str[entry_len - 1] != '\0') {
			rc = -1;
			goto err;
		}

		/* Process mode */
		if (version >= SELINUX_COMPILED_FCONTEXT_MODE)
			rc = next_entry(&mode, mmap_area, sizeof(uint32_t));
		else
			rc = next_entry(&mode, mmap_area, sizeof(mode_t));
		if (rc < 0)
			goto err;

		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;

		if (stem_id < 0 || stem_id >= (int32_t)stem_map_len)
			spec->stem_id = -1;
		 else
			spec->stem_id = stem_map[stem_id];

		/* retrieve the hasMetaChars bit */
		rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t));
		if (rc < 0)
			goto err;

		spec->hasMetaChars = meta_chars;
		/* and prefix length for use by selabel_lookup_best_match */
		if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) {
			rc = next_entry(&prefix_len, mmap_area,
					    sizeof(uint32_t));
			if (rc < 0)
				goto err;

			spec->prefix_len = prefix_len;
		}

		/* Process regex and study_data entries */
		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !entry_len) {
			rc = -1;
			goto err;
		}
		spec->regex = (pcre *)mmap_area->addr;
		rc = next_entry(NULL, mmap_area, entry_len);
		if (rc < 0)
			goto err;

		/* 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;
		}

		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !entry_len) {
			rc = -1;
			goto err;
		}
		spec->lsd.study_data = (void *)mmap_area->addr;
		spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA;
		rc = next_entry(NULL, mmap_area, entry_len);
		if (rc < 0)
			goto err;

		/* 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;
		}

		data->nspec++;
	}
	/* win */
	rc = 0;
err:
	free(stem_map);

	return rc;
}
Пример #3
0
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;
	int rc;
	char *addr, *str_buf;
	int *stem_map;
	struct mmap_area *mmap_area;
	uint32_t i, magic, version;
	uint32_t entry_len, stem_map_len, regex_array_len;
	const char *reg_version;
	const char *reg_arch;
	char reg_arch_matches = 0;

	mmap_area = malloc(sizeof(*mmap_area));
	if (!mmap_area) {
		return -1;
	}

	addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
	if (addr == MAP_FAILED) {
		free(mmap_area);
		perror("mmap");
		return -1;
	}

	/* save where we mmap'd the file to cleanup on close() */
	mmap_area->addr = mmap_area->next_addr = addr;
	mmap_area->len = mmap_area->next_len = len;
	mmap_area->next = data->mmap_areas;
	data->mmap_areas = mmap_area;

	/* check if this looks like an fcontext file */
	rc = next_entry(&magic, mmap_area, sizeof(uint32_t));
	if (rc < 0 || magic != SELINUX_MAGIC_COMPILED_FCONTEXT)
		return -1;

	/* check if this version is higher than we understand */
	rc = next_entry(&version, mmap_area, sizeof(uint32_t));
	if (rc < 0 || version > SELINUX_COMPILED_FCONTEXT_MAX_VERS)
		return -1;

	reg_version = regex_version();
	if (!reg_version)
		return -1;

	reg_arch = regex_arch_string();
	if (!reg_arch)
		return -1;

	if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {

		len = strlen(reg_version);

		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0)
			return -1;

		/* Check version lengths */
		if (len != entry_len)
			return -1;

		/* Check if regex version mismatch */
		str_buf = malloc(entry_len + 1);
		if (!str_buf)
			return -1;

		rc = next_entry(str_buf, mmap_area, entry_len);
		if (rc < 0) {
			free(str_buf);
			return -1;
		}

		str_buf[entry_len] = '\0';
		if ((strcmp(str_buf, reg_version) != 0)) {
			free(str_buf);
			return -1;
		}
		free(str_buf);

		if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
			len = strlen(reg_arch);

			rc = next_entry(&entry_len, mmap_area,
					sizeof(uint32_t));
			if (rc < 0)
				return -1;

			/* Check arch string lengths */
			if (len != entry_len) {
				/*
				 * Skip the entry and conclude that we have
				 * a mismatch, which is not fatal.
				 */
				next_entry(NULL, mmap_area, entry_len);
				goto end_arch_check;
			}

			/* Check if arch string mismatch */
			str_buf = malloc(entry_len + 1);
			if (!str_buf)
				return -1;

			rc = next_entry(str_buf, mmap_area, entry_len);
			if (rc < 0) {
				free(str_buf);
				return -1;
			}

			str_buf[entry_len] = '\0';
			reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
			free(str_buf);
		}
	}
end_arch_check:

	/* allocate the stems_data array */
	rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
	if (rc < 0)
		return -1;

	/*
	 * map indexed by the stem # in the mmap file and contains the stem
	 * number in the data stem_arr
	 */
	stem_map = calloc(stem_map_len, sizeof(*stem_map));
	if (!stem_map)
		return -1;

	for (i = 0; i < stem_map_len; i++) {
		char *buf;
		uint32_t stem_len;
		int newid;

		/* the length does not inlude the nul */
		rc = next_entry(&stem_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !stem_len) {
			rc = -1;
			goto out;
		}

		/* Check for stem_len wrap around. */
		if (stem_len < UINT32_MAX) {
			buf = (char *)mmap_area->next_addr;
			/* Check if over-run before null check. */
			rc = next_entry(NULL, mmap_area, (stem_len + 1));
			if (rc < 0)
				goto out;

			if (buf[stem_len] != '\0') {
				rc = -1;
				goto out;
			}
		} else {
			rc = -1;
			goto out;
		}

		/* store the mapping between old and new */
		newid = find_stem(data, buf, stem_len);
		if (newid < 0) {
			newid = store_stem(data, buf, stem_len);
			if (newid < 0) {
				rc = newid;
				goto out;
			}
			data->stem_arr[newid].from_mmap = 1;
		}
		stem_map[i] = newid;
	}

	/* allocate the regex array */
	rc = next_entry(&regex_array_len, mmap_area, sizeof(uint32_t));
	if (rc < 0 || !regex_array_len) {
		rc = -1;
		goto out;
	}

	for (i = 0; i < regex_array_len; i++) {
		struct spec *spec;
		int32_t stem_id, meta_chars;
		uint32_t mode = 0, prefix_len = 0;

		rc = grow_specs(data);
		if (rc < 0)
			goto out;

		spec = &data->spec_arr[data->nspec];
		spec->from_mmap = 1;

		/* Process context */
		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !entry_len) {
			rc = -1;
			goto out;
		}

		str_buf = malloc(entry_len);
		if (!str_buf) {
			rc = -1;
			goto out;
		}
		rc = next_entry(str_buf, mmap_area, entry_len);
		if (rc < 0) {
			free(str_buf);
			goto out;
		}

		if (str_buf[entry_len - 1] != '\0') {
			free(str_buf);
			rc = -1;
			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",
					    path, spec->lr.ctx_raw);
				goto out;
			}
		}

		/* Process regex string */
		rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
		if (rc < 0 || !entry_len) {
			rc = -1;
			goto out;
		}

		spec->regex_str = (char *)mmap_area->next_addr;
		rc = next_entry(NULL, mmap_area, entry_len);
		if (rc < 0)
			goto out;

		if (spec->regex_str[entry_len - 1] != '\0') {
			rc = -1;
			goto out;
		}

		/* Process mode */
		if (version >= SELINUX_COMPILED_FCONTEXT_MODE)
			rc = next_entry(&mode, mmap_area, sizeof(uint32_t));
		else
			rc = next_entry(&mode, mmap_area, sizeof(mode_t));
		if (rc < 0)
			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 out;

		if (stem_id < 0 || stem_id >= (int32_t)stem_map_len)
			spec->stem_id = -1;
		 else
			spec->stem_id = stem_map[stem_id];

		/* retrieve the hasMetaChars bit */
		rc = next_entry(&meta_chars, mmap_area, sizeof(uint32_t));
		if (rc < 0)
			goto out;

		spec->hasMetaChars = meta_chars;
		/* and prefix length for use by selabel_lookup_best_match */
		if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) {
			rc = next_entry(&prefix_len, mmap_area,
					    sizeof(uint32_t));
			if (rc < 0)
				goto out;

			spec->prefix_len = prefix_len;
		}

		rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches,
				     &spec->regex_compiled);
		if (rc < 0)
			goto out;

		__pthread_mutex_init(&spec->regex_lock, NULL);
		data->nspec++;
	}

	rc = 0;
out:
	free(stem_map);

	return rc;
}