semodule,libsemanage: move module hashing into libsemanage

The main goal of this move is to have the SHA-256 implementation under
libsemanage, since upcoming patches will make use of SHA-256 for a
different (but similar) purpose in libsemanage. Having the hashing code
in libsemanage will reduce code duplication and allow for easier hash
algorithm upgrade in the future.

Note that libselinux currently also contains a hash function
implementation (for yet another different purpose). This patch doesn't
make any effort to address that duplicity yet.

This patch also changes the format of the hash string printed by
semodule to include the name of the hash. The intent is to avoid
ambiguity and potential collisions when the algorithm is potentially
changed in the future.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
This commit is contained in:
Ondrej Mosnacek 2022-02-03 17:53:23 +01:00 committed by James Carter
parent 6f9e771987
commit 67e6201bc8
8 changed files with 114 additions and 38 deletions

View File

@ -282,4 +282,30 @@ extern int semanage_module_get_enabled(semanage_handle_t *sh,
const semanage_module_key_t *modkey, const semanage_module_key_t *modkey,
int *enabled); 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 #endif

View File

@ -345,3 +345,7 @@ LIBSEMANAGE_1.1 {
semanage_module_remove_key; semanage_module_remove_key;
semanage_set_store_root; semanage_set_store_root;
} LIBSEMANAGE_1.0; } LIBSEMANAGE_1.0;
LIBSEMANAGE_3.4 {
semanage_module_compute_checksum;
} LIBSEMANAGE_1.1;

View File

@ -35,11 +35,13 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include "handle.h" #include "handle.h"
#include "modules.h" #include "modules.h"
#include "sha256.h"
#include "debug.h" #include "debug.h"
int semanage_module_install(semanage_handle_t * sh, 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); 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;
}

View File

@ -351,6 +351,14 @@
} }
} }
%exception semanage_module_compute_checksum {
$action
if (result < 0) {
PyErr_SetFromErrno(PyExc_OSError);
SWIG_fail;
}
}
%exception semanage_msg_get_level { %exception semanage_msg_get_level {
$action $action
if (result < 0) { if (result < 0) {

View File

@ -6,7 +6,7 @@ MANDIR = $(PREFIX)/share/man
CFLAGS ?= -Werror -Wall -W CFLAGS ?= -Werror -Wall -W
override LDLIBS += -lsepol -lselinux -lsemanage override LDLIBS += -lsepol -lselinux -lsemanage
SEMODULE_OBJS = semodule.o sha256.o SEMODULE_OBJS = semodule.o
all: semodule genhomedircon all: semodule genhomedircon

View File

@ -25,8 +25,6 @@
#include <sepol/cil/cil.h> #include <sepol/cil/cil.h>
#include <semanage/modules.h> #include <semanage/modules.h>
#include "sha256.h"
enum client_modes { enum client_modes {
NO_MODE, INSTALL_M, REMOVE_M, EXTRACT_M, CIL_M, HLL_M, NO_MODE, INSTALL_M, REMOVE_M, EXTRACT_M, CIL_M, HLL_M,
LIST_M, RELOAD, PRIORITY_M, ENABLE_M, DISABLE_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 */ /* Get module checksum */
static char *hash_module_data(const char *module_name, const int prio) { 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; semanage_module_key_t *modkey = NULL;
Sha256Context context; char *hash_str = NULL;
uint8_t sha256_hash[SHA256_HASH_SIZE]; void *hash = NULL;
char *sha256_buf = NULL; size_t hash_len = 0;
void *data;
size_t data_len = 0, i;
int result; int result;
result = semanage_module_key_create(sh, &modkey); result = semanage_module_key_create(sh, &modkey);
if (result != 0) { if (result != 0) {
goto cleanup_extract; goto cleanup;
} }
result = semanage_module_key_set_name(sh, modkey, module_name); result = semanage_module_key_set_name(sh, modkey, module_name);
if (result != 0) { if (result != 0) {
goto cleanup_extract; goto cleanup;
} }
result = semanage_module_key_set_priority(sh, modkey, prio); result = semanage_module_key_set_priority(sh, modkey, prio);
if (result != 0) { if (result != 0) {
goto cleanup_extract; goto cleanup;
} }
result = semanage_module_extract(sh, modkey, 1, &data, &data_len, result = semanage_module_compute_checksum(sh, modkey, 1, &hash_str,
&extract_info); &hash_len);
if (result != 0) { if (result != 0) {
goto cleanup_extract; goto cleanup;
} }
Sha256Initialise(&context); cleanup:
Sha256Update(&context, data, data_len); free(hash);
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);
semanage_module_key_destroy(sh, modkey); semanage_module_key_destroy(sh, modkey);
free(modkey); free(modkey);
return sha256_buf; return hash_str;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -669,7 +645,10 @@ cleanup_extract:
/* fixed width columns */ /* fixed width columns */
column[0] = sizeof("000") - 1; column[0] = sizeof("000") - 1;
column[3] = sizeof("disabled") - 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 */ /* variable width columns */
const char *tmp = NULL; const char *tmp = NULL;