diff --git a/libsemanage/include/semanage/modules.h b/libsemanage/include/semanage/modules.h index b51f61f0..14666f6d 100644 --- a/libsemanage/include/semanage/modules.h +++ b/libsemanage/include/semanage/modules.h @@ -282,4 +282,30 @@ extern int semanage_module_get_enabled(semanage_handle_t *sh, const semanage_module_key_t *modkey, int *enabled); +/* Compute checksum for @modkey module contents. + * + * If @checksum is NULL, the function will just return the length of the + * checksum string in @checksum_len (checksum strings are guaranteed to + * have a fixed length for a given libsemanage binary). @modkey and @cil + * are ignored in this case and should be set to NULL and 0 (respectively). + * + * If @checksum is non-NULL, on success, @checksum will point to a buffer + * containing the checksum string and @checksum_len will point to the + * length of the string (without the null terminator). The semantics of + * @cil are the same as for @extract_cil in semanage_module_extract(). + * + * The caller is responsible to free the buffer returned in @checksum (using + * free(3)). + * + * Callers may assume that if the checksum strings for two modules match, + * the module content is the same (collisions are theoretically possible, + * yet extremely unlikely). + * + * Returns 0 on success and -1 on error. + */ +extern int semanage_module_compute_checksum(semanage_handle_t *sh, + semanage_module_key_t *modkey, + int cil, char **checksum, + size_t *checksum_len); + #endif diff --git a/libsemanage/src/libsemanage.map b/libsemanage/src/libsemanage.map index 3ea7b60f..00259fc8 100644 --- a/libsemanage/src/libsemanage.map +++ b/libsemanage/src/libsemanage.map @@ -345,3 +345,7 @@ LIBSEMANAGE_1.1 { semanage_module_remove_key; semanage_set_store_root; } LIBSEMANAGE_1.0; + +LIBSEMANAGE_3.4 { + semanage_module_compute_checksum; +} LIBSEMANAGE_1.1; diff --git a/libsemanage/src/modules.c b/libsemanage/src/modules.c index c98df4dd..fe937519 100644 --- a/libsemanage/src/modules.c +++ b/libsemanage/src/modules.c @@ -35,11 +35,13 @@ #include #include #include +#include #include #include #include "handle.h" #include "modules.h" +#include "sha256.h" #include "debug.h" int semanage_module_install(semanage_handle_t * sh, @@ -976,3 +978,60 @@ int semanage_module_remove_key(semanage_handle_t *sh, return sh->funcs->remove_key(sh, modkey); } +static const char CHECKSUM_TYPE[] = "sha256"; +static const size_t CHECKSUM_CONTENT_SIZE = sizeof(CHECKSUM_TYPE) + 1 + 2 * SHA256_HASH_SIZE; + +static void semanage_hash_to_checksum_string(const uint8_t *hash, char *checksum) +{ + size_t i; + + checksum += sprintf(checksum, "%s:", CHECKSUM_TYPE); + for (i = 0; i < SHA256_HASH_SIZE; i++) { + checksum += sprintf(checksum, "%02x", (unsigned)hash[i]); + } +} + +int semanage_module_compute_checksum(semanage_handle_t *sh, + semanage_module_key_t *modkey, + int cil, char **checksum, + size_t *checksum_len) +{ + semanage_module_info_t *extract_info = NULL; + Sha256Context context; + SHA256_HASH sha256_hash; + char *checksum_str; + void *data; + size_t data_len = 0; + int result; + + if (!checksum_len) + return -1; + + if (!checksum) { + *checksum_len = CHECKSUM_CONTENT_SIZE; + return 0; + } + + result = semanage_module_extract(sh, modkey, cil, &data, &data_len, &extract_info); + if (result != 0) + return -1; + + semanage_module_info_destroy(sh, extract_info); + free(extract_info); + + Sha256Initialise(&context); + Sha256Update(&context, data, data_len); + Sha256Finalise(&context, &sha256_hash); + + munmap(data, data_len); + + checksum_str = malloc(CHECKSUM_CONTENT_SIZE + 1 /* '\0' */); + if (!checksum_str) + return -1; + + semanage_hash_to_checksum_string(sha256_hash.bytes, checksum_str); + + *checksum = checksum_str; + *checksum_len = CHECKSUM_CONTENT_SIZE; + return 0; +} diff --git a/libsemanage/src/semanageswig_python_exception.i b/libsemanage/src/semanageswig_python_exception.i index 372ec948..0df8bbc3 100644 --- a/libsemanage/src/semanageswig_python_exception.i +++ b/libsemanage/src/semanageswig_python_exception.i @@ -351,6 +351,14 @@ } } +%exception semanage_module_compute_checksum { + $action + if (result < 0) { + PyErr_SetFromErrno(PyExc_OSError); + SWIG_fail; + } +} + %exception semanage_msg_get_level { $action if (result < 0) { diff --git a/policycoreutils/semodule/sha256.c b/libsemanage/src/sha256.c similarity index 100% rename from policycoreutils/semodule/sha256.c rename to libsemanage/src/sha256.c diff --git a/policycoreutils/semodule/sha256.h b/libsemanage/src/sha256.h similarity index 100% rename from policycoreutils/semodule/sha256.h rename to libsemanage/src/sha256.h diff --git a/policycoreutils/semodule/Makefile b/policycoreutils/semodule/Makefile index 9875ac38..73801e48 100644 --- a/policycoreutils/semodule/Makefile +++ b/policycoreutils/semodule/Makefile @@ -6,7 +6,7 @@ MANDIR = $(PREFIX)/share/man CFLAGS ?= -Werror -Wall -W override LDLIBS += -lsepol -lselinux -lsemanage -SEMODULE_OBJS = semodule.o sha256.o +SEMODULE_OBJS = semodule.o all: semodule genhomedircon diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c index 94a9d131..f4a76289 100644 --- a/policycoreutils/semodule/semodule.c +++ b/policycoreutils/semodule/semodule.c @@ -25,8 +25,6 @@ #include #include -#include "sha256.h" - enum client_modes { NO_MODE, INSTALL_M, REMOVE_M, EXTRACT_M, CIL_M, HLL_M, LIST_M, RELOAD, PRIORITY_M, ENABLE_M, DISABLE_M @@ -348,60 +346,38 @@ static void parse_command_line(int argc, char **argv) /* Get module checksum */ static char *hash_module_data(const char *module_name, const int prio) { - semanage_module_info_t *extract_info = NULL; semanage_module_key_t *modkey = NULL; - Sha256Context context; - uint8_t sha256_hash[SHA256_HASH_SIZE]; - char *sha256_buf = NULL; - void *data; - size_t data_len = 0, i; + char *hash_str = NULL; + void *hash = NULL; + size_t hash_len = 0; int result; result = semanage_module_key_create(sh, &modkey); if (result != 0) { - goto cleanup_extract; + goto cleanup; } result = semanage_module_key_set_name(sh, modkey, module_name); if (result != 0) { - goto cleanup_extract; + goto cleanup; } result = semanage_module_key_set_priority(sh, modkey, prio); if (result != 0) { - goto cleanup_extract; + goto cleanup; } - result = semanage_module_extract(sh, modkey, 1, &data, &data_len, - &extract_info); + result = semanage_module_compute_checksum(sh, modkey, 1, &hash_str, + &hash_len); if (result != 0) { - goto cleanup_extract; + goto cleanup; } - Sha256Initialise(&context); - Sha256Update(&context, data, data_len); - - Sha256Finalise(&context, (SHA256_HASH *)sha256_hash); - - sha256_buf = calloc(1, SHA256_HASH_SIZE * 2 + 1); - - if (sha256_buf == NULL) - goto cleanup_extract; - - for (i = 0; i < SHA256_HASH_SIZE; i++) { - sprintf((&sha256_buf[i * 2]), "%02x", sha256_hash[i]); - } - sha256_buf[i * 2] = 0; - -cleanup_extract: - if (data_len > 0) { - munmap(data, data_len); - } - semanage_module_info_destroy(sh, extract_info); - free(extract_info); +cleanup: + free(hash); semanage_module_key_destroy(sh, modkey); free(modkey); - return sha256_buf; + return hash_str; } int main(int argc, char *argv[]) @@ -669,7 +645,10 @@ cleanup_extract: /* fixed width columns */ column[0] = sizeof("000") - 1; column[3] = sizeof("disabled") - 1; - column[4] = 64; /* SHA256_HASH_SIZE * 2 */ + + result = semanage_module_compute_checksum(sh, NULL, 0, NULL, + &column[4]); + if (result != 0) goto cleanup_list; /* variable width columns */ const char *tmp = NULL;