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