16cd6a6acSopenharmony_ci/* Author: Karl MacMillan <kmacmillan@tresys.com>
26cd6a6acSopenharmony_ci *         Jason Tang     <jtang@tresys.com>
36cd6a6acSopenharmony_ci *         Chris PeBenito <cpebenito@tresys.com>
46cd6a6acSopenharmony_ci *
56cd6a6acSopenharmony_ci * Copyright (C) 2004-2005 Tresys Technology, LLC
66cd6a6acSopenharmony_ci *
76cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
86cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
96cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
106cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
116cd6a6acSopenharmony_ci *
126cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
136cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
146cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
156cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
166cd6a6acSopenharmony_ci *
176cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
186cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
196cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
206cd6a6acSopenharmony_ci */
216cd6a6acSopenharmony_ci
226cd6a6acSopenharmony_ci#include "policydb_internal.h"
236cd6a6acSopenharmony_ci#include "module_internal.h"
246cd6a6acSopenharmony_ci#include <sepol/policydb/link.h>
256cd6a6acSopenharmony_ci#include <sepol/policydb/expand.h>
266cd6a6acSopenharmony_ci#include <sepol/policydb/module.h>
276cd6a6acSopenharmony_ci#include "debug.h"
286cd6a6acSopenharmony_ci#include "private.h"
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci#include <stdio.h>
316cd6a6acSopenharmony_ci#include <stdlib.h>
326cd6a6acSopenharmony_ci#include <limits.h>
336cd6a6acSopenharmony_ci#include <inttypes.h>
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ci#define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
366cd6a6acSopenharmony_ci#define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
376cd6a6acSopenharmony_ci#define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
386cd6a6acSopenharmony_ci#define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
396cd6a6acSopenharmony_ci
406cd6a6acSopenharmony_cistatic int policy_file_seek(struct policy_file *fp, size_t offset)
416cd6a6acSopenharmony_ci{
426cd6a6acSopenharmony_ci	switch (fp->type) {
436cd6a6acSopenharmony_ci	case PF_USE_STDIO:
446cd6a6acSopenharmony_ci		if (offset > LONG_MAX) {
456cd6a6acSopenharmony_ci			errno = EFAULT;
466cd6a6acSopenharmony_ci			return -1;
476cd6a6acSopenharmony_ci		}
486cd6a6acSopenharmony_ci		return fseek(fp->fp, (long)offset, SEEK_SET);
496cd6a6acSopenharmony_ci	case PF_USE_MEMORY:
506cd6a6acSopenharmony_ci		if (offset > fp->size) {
516cd6a6acSopenharmony_ci			errno = EFAULT;
526cd6a6acSopenharmony_ci			return -1;
536cd6a6acSopenharmony_ci		}
546cd6a6acSopenharmony_ci		fp->data -= fp->size - fp->len;
556cd6a6acSopenharmony_ci		fp->data += offset;
566cd6a6acSopenharmony_ci		fp->len = fp->size - offset;
576cd6a6acSopenharmony_ci		return 0;
586cd6a6acSopenharmony_ci	default:
596cd6a6acSopenharmony_ci		return 0;
606cd6a6acSopenharmony_ci	}
616cd6a6acSopenharmony_ci}
626cd6a6acSopenharmony_ci
636cd6a6acSopenharmony_cistatic int policy_file_length(struct policy_file *fp, size_t *out)
646cd6a6acSopenharmony_ci{
656cd6a6acSopenharmony_ci	long prev_offset, end_offset;
666cd6a6acSopenharmony_ci	int rc;
676cd6a6acSopenharmony_ci	switch (fp->type) {
686cd6a6acSopenharmony_ci	case PF_USE_STDIO:
696cd6a6acSopenharmony_ci		prev_offset = ftell(fp->fp);
706cd6a6acSopenharmony_ci		if (prev_offset < 0)
716cd6a6acSopenharmony_ci			return prev_offset;
726cd6a6acSopenharmony_ci		rc = fseek(fp->fp, 0L, SEEK_END);
736cd6a6acSopenharmony_ci		if (rc < 0)
746cd6a6acSopenharmony_ci			return rc;
756cd6a6acSopenharmony_ci		end_offset = ftell(fp->fp);
766cd6a6acSopenharmony_ci		if (end_offset < 0)
776cd6a6acSopenharmony_ci			return end_offset;
786cd6a6acSopenharmony_ci		rc = fseek(fp->fp, prev_offset, SEEK_SET);
796cd6a6acSopenharmony_ci		if (rc < 0)
806cd6a6acSopenharmony_ci			return rc;
816cd6a6acSopenharmony_ci		*out = end_offset;
826cd6a6acSopenharmony_ci		break;
836cd6a6acSopenharmony_ci	case PF_USE_MEMORY:
846cd6a6acSopenharmony_ci		*out = fp->size;
856cd6a6acSopenharmony_ci		break;
866cd6a6acSopenharmony_ci	default:
876cd6a6acSopenharmony_ci		*out = 0;
886cd6a6acSopenharmony_ci		break;
896cd6a6acSopenharmony_ci	}
906cd6a6acSopenharmony_ci	return 0;
916cd6a6acSopenharmony_ci}
926cd6a6acSopenharmony_ci
936cd6a6acSopenharmony_cistatic int module_package_init(sepol_module_package_t * p)
946cd6a6acSopenharmony_ci{
956cd6a6acSopenharmony_ci	memset(p, 0, sizeof(sepol_module_package_t));
966cd6a6acSopenharmony_ci	if (sepol_policydb_create(&p->policy))
976cd6a6acSopenharmony_ci		return -1;
986cd6a6acSopenharmony_ci
996cd6a6acSopenharmony_ci	p->version = 1;
1006cd6a6acSopenharmony_ci	return 0;
1016cd6a6acSopenharmony_ci}
1026cd6a6acSopenharmony_ci
1036cd6a6acSopenharmony_cistatic int set_char(char **field, char *data, size_t len)
1046cd6a6acSopenharmony_ci{
1056cd6a6acSopenharmony_ci	if (*field) {
1066cd6a6acSopenharmony_ci		free(*field);
1076cd6a6acSopenharmony_ci		*field = NULL;
1086cd6a6acSopenharmony_ci	}
1096cd6a6acSopenharmony_ci	if (len) {
1106cd6a6acSopenharmony_ci		*field = malloc(len);
1116cd6a6acSopenharmony_ci		if (!*field)
1126cd6a6acSopenharmony_ci			return -1;
1136cd6a6acSopenharmony_ci		memcpy(*field, data, len);
1146cd6a6acSopenharmony_ci	}
1156cd6a6acSopenharmony_ci	return 0;
1166cd6a6acSopenharmony_ci}
1176cd6a6acSopenharmony_ci
1186cd6a6acSopenharmony_ciint sepol_module_package_create(sepol_module_package_t ** p)
1196cd6a6acSopenharmony_ci{
1206cd6a6acSopenharmony_ci	int rc;
1216cd6a6acSopenharmony_ci
1226cd6a6acSopenharmony_ci	*p = calloc(1, sizeof(sepol_module_package_t));
1236cd6a6acSopenharmony_ci	if (!(*p))
1246cd6a6acSopenharmony_ci		return -1;
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ci	rc = module_package_init(*p);
1276cd6a6acSopenharmony_ci	if (rc < 0) {
1286cd6a6acSopenharmony_ci		free(*p);
1296cd6a6acSopenharmony_ci		*p = NULL;
1306cd6a6acSopenharmony_ci	}
1316cd6a6acSopenharmony_ci
1326cd6a6acSopenharmony_ci	return rc;
1336cd6a6acSopenharmony_ci}
1346cd6a6acSopenharmony_ci
1356cd6a6acSopenharmony_ci
1366cd6a6acSopenharmony_ci/* Deallocates all memory associated with a module package, including
1376cd6a6acSopenharmony_ci * the pointer itself.  Does nothing if p is NULL.
1386cd6a6acSopenharmony_ci */
1396cd6a6acSopenharmony_civoid sepol_module_package_free(sepol_module_package_t * p)
1406cd6a6acSopenharmony_ci{
1416cd6a6acSopenharmony_ci	if (p == NULL)
1426cd6a6acSopenharmony_ci		return;
1436cd6a6acSopenharmony_ci
1446cd6a6acSopenharmony_ci	sepol_policydb_free(p->policy);
1456cd6a6acSopenharmony_ci	free(p->file_contexts);
1466cd6a6acSopenharmony_ci	free(p->seusers);
1476cd6a6acSopenharmony_ci	free(p->user_extra);
1486cd6a6acSopenharmony_ci	free(p->netfilter_contexts);
1496cd6a6acSopenharmony_ci	free(p);
1506cd6a6acSopenharmony_ci}
1516cd6a6acSopenharmony_ci
1526cd6a6acSopenharmony_ci
1536cd6a6acSopenharmony_cichar *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
1546cd6a6acSopenharmony_ci{
1556cd6a6acSopenharmony_ci	return p->file_contexts;
1566cd6a6acSopenharmony_ci}
1576cd6a6acSopenharmony_ci
1586cd6a6acSopenharmony_cisize_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
1596cd6a6acSopenharmony_ci{
1606cd6a6acSopenharmony_ci	return p->file_contexts_len;
1616cd6a6acSopenharmony_ci}
1626cd6a6acSopenharmony_ci
1636cd6a6acSopenharmony_cichar *sepol_module_package_get_seusers(sepol_module_package_t * p)
1646cd6a6acSopenharmony_ci{
1656cd6a6acSopenharmony_ci	return p->seusers;
1666cd6a6acSopenharmony_ci}
1676cd6a6acSopenharmony_ci
1686cd6a6acSopenharmony_cisize_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
1696cd6a6acSopenharmony_ci{
1706cd6a6acSopenharmony_ci	return p->seusers_len;
1716cd6a6acSopenharmony_ci}
1726cd6a6acSopenharmony_ci
1736cd6a6acSopenharmony_cichar *sepol_module_package_get_user_extra(sepol_module_package_t * p)
1746cd6a6acSopenharmony_ci{
1756cd6a6acSopenharmony_ci	return p->user_extra;
1766cd6a6acSopenharmony_ci}
1776cd6a6acSopenharmony_ci
1786cd6a6acSopenharmony_cisize_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
1796cd6a6acSopenharmony_ci{
1806cd6a6acSopenharmony_ci	return p->user_extra_len;
1816cd6a6acSopenharmony_ci}
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_cichar *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
1846cd6a6acSopenharmony_ci{
1856cd6a6acSopenharmony_ci	return p->netfilter_contexts;
1866cd6a6acSopenharmony_ci}
1876cd6a6acSopenharmony_ci
1886cd6a6acSopenharmony_cisize_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
1896cd6a6acSopenharmony_ci						       p)
1906cd6a6acSopenharmony_ci{
1916cd6a6acSopenharmony_ci	return p->netfilter_contexts_len;
1926cd6a6acSopenharmony_ci}
1936cd6a6acSopenharmony_ci
1946cd6a6acSopenharmony_ciint sepol_module_package_set_file_contexts(sepol_module_package_t * p,
1956cd6a6acSopenharmony_ci					   char *data, size_t len)
1966cd6a6acSopenharmony_ci{
1976cd6a6acSopenharmony_ci	if (set_char(&p->file_contexts, data, len))
1986cd6a6acSopenharmony_ci		return -1;
1996cd6a6acSopenharmony_ci
2006cd6a6acSopenharmony_ci	p->file_contexts_len = len;
2016cd6a6acSopenharmony_ci	return 0;
2026cd6a6acSopenharmony_ci}
2036cd6a6acSopenharmony_ci
2046cd6a6acSopenharmony_ciint sepol_module_package_set_seusers(sepol_module_package_t * p,
2056cd6a6acSopenharmony_ci				     char *data, size_t len)
2066cd6a6acSopenharmony_ci{
2076cd6a6acSopenharmony_ci	if (set_char(&p->seusers, data, len))
2086cd6a6acSopenharmony_ci		return -1;
2096cd6a6acSopenharmony_ci
2106cd6a6acSopenharmony_ci	p->seusers_len = len;
2116cd6a6acSopenharmony_ci	return 0;
2126cd6a6acSopenharmony_ci}
2136cd6a6acSopenharmony_ci
2146cd6a6acSopenharmony_ciint sepol_module_package_set_user_extra(sepol_module_package_t * p,
2156cd6a6acSopenharmony_ci					char *data, size_t len)
2166cd6a6acSopenharmony_ci{
2176cd6a6acSopenharmony_ci	if (set_char(&p->user_extra, data, len))
2186cd6a6acSopenharmony_ci		return -1;
2196cd6a6acSopenharmony_ci
2206cd6a6acSopenharmony_ci	p->user_extra_len = len;
2216cd6a6acSopenharmony_ci	return 0;
2226cd6a6acSopenharmony_ci}
2236cd6a6acSopenharmony_ci
2246cd6a6acSopenharmony_ciint sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
2256cd6a6acSopenharmony_ci						char *data, size_t len)
2266cd6a6acSopenharmony_ci{
2276cd6a6acSopenharmony_ci	if (set_char(&p->netfilter_contexts, data, len))
2286cd6a6acSopenharmony_ci		return -1;
2296cd6a6acSopenharmony_ci
2306cd6a6acSopenharmony_ci	p->netfilter_contexts_len = len;
2316cd6a6acSopenharmony_ci	return 0;
2326cd6a6acSopenharmony_ci}
2336cd6a6acSopenharmony_ci
2346cd6a6acSopenharmony_cisepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
2356cd6a6acSopenharmony_ci{
2366cd6a6acSopenharmony_ci	return p->policy;
2376cd6a6acSopenharmony_ci}
2386cd6a6acSopenharmony_ci
2396cd6a6acSopenharmony_ci/* Append each of the file contexts from each module to the base
2406cd6a6acSopenharmony_ci * policy's file context.  'base_context' will be reallocated to a
2416cd6a6acSopenharmony_ci * larger size (and thus it is an in/out reference
2426cd6a6acSopenharmony_ci * variable). 'base_fc_len' is the length of base's file context; it
2436cd6a6acSopenharmony_ci * too is a reference variable.  Return 0 on success, -1 if out of
2446cd6a6acSopenharmony_ci * memory. */
2456cd6a6acSopenharmony_cistatic int link_file_contexts(sepol_module_package_t * base,
2466cd6a6acSopenharmony_ci			      sepol_module_package_t ** modules,
2476cd6a6acSopenharmony_ci			      int num_modules)
2486cd6a6acSopenharmony_ci{
2496cd6a6acSopenharmony_ci	size_t fc_len;
2506cd6a6acSopenharmony_ci	int i;
2516cd6a6acSopenharmony_ci	char *s;
2526cd6a6acSopenharmony_ci
2536cd6a6acSopenharmony_ci	fc_len = base->file_contexts_len;
2546cd6a6acSopenharmony_ci	for (i = 0; i < num_modules; i++) {
2556cd6a6acSopenharmony_ci		fc_len += modules[i]->file_contexts_len;
2566cd6a6acSopenharmony_ci	}
2576cd6a6acSopenharmony_ci
2586cd6a6acSopenharmony_ci	if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
2596cd6a6acSopenharmony_ci		return -1;
2606cd6a6acSopenharmony_ci	}
2616cd6a6acSopenharmony_ci	base->file_contexts = s;
2626cd6a6acSopenharmony_ci	for (i = 0; i < num_modules; i++) {
2636cd6a6acSopenharmony_ci		memcpy(base->file_contexts + base->file_contexts_len,
2646cd6a6acSopenharmony_ci		       modules[i]->file_contexts,
2656cd6a6acSopenharmony_ci		       modules[i]->file_contexts_len);
2666cd6a6acSopenharmony_ci		base->file_contexts_len += modules[i]->file_contexts_len;
2676cd6a6acSopenharmony_ci	}
2686cd6a6acSopenharmony_ci	return 0;
2696cd6a6acSopenharmony_ci}
2706cd6a6acSopenharmony_ci
2716cd6a6acSopenharmony_ci/* Append each of the netfilter contexts from each module to the base
2726cd6a6acSopenharmony_ci * policy's netfilter context.  'base_context' will be reallocated to a
2736cd6a6acSopenharmony_ci * larger size (and thus it is an in/out reference
2746cd6a6acSopenharmony_ci * variable). 'base_nc_len' is the length of base's netfilter contexts; it
2756cd6a6acSopenharmony_ci * too is a reference variable.  Return 0 on success, -1 if out of
2766cd6a6acSopenharmony_ci * memory. */
2776cd6a6acSopenharmony_cistatic int link_netfilter_contexts(sepol_module_package_t * base,
2786cd6a6acSopenharmony_ci				   sepol_module_package_t ** modules,
2796cd6a6acSopenharmony_ci				   int num_modules)
2806cd6a6acSopenharmony_ci{
2816cd6a6acSopenharmony_ci	size_t base_nc_len;
2826cd6a6acSopenharmony_ci	int i;
2836cd6a6acSopenharmony_ci	char *base_context;
2846cd6a6acSopenharmony_ci
2856cd6a6acSopenharmony_ci	base_nc_len = base->netfilter_contexts_len;
2866cd6a6acSopenharmony_ci	for (i = 0; i < num_modules; i++) {
2876cd6a6acSopenharmony_ci		base_nc_len += modules[i]->netfilter_contexts_len;
2886cd6a6acSopenharmony_ci	}
2896cd6a6acSopenharmony_ci
2906cd6a6acSopenharmony_ci	if ((base_context =
2916cd6a6acSopenharmony_ci	     (char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
2926cd6a6acSopenharmony_ci		return -1;
2936cd6a6acSopenharmony_ci	}
2946cd6a6acSopenharmony_ci	base->netfilter_contexts = base_context;
2956cd6a6acSopenharmony_ci	for (i = 0; i < num_modules; i++) {
2966cd6a6acSopenharmony_ci		if (modules[i]->netfilter_contexts_len > 0) {
2976cd6a6acSopenharmony_ci			memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
2986cd6a6acSopenharmony_ci			       modules[i]->netfilter_contexts,
2996cd6a6acSopenharmony_ci			       modules[i]->netfilter_contexts_len);
3006cd6a6acSopenharmony_ci			base->netfilter_contexts_len +=
3016cd6a6acSopenharmony_ci			    modules[i]->netfilter_contexts_len;
3026cd6a6acSopenharmony_ci		}
3036cd6a6acSopenharmony_ci
3046cd6a6acSopenharmony_ci	}
3056cd6a6acSopenharmony_ci	return 0;
3066cd6a6acSopenharmony_ci}
3076cd6a6acSopenharmony_ci
3086cd6a6acSopenharmony_ci/* Links the module packages into the base.  Returns 0 on success, -1
3096cd6a6acSopenharmony_ci * if a requirement was not met, or -2 for all other errors. */
3106cd6a6acSopenharmony_ciint sepol_link_packages(sepol_handle_t * handle,
3116cd6a6acSopenharmony_ci			sepol_module_package_t * base,
3126cd6a6acSopenharmony_ci			sepol_module_package_t ** modules, int num_modules,
3136cd6a6acSopenharmony_ci			int verbose)
3146cd6a6acSopenharmony_ci{
3156cd6a6acSopenharmony_ci	policydb_t **mod_pols = NULL;
3166cd6a6acSopenharmony_ci	int i, retval;
3176cd6a6acSopenharmony_ci
3186cd6a6acSopenharmony_ci	if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
3196cd6a6acSopenharmony_ci		ERR(handle, "Out of memory!");
3206cd6a6acSopenharmony_ci		return -2;
3216cd6a6acSopenharmony_ci	}
3226cd6a6acSopenharmony_ci	for (i = 0; i < num_modules; i++) {
3236cd6a6acSopenharmony_ci		mod_pols[i] = &modules[i]->policy->p;
3246cd6a6acSopenharmony_ci	}
3256cd6a6acSopenharmony_ci
3266cd6a6acSopenharmony_ci	retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
3276cd6a6acSopenharmony_ci			      verbose);
3286cd6a6acSopenharmony_ci	free(mod_pols);
3296cd6a6acSopenharmony_ci	if (retval == -3) {
3306cd6a6acSopenharmony_ci		return -1;
3316cd6a6acSopenharmony_ci	} else if (retval < 0) {
3326cd6a6acSopenharmony_ci		return -2;
3336cd6a6acSopenharmony_ci	}
3346cd6a6acSopenharmony_ci
3356cd6a6acSopenharmony_ci	if (link_file_contexts(base, modules, num_modules) == -1) {
3366cd6a6acSopenharmony_ci		ERR(handle, "Out of memory!");
3376cd6a6acSopenharmony_ci		return -2;
3386cd6a6acSopenharmony_ci	}
3396cd6a6acSopenharmony_ci
3406cd6a6acSopenharmony_ci	if (link_netfilter_contexts(base, modules, num_modules) == -1) {
3416cd6a6acSopenharmony_ci		ERR(handle, "Out of memory!");
3426cd6a6acSopenharmony_ci		return -2;
3436cd6a6acSopenharmony_ci	}
3446cd6a6acSopenharmony_ci
3456cd6a6acSopenharmony_ci	return 0;
3466cd6a6acSopenharmony_ci}
3476cd6a6acSopenharmony_ci
3486cd6a6acSopenharmony_ci/* buf must be large enough - no checks are performed */
3496cd6a6acSopenharmony_ci#define _read_helper_bufsize BUFSIZ
3506cd6a6acSopenharmony_cistatic int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
3516cd6a6acSopenharmony_ci{
3526cd6a6acSopenharmony_ci	uint32_t offset, nel, read_len;
3536cd6a6acSopenharmony_ci	int rc;
3546cd6a6acSopenharmony_ci
3556cd6a6acSopenharmony_ci	offset = 0;
3566cd6a6acSopenharmony_ci	nel = bytes;
3576cd6a6acSopenharmony_ci
3586cd6a6acSopenharmony_ci	while (nel) {
3596cd6a6acSopenharmony_ci		if (nel < _read_helper_bufsize)
3606cd6a6acSopenharmony_ci			read_len = nel;
3616cd6a6acSopenharmony_ci		else
3626cd6a6acSopenharmony_ci			read_len = _read_helper_bufsize;
3636cd6a6acSopenharmony_ci		rc = next_entry(&buf[offset], file, read_len);
3646cd6a6acSopenharmony_ci		if (rc < 0)
3656cd6a6acSopenharmony_ci			return -1;
3666cd6a6acSopenharmony_ci		offset += read_len;
3676cd6a6acSopenharmony_ci		nel -= read_len;
3686cd6a6acSopenharmony_ci	}
3696cd6a6acSopenharmony_ci	return 0;
3706cd6a6acSopenharmony_ci}
3716cd6a6acSopenharmony_ci
3726cd6a6acSopenharmony_ci#define MAXSECTIONS 100
3736cd6a6acSopenharmony_ci
3746cd6a6acSopenharmony_ci/* Get the section offsets from a package file, offsets will be malloc'd to
3756cd6a6acSopenharmony_ci * the appropriate size and the caller must free() them */
3766cd6a6acSopenharmony_cistatic int module_package_read_offsets(sepol_module_package_t * mod,
3776cd6a6acSopenharmony_ci				       struct policy_file *file,
3786cd6a6acSopenharmony_ci				       size_t ** offsets, uint32_t * sections)
3796cd6a6acSopenharmony_ci{
3806cd6a6acSopenharmony_ci	uint32_t *buf = NULL, nsec;
3816cd6a6acSopenharmony_ci	unsigned i;
3826cd6a6acSopenharmony_ci	size_t *off = NULL;
3836cd6a6acSopenharmony_ci	int rc;
3846cd6a6acSopenharmony_ci
3856cd6a6acSopenharmony_ci	buf = malloc(sizeof(uint32_t)*3);
3866cd6a6acSopenharmony_ci	if (!buf) {
3876cd6a6acSopenharmony_ci		ERR(file->handle, "out of memory");
3886cd6a6acSopenharmony_ci		goto err;
3896cd6a6acSopenharmony_ci	}
3906cd6a6acSopenharmony_ci
3916cd6a6acSopenharmony_ci	rc = next_entry(buf, file, sizeof(uint32_t) * 3);
3926cd6a6acSopenharmony_ci	if (rc < 0) {
3936cd6a6acSopenharmony_ci		ERR(file->handle, "module package header truncated");
3946cd6a6acSopenharmony_ci		goto err;
3956cd6a6acSopenharmony_ci	}
3966cd6a6acSopenharmony_ci	if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
3976cd6a6acSopenharmony_ci		ERR(file->handle,
3986cd6a6acSopenharmony_ci		    "wrong magic number for module package:  expected %#08x, got %#08x",
3996cd6a6acSopenharmony_ci		    SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
4006cd6a6acSopenharmony_ci		goto err;
4016cd6a6acSopenharmony_ci	}
4026cd6a6acSopenharmony_ci
4036cd6a6acSopenharmony_ci	mod->version = le32_to_cpu(buf[1]);
4046cd6a6acSopenharmony_ci	nsec = *sections = le32_to_cpu(buf[2]);
4056cd6a6acSopenharmony_ci
4066cd6a6acSopenharmony_ci	if (nsec > MAXSECTIONS) {
4076cd6a6acSopenharmony_ci		ERR(file->handle, "too many sections (%u) in module package",
4086cd6a6acSopenharmony_ci		    nsec);
4096cd6a6acSopenharmony_ci		goto err;
4106cd6a6acSopenharmony_ci	}
4116cd6a6acSopenharmony_ci
4126cd6a6acSopenharmony_ci	off = (size_t *) calloc(nsec + 1, sizeof(size_t));
4136cd6a6acSopenharmony_ci	if (!off) {
4146cd6a6acSopenharmony_ci		ERR(file->handle, "out of memory");
4156cd6a6acSopenharmony_ci		goto err;
4166cd6a6acSopenharmony_ci	}
4176cd6a6acSopenharmony_ci
4186cd6a6acSopenharmony_ci	free(buf);
4196cd6a6acSopenharmony_ci	buf = calloc(nsec, sizeof(uint32_t));
4206cd6a6acSopenharmony_ci	if (!buf) {
4216cd6a6acSopenharmony_ci		ERR(file->handle, "out of memory");
4226cd6a6acSopenharmony_ci		goto err;
4236cd6a6acSopenharmony_ci	}
4246cd6a6acSopenharmony_ci	rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
4256cd6a6acSopenharmony_ci	if (rc < 0) {
4266cd6a6acSopenharmony_ci		ERR(file->handle, "module package offset array truncated");
4276cd6a6acSopenharmony_ci		goto err;
4286cd6a6acSopenharmony_ci	}
4296cd6a6acSopenharmony_ci
4306cd6a6acSopenharmony_ci	for (i = 0; i < nsec; i++) {
4316cd6a6acSopenharmony_ci		off[i] = le32_to_cpu(buf[i]);
4326cd6a6acSopenharmony_ci		if (i && off[i] < off[i - 1]) {
4336cd6a6acSopenharmony_ci			ERR(file->handle, "offsets are not increasing (at %u, "
4346cd6a6acSopenharmony_ci			    "offset %zu -> %zu", i, off[i - 1],
4356cd6a6acSopenharmony_ci			    off[i]);
4366cd6a6acSopenharmony_ci			goto err;
4376cd6a6acSopenharmony_ci		}
4386cd6a6acSopenharmony_ci	}
4396cd6a6acSopenharmony_ci
4406cd6a6acSopenharmony_ci	rc = policy_file_length(file, &off[nsec]);
4416cd6a6acSopenharmony_ci	if (rc < 0)
4426cd6a6acSopenharmony_ci		goto err;
4436cd6a6acSopenharmony_ci
4446cd6a6acSopenharmony_ci	if (nsec && off[nsec] < off[nsec-1]) {
4456cd6a6acSopenharmony_ci		ERR(file->handle, "offset greater than file size (at %u, "
4466cd6a6acSopenharmony_ci		    "offset %zu -> %zu", nsec, off[nsec - 1],
4476cd6a6acSopenharmony_ci		    off[nsec]);
4486cd6a6acSopenharmony_ci		goto err;
4496cd6a6acSopenharmony_ci	}
4506cd6a6acSopenharmony_ci	*offsets = off;
4516cd6a6acSopenharmony_ci	free(buf);
4526cd6a6acSopenharmony_ci	return 0;
4536cd6a6acSopenharmony_ci
4546cd6a6acSopenharmony_cierr:
4556cd6a6acSopenharmony_ci	free(buf);
4566cd6a6acSopenharmony_ci	free(off);
4576cd6a6acSopenharmony_ci	return -1;
4586cd6a6acSopenharmony_ci}
4596cd6a6acSopenharmony_ci
4606cd6a6acSopenharmony_ci/* Flags for which sections have been seen during parsing of module package. */
4616cd6a6acSopenharmony_ci#define SEEN_MOD 1
4626cd6a6acSopenharmony_ci#define SEEN_FC  2
4636cd6a6acSopenharmony_ci#define SEEN_SEUSER 4
4646cd6a6acSopenharmony_ci#define SEEN_USER_EXTRA 8
4656cd6a6acSopenharmony_ci#define SEEN_NETFILTER 16
4666cd6a6acSopenharmony_ci
4676cd6a6acSopenharmony_ciint sepol_module_package_read(sepol_module_package_t * mod,
4686cd6a6acSopenharmony_ci			      struct sepol_policy_file *spf, int verbose)
4696cd6a6acSopenharmony_ci{
4706cd6a6acSopenharmony_ci	struct policy_file *file = &spf->pf;
4716cd6a6acSopenharmony_ci	uint32_t buf[1], nsec;
4726cd6a6acSopenharmony_ci	size_t *offsets, len;
4736cd6a6acSopenharmony_ci	int rc;
4746cd6a6acSopenharmony_ci	unsigned i, seen = 0;
4756cd6a6acSopenharmony_ci
4766cd6a6acSopenharmony_ci	if (module_package_read_offsets(mod, file, &offsets, &nsec))
4776cd6a6acSopenharmony_ci		return -1;
4786cd6a6acSopenharmony_ci
4796cd6a6acSopenharmony_ci	/* we know the section offsets, seek to them and read in the data */
4806cd6a6acSopenharmony_ci
4816cd6a6acSopenharmony_ci	for (i = 0; i < nsec; i++) {
4826cd6a6acSopenharmony_ci
4836cd6a6acSopenharmony_ci		if (policy_file_seek(file, offsets[i])) {
4846cd6a6acSopenharmony_ci			ERR(file->handle, "error seeking to offset %zu for "
4856cd6a6acSopenharmony_ci			    "module package section %u", offsets[i], i);
4866cd6a6acSopenharmony_ci			goto cleanup;
4876cd6a6acSopenharmony_ci		}
4886cd6a6acSopenharmony_ci
4896cd6a6acSopenharmony_ci		len = offsets[i + 1] - offsets[i];
4906cd6a6acSopenharmony_ci
4916cd6a6acSopenharmony_ci		if (len < sizeof(uint32_t)) {
4926cd6a6acSopenharmony_ci			ERR(file->handle, "module package section %u "
4936cd6a6acSopenharmony_ci			    "has too small length %zu", i, len);
4946cd6a6acSopenharmony_ci			goto cleanup;
4956cd6a6acSopenharmony_ci		}
4966cd6a6acSopenharmony_ci
4976cd6a6acSopenharmony_ci		/* read the magic number, so that we know which function to call */
4986cd6a6acSopenharmony_ci		rc = next_entry(buf, file, sizeof(uint32_t));
4996cd6a6acSopenharmony_ci		if (rc < 0) {
5006cd6a6acSopenharmony_ci			ERR(file->handle,
5016cd6a6acSopenharmony_ci			    "module package section %u truncated, lacks magic number",
5026cd6a6acSopenharmony_ci			    i);
5036cd6a6acSopenharmony_ci			goto cleanup;
5046cd6a6acSopenharmony_ci		}
5056cd6a6acSopenharmony_ci
5066cd6a6acSopenharmony_ci		switch (le32_to_cpu(buf[0])) {
5076cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_FC:
5086cd6a6acSopenharmony_ci			if (seen & SEEN_FC) {
5096cd6a6acSopenharmony_ci				ERR(file->handle,
5106cd6a6acSopenharmony_ci				    "found multiple file contexts sections in module package (at section %u)",
5116cd6a6acSopenharmony_ci				    i);
5126cd6a6acSopenharmony_ci				goto cleanup;
5136cd6a6acSopenharmony_ci			}
5146cd6a6acSopenharmony_ci
5156cd6a6acSopenharmony_ci			mod->file_contexts_len = len - sizeof(uint32_t);
5166cd6a6acSopenharmony_ci			mod->file_contexts =
5176cd6a6acSopenharmony_ci			    (char *)malloc(mod->file_contexts_len);
5186cd6a6acSopenharmony_ci			if (!mod->file_contexts) {
5196cd6a6acSopenharmony_ci				ERR(file->handle, "out of memory");
5206cd6a6acSopenharmony_ci				goto cleanup;
5216cd6a6acSopenharmony_ci			}
5226cd6a6acSopenharmony_ci			if (read_helper
5236cd6a6acSopenharmony_ci			    (mod->file_contexts, file,
5246cd6a6acSopenharmony_ci			     mod->file_contexts_len)) {
5256cd6a6acSopenharmony_ci				ERR(file->handle,
5266cd6a6acSopenharmony_ci				    "invalid file contexts section at section %u",
5276cd6a6acSopenharmony_ci				    i);
5286cd6a6acSopenharmony_ci				free(mod->file_contexts);
5296cd6a6acSopenharmony_ci				mod->file_contexts = NULL;
5306cd6a6acSopenharmony_ci				goto cleanup;
5316cd6a6acSopenharmony_ci			}
5326cd6a6acSopenharmony_ci			seen |= SEEN_FC;
5336cd6a6acSopenharmony_ci			break;
5346cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_SEUSER:
5356cd6a6acSopenharmony_ci			if (seen & SEEN_SEUSER) {
5366cd6a6acSopenharmony_ci				ERR(file->handle,
5376cd6a6acSopenharmony_ci				    "found multiple seuser sections in module package (at section %u)",
5386cd6a6acSopenharmony_ci				    i);
5396cd6a6acSopenharmony_ci				goto cleanup;
5406cd6a6acSopenharmony_ci			}
5416cd6a6acSopenharmony_ci
5426cd6a6acSopenharmony_ci			mod->seusers_len = len - sizeof(uint32_t);
5436cd6a6acSopenharmony_ci			mod->seusers = (char *)malloc(mod->seusers_len);
5446cd6a6acSopenharmony_ci			if (!mod->seusers) {
5456cd6a6acSopenharmony_ci				ERR(file->handle, "out of memory");
5466cd6a6acSopenharmony_ci				goto cleanup;
5476cd6a6acSopenharmony_ci			}
5486cd6a6acSopenharmony_ci			if (read_helper(mod->seusers, file, mod->seusers_len)) {
5496cd6a6acSopenharmony_ci				ERR(file->handle,
5506cd6a6acSopenharmony_ci				    "invalid seuser section at section %u", i);
5516cd6a6acSopenharmony_ci				free(mod->seusers);
5526cd6a6acSopenharmony_ci				mod->seusers = NULL;
5536cd6a6acSopenharmony_ci				goto cleanup;
5546cd6a6acSopenharmony_ci			}
5556cd6a6acSopenharmony_ci			seen |= SEEN_SEUSER;
5566cd6a6acSopenharmony_ci			break;
5576cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
5586cd6a6acSopenharmony_ci			if (seen & SEEN_USER_EXTRA) {
5596cd6a6acSopenharmony_ci				ERR(file->handle,
5606cd6a6acSopenharmony_ci				    "found multiple user_extra sections in module package (at section %u)",
5616cd6a6acSopenharmony_ci				    i);
5626cd6a6acSopenharmony_ci				goto cleanup;
5636cd6a6acSopenharmony_ci			}
5646cd6a6acSopenharmony_ci
5656cd6a6acSopenharmony_ci			mod->user_extra_len = len - sizeof(uint32_t);
5666cd6a6acSopenharmony_ci			mod->user_extra = (char *)malloc(mod->user_extra_len);
5676cd6a6acSopenharmony_ci			if (!mod->user_extra) {
5686cd6a6acSopenharmony_ci				ERR(file->handle, "out of memory");
5696cd6a6acSopenharmony_ci				goto cleanup;
5706cd6a6acSopenharmony_ci			}
5716cd6a6acSopenharmony_ci			if (read_helper
5726cd6a6acSopenharmony_ci			    (mod->user_extra, file, mod->user_extra_len)) {
5736cd6a6acSopenharmony_ci				ERR(file->handle,
5746cd6a6acSopenharmony_ci				    "invalid user_extra section at section %u",
5756cd6a6acSopenharmony_ci				    i);
5766cd6a6acSopenharmony_ci				free(mod->user_extra);
5776cd6a6acSopenharmony_ci				mod->user_extra = NULL;
5786cd6a6acSopenharmony_ci				goto cleanup;
5796cd6a6acSopenharmony_ci			}
5806cd6a6acSopenharmony_ci			seen |= SEEN_USER_EXTRA;
5816cd6a6acSopenharmony_ci			break;
5826cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_NETFILTER:
5836cd6a6acSopenharmony_ci			if (seen & SEEN_NETFILTER) {
5846cd6a6acSopenharmony_ci				ERR(file->handle,
5856cd6a6acSopenharmony_ci				    "found multiple netfilter contexts sections in module package (at section %u)",
5866cd6a6acSopenharmony_ci				    i);
5876cd6a6acSopenharmony_ci				goto cleanup;
5886cd6a6acSopenharmony_ci			}
5896cd6a6acSopenharmony_ci
5906cd6a6acSopenharmony_ci			mod->netfilter_contexts_len = len - sizeof(uint32_t);
5916cd6a6acSopenharmony_ci			mod->netfilter_contexts =
5926cd6a6acSopenharmony_ci			    (char *)malloc(mod->netfilter_contexts_len);
5936cd6a6acSopenharmony_ci			if (!mod->netfilter_contexts) {
5946cd6a6acSopenharmony_ci				ERR(file->handle, "out of memory");
5956cd6a6acSopenharmony_ci				goto cleanup;
5966cd6a6acSopenharmony_ci			}
5976cd6a6acSopenharmony_ci			if (read_helper
5986cd6a6acSopenharmony_ci			    (mod->netfilter_contexts, file,
5996cd6a6acSopenharmony_ci			     mod->netfilter_contexts_len)) {
6006cd6a6acSopenharmony_ci				ERR(file->handle,
6016cd6a6acSopenharmony_ci				    "invalid netfilter contexts section at section %u",
6026cd6a6acSopenharmony_ci				    i);
6036cd6a6acSopenharmony_ci				free(mod->netfilter_contexts);
6046cd6a6acSopenharmony_ci				mod->netfilter_contexts = NULL;
6056cd6a6acSopenharmony_ci				goto cleanup;
6066cd6a6acSopenharmony_ci			}
6076cd6a6acSopenharmony_ci			seen |= SEEN_NETFILTER;
6086cd6a6acSopenharmony_ci			break;
6096cd6a6acSopenharmony_ci		case POLICYDB_MOD_MAGIC:
6106cd6a6acSopenharmony_ci			if (seen & SEEN_MOD) {
6116cd6a6acSopenharmony_ci				ERR(file->handle,
6126cd6a6acSopenharmony_ci				    "found multiple module sections in module package (at section %u)",
6136cd6a6acSopenharmony_ci				    i);
6146cd6a6acSopenharmony_ci				goto cleanup;
6156cd6a6acSopenharmony_ci			}
6166cd6a6acSopenharmony_ci
6176cd6a6acSopenharmony_ci			/* seek back to where the magic number was */
6186cd6a6acSopenharmony_ci			if (policy_file_seek(file, offsets[i]))
6196cd6a6acSopenharmony_ci				goto cleanup;
6206cd6a6acSopenharmony_ci
6216cd6a6acSopenharmony_ci			rc = policydb_read(&mod->policy->p, file, verbose);
6226cd6a6acSopenharmony_ci			if (rc < 0) {
6236cd6a6acSopenharmony_ci				ERR(file->handle,
6246cd6a6acSopenharmony_ci				    "invalid module in module package (at section %u)",
6256cd6a6acSopenharmony_ci				    i);
6266cd6a6acSopenharmony_ci				goto cleanup;
6276cd6a6acSopenharmony_ci			}
6286cd6a6acSopenharmony_ci			seen |= SEEN_MOD;
6296cd6a6acSopenharmony_ci			break;
6306cd6a6acSopenharmony_ci		default:
6316cd6a6acSopenharmony_ci			/* unknown section, ignore */
6326cd6a6acSopenharmony_ci			ERR(file->handle,
6336cd6a6acSopenharmony_ci			    "unknown magic number at section %u, offset: %zx, number: %x ",
6346cd6a6acSopenharmony_ci			    i, offsets[i], le32_to_cpu(buf[0]));
6356cd6a6acSopenharmony_ci			break;
6366cd6a6acSopenharmony_ci		}
6376cd6a6acSopenharmony_ci	}
6386cd6a6acSopenharmony_ci
6396cd6a6acSopenharmony_ci	if ((seen & SEEN_MOD) == 0) {
6406cd6a6acSopenharmony_ci		ERR(file->handle, "missing module in module package");
6416cd6a6acSopenharmony_ci		goto cleanup;
6426cd6a6acSopenharmony_ci	}
6436cd6a6acSopenharmony_ci
6446cd6a6acSopenharmony_ci	free(offsets);
6456cd6a6acSopenharmony_ci	return 0;
6466cd6a6acSopenharmony_ci
6476cd6a6acSopenharmony_ci      cleanup:
6486cd6a6acSopenharmony_ci	free(offsets);
6496cd6a6acSopenharmony_ci	return -1;
6506cd6a6acSopenharmony_ci}
6516cd6a6acSopenharmony_ci
6526cd6a6acSopenharmony_ciint sepol_module_package_info(struct sepol_policy_file *spf, int *type,
6536cd6a6acSopenharmony_ci			      char **name, char **version)
6546cd6a6acSopenharmony_ci{
6556cd6a6acSopenharmony_ci	struct policy_file *file = &spf->pf;
6566cd6a6acSopenharmony_ci	sepol_module_package_t *mod = NULL;
6576cd6a6acSopenharmony_ci	uint32_t buf[5], len, nsec;
6586cd6a6acSopenharmony_ci	size_t *offsets = NULL;
6596cd6a6acSopenharmony_ci	unsigned i, seen = 0;
6606cd6a6acSopenharmony_ci	char *id;
6616cd6a6acSopenharmony_ci	int rc;
6626cd6a6acSopenharmony_ci
6636cd6a6acSopenharmony_ci	if (sepol_module_package_create(&mod))
6646cd6a6acSopenharmony_ci		return -1;
6656cd6a6acSopenharmony_ci
6666cd6a6acSopenharmony_ci	if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
6676cd6a6acSopenharmony_ci		goto cleanup;
6686cd6a6acSopenharmony_ci	}
6696cd6a6acSopenharmony_ci
6706cd6a6acSopenharmony_ci	for (i = 0; i < nsec; i++) {
6716cd6a6acSopenharmony_ci
6726cd6a6acSopenharmony_ci		if (policy_file_seek(file, offsets[i])) {
6736cd6a6acSopenharmony_ci			ERR(file->handle, "error seeking to offset "
6746cd6a6acSopenharmony_ci			    "%zu for module package section %u", offsets[i], i);
6756cd6a6acSopenharmony_ci			goto cleanup;
6766cd6a6acSopenharmony_ci		}
6776cd6a6acSopenharmony_ci
6786cd6a6acSopenharmony_ci		len = offsets[i + 1] - offsets[i];
6796cd6a6acSopenharmony_ci
6806cd6a6acSopenharmony_ci		if (len < sizeof(uint32_t)) {
6816cd6a6acSopenharmony_ci			ERR(file->handle,
6826cd6a6acSopenharmony_ci			    "module package section %u has too small length %u",
6836cd6a6acSopenharmony_ci			    i, len);
6846cd6a6acSopenharmony_ci			goto cleanup;
6856cd6a6acSopenharmony_ci		}
6866cd6a6acSopenharmony_ci
6876cd6a6acSopenharmony_ci		/* read the magic number, so that we know which function to call */
6886cd6a6acSopenharmony_ci		rc = next_entry(buf, file, sizeof(uint32_t) * 2);
6896cd6a6acSopenharmony_ci		if (rc < 0) {
6906cd6a6acSopenharmony_ci			ERR(file->handle,
6916cd6a6acSopenharmony_ci			    "module package section %u truncated, lacks magic number",
6926cd6a6acSopenharmony_ci			    i);
6936cd6a6acSopenharmony_ci			goto cleanup;
6946cd6a6acSopenharmony_ci		}
6956cd6a6acSopenharmony_ci
6966cd6a6acSopenharmony_ci		switch (le32_to_cpu(buf[0])) {
6976cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_FC:
6986cd6a6acSopenharmony_ci			/* skip file contexts */
6996cd6a6acSopenharmony_ci			if (seen & SEEN_FC) {
7006cd6a6acSopenharmony_ci				ERR(file->handle,
7016cd6a6acSopenharmony_ci				    "found multiple file contexts sections in module package (at section %u)",
7026cd6a6acSopenharmony_ci				    i);
7036cd6a6acSopenharmony_ci				goto cleanup;
7046cd6a6acSopenharmony_ci			}
7056cd6a6acSopenharmony_ci			seen |= SEEN_FC;
7066cd6a6acSopenharmony_ci			break;
7076cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_SEUSER:
7086cd6a6acSopenharmony_ci			/* skip seuser */
7096cd6a6acSopenharmony_ci			if (seen & SEEN_SEUSER) {
7106cd6a6acSopenharmony_ci				ERR(file->handle,
7116cd6a6acSopenharmony_ci				    "found seuser sections in module package (at section %u)",
7126cd6a6acSopenharmony_ci				    i);
7136cd6a6acSopenharmony_ci				goto cleanup;
7146cd6a6acSopenharmony_ci			}
7156cd6a6acSopenharmony_ci			seen |= SEEN_SEUSER;
7166cd6a6acSopenharmony_ci			break;
7176cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_USER_EXTRA:
7186cd6a6acSopenharmony_ci			/* skip user_extra */
7196cd6a6acSopenharmony_ci			if (seen & SEEN_USER_EXTRA) {
7206cd6a6acSopenharmony_ci				ERR(file->handle,
7216cd6a6acSopenharmony_ci				    "found user_extra sections in module package (at section %u)",
7226cd6a6acSopenharmony_ci				    i);
7236cd6a6acSopenharmony_ci				goto cleanup;
7246cd6a6acSopenharmony_ci			}
7256cd6a6acSopenharmony_ci			seen |= SEEN_USER_EXTRA;
7266cd6a6acSopenharmony_ci			break;
7276cd6a6acSopenharmony_ci		case SEPOL_PACKAGE_SECTION_NETFILTER:
7286cd6a6acSopenharmony_ci			/* skip netfilter contexts */
7296cd6a6acSopenharmony_ci			if (seen & SEEN_NETFILTER) {
7306cd6a6acSopenharmony_ci				ERR(file->handle,
7316cd6a6acSopenharmony_ci				    "found multiple netfilter contexts sections in module package (at section %u)",
7326cd6a6acSopenharmony_ci				    i);
7336cd6a6acSopenharmony_ci				goto cleanup;
7346cd6a6acSopenharmony_ci			}
7356cd6a6acSopenharmony_ci			seen |= SEEN_NETFILTER;
7366cd6a6acSopenharmony_ci			break;
7376cd6a6acSopenharmony_ci		case POLICYDB_MOD_MAGIC:
7386cd6a6acSopenharmony_ci			if (seen & SEEN_MOD) {
7396cd6a6acSopenharmony_ci				ERR(file->handle,
7406cd6a6acSopenharmony_ci				    "found multiple module sections in module package (at section %u)",
7416cd6a6acSopenharmony_ci				    i);
7426cd6a6acSopenharmony_ci				goto cleanup;
7436cd6a6acSopenharmony_ci			}
7446cd6a6acSopenharmony_ci			len = le32_to_cpu(buf[1]);
7456cd6a6acSopenharmony_ci			if (len != strlen(POLICYDB_MOD_STRING)) {
7466cd6a6acSopenharmony_ci				ERR(file->handle,
7476cd6a6acSopenharmony_ci				    "module string length is wrong (at section %u)",
7486cd6a6acSopenharmony_ci				    i);
7496cd6a6acSopenharmony_ci				goto cleanup;
7506cd6a6acSopenharmony_ci			}
7516cd6a6acSopenharmony_ci
7526cd6a6acSopenharmony_ci			/* skip id */
7536cd6a6acSopenharmony_ci			id = malloc(len + 1);
7546cd6a6acSopenharmony_ci			if (!id) {
7556cd6a6acSopenharmony_ci				ERR(file->handle,
7566cd6a6acSopenharmony_ci				    "out of memory (at section %u)",
7576cd6a6acSopenharmony_ci				    i);
7586cd6a6acSopenharmony_ci				goto cleanup;
7596cd6a6acSopenharmony_ci			}
7606cd6a6acSopenharmony_ci			rc = next_entry(id, file, len);
7616cd6a6acSopenharmony_ci			free(id);
7626cd6a6acSopenharmony_ci			if (rc < 0) {
7636cd6a6acSopenharmony_ci				ERR(file->handle,
7646cd6a6acSopenharmony_ci				    "cannot get module string (at section %u)",
7656cd6a6acSopenharmony_ci				    i);
7666cd6a6acSopenharmony_ci				goto cleanup;
7676cd6a6acSopenharmony_ci			}
7686cd6a6acSopenharmony_ci
7696cd6a6acSopenharmony_ci			rc = next_entry(buf, file, sizeof(uint32_t) * 5);
7706cd6a6acSopenharmony_ci			if (rc < 0) {
7716cd6a6acSopenharmony_ci				ERR(file->handle,
7726cd6a6acSopenharmony_ci				    "cannot get module header (at section %u)",
7736cd6a6acSopenharmony_ci				    i);
7746cd6a6acSopenharmony_ci				goto cleanup;
7756cd6a6acSopenharmony_ci			}
7766cd6a6acSopenharmony_ci
7776cd6a6acSopenharmony_ci			*type = le32_to_cpu(buf[0]);
7786cd6a6acSopenharmony_ci			/* if base - we're done */
7796cd6a6acSopenharmony_ci			if (*type == POLICY_BASE) {
7806cd6a6acSopenharmony_ci				*name = NULL;
7816cd6a6acSopenharmony_ci				*version = NULL;
7826cd6a6acSopenharmony_ci				seen |= SEEN_MOD;
7836cd6a6acSopenharmony_ci				break;
7846cd6a6acSopenharmony_ci			} else if (*type != POLICY_MOD) {
7856cd6a6acSopenharmony_ci				ERR(file->handle,
7866cd6a6acSopenharmony_ci				    "module has invalid type %d (at section %u)",
7876cd6a6acSopenharmony_ci				    *type, i);
7886cd6a6acSopenharmony_ci				goto cleanup;
7896cd6a6acSopenharmony_ci			}
7906cd6a6acSopenharmony_ci
7916cd6a6acSopenharmony_ci			/* read the name and version */
7926cd6a6acSopenharmony_ci			rc = next_entry(buf, file, sizeof(uint32_t));
7936cd6a6acSopenharmony_ci			if (rc < 0) {
7946cd6a6acSopenharmony_ci				ERR(file->handle,
7956cd6a6acSopenharmony_ci				    "cannot get module name len (at section %u)",
7966cd6a6acSopenharmony_ci				    i);
7976cd6a6acSopenharmony_ci				goto cleanup;
7986cd6a6acSopenharmony_ci			}
7996cd6a6acSopenharmony_ci
8006cd6a6acSopenharmony_ci			len = le32_to_cpu(buf[0]);
8016cd6a6acSopenharmony_ci			if (str_read(name, file, len)) {
8026cd6a6acSopenharmony_ci				ERR(file->handle,
8036cd6a6acSopenharmony_ci				    "cannot read module name (at section %u): %m",
8046cd6a6acSopenharmony_ci				    i);
8056cd6a6acSopenharmony_ci				goto cleanup;
8066cd6a6acSopenharmony_ci			}
8076cd6a6acSopenharmony_ci
8086cd6a6acSopenharmony_ci			rc = next_entry(buf, file, sizeof(uint32_t));
8096cd6a6acSopenharmony_ci			if (rc < 0) {
8106cd6a6acSopenharmony_ci				ERR(file->handle,
8116cd6a6acSopenharmony_ci				    "cannot get module version len (at section %u)",
8126cd6a6acSopenharmony_ci				    i);
8136cd6a6acSopenharmony_ci				goto cleanup;
8146cd6a6acSopenharmony_ci			}
8156cd6a6acSopenharmony_ci			len = le32_to_cpu(buf[0]);
8166cd6a6acSopenharmony_ci			if (str_read(version, file, len)) {
8176cd6a6acSopenharmony_ci				ERR(file->handle,
8186cd6a6acSopenharmony_ci				    "cannot read module version (at section %u): %m",
8196cd6a6acSopenharmony_ci				i);
8206cd6a6acSopenharmony_ci				goto cleanup;
8216cd6a6acSopenharmony_ci			}
8226cd6a6acSopenharmony_ci			seen |= SEEN_MOD;
8236cd6a6acSopenharmony_ci			break;
8246cd6a6acSopenharmony_ci		default:
8256cd6a6acSopenharmony_ci			break;
8266cd6a6acSopenharmony_ci		}
8276cd6a6acSopenharmony_ci
8286cd6a6acSopenharmony_ci	}
8296cd6a6acSopenharmony_ci
8306cd6a6acSopenharmony_ci	if ((seen & SEEN_MOD) == 0) {
8316cd6a6acSopenharmony_ci		ERR(file->handle, "missing module in module package");
8326cd6a6acSopenharmony_ci		goto cleanup;
8336cd6a6acSopenharmony_ci	}
8346cd6a6acSopenharmony_ci
8356cd6a6acSopenharmony_ci	sepol_module_package_free(mod);
8366cd6a6acSopenharmony_ci	free(offsets);
8376cd6a6acSopenharmony_ci	return 0;
8386cd6a6acSopenharmony_ci
8396cd6a6acSopenharmony_ci      cleanup:
8406cd6a6acSopenharmony_ci	sepol_module_package_free(mod);
8416cd6a6acSopenharmony_ci	free(offsets);
8426cd6a6acSopenharmony_ci	return -1;
8436cd6a6acSopenharmony_ci}
8446cd6a6acSopenharmony_ci
8456cd6a6acSopenharmony_cistatic int write_helper(char *data, size_t len, struct policy_file *file)
8466cd6a6acSopenharmony_ci{
8476cd6a6acSopenharmony_ci	int idx = 0;
8486cd6a6acSopenharmony_ci	size_t len2;
8496cd6a6acSopenharmony_ci
8506cd6a6acSopenharmony_ci	while (len) {
8516cd6a6acSopenharmony_ci		if (len > BUFSIZ)
8526cd6a6acSopenharmony_ci			len2 = BUFSIZ;
8536cd6a6acSopenharmony_ci		else
8546cd6a6acSopenharmony_ci			len2 = len;
8556cd6a6acSopenharmony_ci
8566cd6a6acSopenharmony_ci		if (put_entry(&data[idx], 1, len2, file) != len2) {
8576cd6a6acSopenharmony_ci			return -1;
8586cd6a6acSopenharmony_ci		}
8596cd6a6acSopenharmony_ci		len -= len2;
8606cd6a6acSopenharmony_ci		idx += len2;
8616cd6a6acSopenharmony_ci	}
8626cd6a6acSopenharmony_ci	return 0;
8636cd6a6acSopenharmony_ci}
8646cd6a6acSopenharmony_ci
8656cd6a6acSopenharmony_ciint sepol_module_package_write(sepol_module_package_t * p,
8666cd6a6acSopenharmony_ci			       struct sepol_policy_file *spf)
8676cd6a6acSopenharmony_ci{
8686cd6a6acSopenharmony_ci	struct policy_file *file = &spf->pf;
8696cd6a6acSopenharmony_ci	policy_file_t polfile;
8706cd6a6acSopenharmony_ci	uint32_t buf[5], offsets[5], len, nsec = 0;
8716cd6a6acSopenharmony_ci	int i;
8726cd6a6acSopenharmony_ci
8736cd6a6acSopenharmony_ci	if (p->policy) {
8746cd6a6acSopenharmony_ci		/* compute policy length */
8756cd6a6acSopenharmony_ci		policy_file_init(&polfile);
8766cd6a6acSopenharmony_ci		polfile.type = PF_LEN;
8776cd6a6acSopenharmony_ci		polfile.handle = file->handle;
8786cd6a6acSopenharmony_ci		if (policydb_write(&p->policy->p, &polfile))
8796cd6a6acSopenharmony_ci			return -1;
8806cd6a6acSopenharmony_ci		len = polfile.len;
8816cd6a6acSopenharmony_ci		if (!polfile.len)
8826cd6a6acSopenharmony_ci			return -1;
8836cd6a6acSopenharmony_ci		nsec++;
8846cd6a6acSopenharmony_ci
8856cd6a6acSopenharmony_ci	} else {
8866cd6a6acSopenharmony_ci		/* We don't support writing a package without a module at this point */
8876cd6a6acSopenharmony_ci		return -1;
8886cd6a6acSopenharmony_ci	}
8896cd6a6acSopenharmony_ci
8906cd6a6acSopenharmony_ci	/* seusers and user_extra only supported in base at the moment */
8916cd6a6acSopenharmony_ci	if ((p->seusers || p->user_extra)
8926cd6a6acSopenharmony_ci	    && (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
8936cd6a6acSopenharmony_ci		ERR(file->handle,
8946cd6a6acSopenharmony_ci		    "seuser and user_extra sections only supported in base");
8956cd6a6acSopenharmony_ci		return -1;
8966cd6a6acSopenharmony_ci	}
8976cd6a6acSopenharmony_ci
8986cd6a6acSopenharmony_ci	if (p->file_contexts)
8996cd6a6acSopenharmony_ci		nsec++;
9006cd6a6acSopenharmony_ci
9016cd6a6acSopenharmony_ci	if (p->seusers)
9026cd6a6acSopenharmony_ci		nsec++;
9036cd6a6acSopenharmony_ci
9046cd6a6acSopenharmony_ci	if (p->user_extra)
9056cd6a6acSopenharmony_ci		nsec++;
9066cd6a6acSopenharmony_ci
9076cd6a6acSopenharmony_ci	if (p->netfilter_contexts)
9086cd6a6acSopenharmony_ci		nsec++;
9096cd6a6acSopenharmony_ci
9106cd6a6acSopenharmony_ci	buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
9116cd6a6acSopenharmony_ci	buf[1] = cpu_to_le32(p->version);
9126cd6a6acSopenharmony_ci	buf[2] = cpu_to_le32(nsec);
9136cd6a6acSopenharmony_ci	if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
9146cd6a6acSopenharmony_ci		return -1;
9156cd6a6acSopenharmony_ci
9166cd6a6acSopenharmony_ci	/* calculate offsets */
9176cd6a6acSopenharmony_ci	offsets[0] = (nsec + 3) * sizeof(uint32_t);
9186cd6a6acSopenharmony_ci	buf[0] = cpu_to_le32(offsets[0]);
9196cd6a6acSopenharmony_ci
9206cd6a6acSopenharmony_ci	i = 1;
9216cd6a6acSopenharmony_ci	if (p->file_contexts) {
9226cd6a6acSopenharmony_ci		offsets[i] = offsets[i - 1] + len;
9236cd6a6acSopenharmony_ci		buf[i] = cpu_to_le32(offsets[i]);
9246cd6a6acSopenharmony_ci		/* add a uint32_t to compensate for the magic number */
9256cd6a6acSopenharmony_ci		len = p->file_contexts_len + sizeof(uint32_t);
9266cd6a6acSopenharmony_ci		i++;
9276cd6a6acSopenharmony_ci	}
9286cd6a6acSopenharmony_ci	if (p->seusers) {
9296cd6a6acSopenharmony_ci		offsets[i] = offsets[i - 1] + len;
9306cd6a6acSopenharmony_ci		buf[i] = cpu_to_le32(offsets[i]);
9316cd6a6acSopenharmony_ci		len = p->seusers_len + sizeof(uint32_t);
9326cd6a6acSopenharmony_ci		i++;
9336cd6a6acSopenharmony_ci	}
9346cd6a6acSopenharmony_ci	if (p->user_extra) {
9356cd6a6acSopenharmony_ci		offsets[i] = offsets[i - 1] + len;
9366cd6a6acSopenharmony_ci		buf[i] = cpu_to_le32(offsets[i]);
9376cd6a6acSopenharmony_ci		len = p->user_extra_len + sizeof(uint32_t);
9386cd6a6acSopenharmony_ci		i++;
9396cd6a6acSopenharmony_ci	}
9406cd6a6acSopenharmony_ci	if (p->netfilter_contexts) {
9416cd6a6acSopenharmony_ci		offsets[i] = offsets[i - 1] + len;
9426cd6a6acSopenharmony_ci		buf[i] = cpu_to_le32(offsets[i]);
9436cd6a6acSopenharmony_ci		len = p->netfilter_contexts_len + sizeof(uint32_t);
9446cd6a6acSopenharmony_ci		i++;
9456cd6a6acSopenharmony_ci	}
9466cd6a6acSopenharmony_ci	if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
9476cd6a6acSopenharmony_ci		return -1;
9486cd6a6acSopenharmony_ci
9496cd6a6acSopenharmony_ci	/* write sections */
9506cd6a6acSopenharmony_ci
9516cd6a6acSopenharmony_ci	if (policydb_write(&p->policy->p, file))
9526cd6a6acSopenharmony_ci		return -1;
9536cd6a6acSopenharmony_ci
9546cd6a6acSopenharmony_ci	if (p->file_contexts) {
9556cd6a6acSopenharmony_ci		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
9566cd6a6acSopenharmony_ci		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
9576cd6a6acSopenharmony_ci			return -1;
9586cd6a6acSopenharmony_ci		if (write_helper(p->file_contexts, p->file_contexts_len, file))
9596cd6a6acSopenharmony_ci			return -1;
9606cd6a6acSopenharmony_ci	}
9616cd6a6acSopenharmony_ci	if (p->seusers) {
9626cd6a6acSopenharmony_ci		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
9636cd6a6acSopenharmony_ci		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
9646cd6a6acSopenharmony_ci			return -1;
9656cd6a6acSopenharmony_ci		if (write_helper(p->seusers, p->seusers_len, file))
9666cd6a6acSopenharmony_ci			return -1;
9676cd6a6acSopenharmony_ci
9686cd6a6acSopenharmony_ci	}
9696cd6a6acSopenharmony_ci	if (p->user_extra) {
9706cd6a6acSopenharmony_ci		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
9716cd6a6acSopenharmony_ci		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
9726cd6a6acSopenharmony_ci			return -1;
9736cd6a6acSopenharmony_ci		if (write_helper(p->user_extra, p->user_extra_len, file))
9746cd6a6acSopenharmony_ci			return -1;
9756cd6a6acSopenharmony_ci	}
9766cd6a6acSopenharmony_ci	if (p->netfilter_contexts) {
9776cd6a6acSopenharmony_ci		buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
9786cd6a6acSopenharmony_ci		if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
9796cd6a6acSopenharmony_ci			return -1;
9806cd6a6acSopenharmony_ci		if (write_helper
9816cd6a6acSopenharmony_ci		    (p->netfilter_contexts, p->netfilter_contexts_len, file))
9826cd6a6acSopenharmony_ci			return -1;
9836cd6a6acSopenharmony_ci	}
9846cd6a6acSopenharmony_ci	return 0;
9856cd6a6acSopenharmony_ci}
9866cd6a6acSopenharmony_ci
9876cd6a6acSopenharmony_ciint sepol_link_modules(sepol_handle_t * handle,
9886cd6a6acSopenharmony_ci		       sepol_policydb_t * base,
9896cd6a6acSopenharmony_ci		       sepol_policydb_t ** modules, size_t len, int verbose)
9906cd6a6acSopenharmony_ci{
9916cd6a6acSopenharmony_ci	return link_modules(handle, &base->p, (policydb_t **) modules, len,
9926cd6a6acSopenharmony_ci			    verbose);
9936cd6a6acSopenharmony_ci}
9946cd6a6acSopenharmony_ci
9956cd6a6acSopenharmony_ciint sepol_expand_module(sepol_handle_t * handle,
9966cd6a6acSopenharmony_ci			sepol_policydb_t * base,
9976cd6a6acSopenharmony_ci			sepol_policydb_t * out, int verbose, int check)
9986cd6a6acSopenharmony_ci{
9996cd6a6acSopenharmony_ci	return expand_module(handle, &base->p, &out->p, verbose, check);
10006cd6a6acSopenharmony_ci}
1001