diff --git a/.policycoreutils.metadata b/.policycoreutils.metadata
index 5ef1737..f13ed2e 100644
--- a/.policycoreutils.metadata
+++ b/.policycoreutils.metadata
@@ -1,9 +1,9 @@
-3b2b219d260791ac448dff7c2e169cb493c78cb0 SOURCES/gui-po.tgz
+ab60ee590bb04c6172c12f60fd8fd730bb906dd6 SOURCES/gui-po.tgz
 6e64d9a38fb516738023eb429eef29af5383f443 SOURCES/policycoreutils-2.9.tar.gz
-d609be1fbc8824f4b4643c5f51ac250ad1a13e33 SOURCES/policycoreutils-po.tgz
-e9509bc5c150069a1045c97b2293c4a8d3a65022 SOURCES/python-po.tgz
+7bc3c564bdf9929ef396101d9bbcf366817f6b02 SOURCES/policycoreutils-po.tgz
+37703412bf6e9d3ecc7a896ef0cc833bf4fa9426 SOURCES/python-po.tgz
 0a34ef54394972870203832c8ce52d4405bd5330 SOURCES/restorecond-2.9.tar.gz
-2dfbf280ec17c1755b93426678dc885a0cf8909b SOURCES/sandbox-po.tgz
+221c505bfd2cb67b87dd2c95001c4a7bbb072571 SOURCES/sandbox-po.tgz
 8645509cdfc433278c2e4d29ee8f511625c7edcc SOURCES/selinux-dbus-2.9.tar.gz
 5c155ae47692389d9fabaa154195e7f978f2a3f0 SOURCES/selinux-gui-2.9.tar.gz
 660e1ab824ef80f7a69f0b70f61e231957fd398e SOURCES/selinux-python-2.9.tar.gz
diff --git a/SOURCES/0041-semodule-add-m-checksum-option.patch b/SOURCES/0041-semodule-add-m-checksum-option.patch
new file mode 100644
index 0000000..0fa0c54
--- /dev/null
+++ b/SOURCES/0041-semodule-add-m-checksum-option.patch
@@ -0,0 +1,674 @@
+From e748832819b781507903838483376d308c90ca79 Mon Sep 17 00:00:00 2001
+From: Petr Lautrbach <plautrba@redhat.com>
+Date: Tue, 16 Nov 2021 14:27:11 +0100
+Subject: [PATCH] semodule: add -m | --checksum option
+
+Since cil doesn't store module name and module version in module itself,
+there's no simple way how to compare that installed module is the same
+version as the module which is supposed to be installed. Even though the
+version was not used by semodule itself, it was apparently used by some
+team.
+
+With `semodule -l --checksum` users get SHA256 hashes of modules and
+could compare them with their files which is faster than installing
+modules again and again.
+
+E.g.
+
+    # time (
+    semodule -l --checksum | grep localmodule
+    /usr/libexec/selinux/hll/pp localmodule.pp | sha256sum
+    )
+    localmodule db002f64ddfa3983257b42b54da7b182c9b2e476f47880ae3494f9099e1a42bd
+    db002f64ddfa3983257b42b54da7b182c9b2e476f47880ae3494f9099e1a42bd  -
+
+    real    0m0.876s
+    user    0m0.849s
+    sys     0m0.028s
+
+vs
+
+    # time semodule -i localmodule.pp
+
+    real    0m6.147s
+    user    0m5.800s
+    sys     0m0.231s
+
+Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
+Acked-by: James Carter <jwcart2@gmail.com>
+---
+ policycoreutils/semodule/Makefile   |   2 +-
+ policycoreutils/semodule/semodule.8 |   6 +
+ policycoreutils/semodule/semodule.c |  95 ++++++++-
+ policycoreutils/semodule/sha256.c   | 294 ++++++++++++++++++++++++++++
+ policycoreutils/semodule/sha256.h   |  89 +++++++++
+ 5 files changed, 480 insertions(+), 6 deletions(-)
+ create mode 100644 policycoreutils/semodule/sha256.c
+ create mode 100644 policycoreutils/semodule/sha256.h
+
+diff --git a/policycoreutils/semodule/Makefile b/policycoreutils/semodule/Makefile
+index 73801e487a76..9875ac383280 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
++SEMODULE_OBJS = semodule.o sha256.o
+ 
+ all: semodule genhomedircon
+ 
+diff --git a/policycoreutils/semodule/semodule.8 b/policycoreutils/semodule/semodule.8
+index 18d4f708661c..3a2fb21c2481 100644
+--- a/policycoreutils/semodule/semodule.8
++++ b/policycoreutils/semodule/semodule.8
+@@ -95,6 +95,9 @@ only modules listed in \-\-extract after this option.
+ .B  \-H,\-\-hll
+ Extract module as an HLL file. This only affects the \-\-extract option and
+ only modules listed in \-\-extract after this option.
++.TP
++.B  \-m,\-\-checksum
++Add SHA256 checksum of modules to the list output.
+ 
+ .SH EXAMPLE
+ .nf
+@@ -130,6 +133,9 @@ $ semodule \-B \-S "/tmp/var/lib/selinux"
+ # Write the HLL version of puppet and the CIL version of wireshark
+ # modules at priority 400 to the current working directory
+ $ semodule \-X 400 \-\-hll \-E puppet \-\-cil \-E wireshark
++# Check whether a module in "localmodule.pp" file is same as installed module "localmodule"
++$ /usr/libexec/selinux/hll/pp localmodule.pp | sha256sum
++$ semodule -l -m | grep localmodule
+ .fi
+ 
+ .SH SEE ALSO
+diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c
+index a76797f505cd..300a97d735cc 100644
+--- a/policycoreutils/semodule/semodule.c
++++ b/policycoreutils/semodule/semodule.c
+@@ -24,6 +24,8 @@
+ 
+ #include <semanage/modules.h>
+ 
++#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
+@@ -56,6 +58,7 @@ static semanage_handle_t *sh = NULL;
+ static char *store;
+ static char *store_root;
+ int extract_cil = 0;
++static int checksum = 0;
+ 
+ extern char *optarg;
+ extern int optind;
+@@ -146,6 +149,7 @@ static void usage(char *progname)
+ 	printf("  -S,--store-path  use an alternate path for the policy store root\n");
+ 	printf("  -c, --cil extract module as cil. This only affects module extraction.\n");
+ 	printf("  -H, --hll extract module as hll. This only affects module extraction.\n");
++	printf("  -m, --checksum   print module checksum (SHA256).\n");
+ }
+ 
+ /* Sets the global mode variable to new_mode, but only if no other
+@@ -199,6 +203,7 @@ static void parse_command_line(int argc, char **argv)
+ 		{"disable", required_argument, NULL, 'd'},
+ 		{"path", required_argument, NULL, 'p'},
+ 		{"store-path", required_argument, NULL, 'S'},
++		{"checksum", 0, NULL, 'm'},
+ 		{NULL, 0, NULL, 0}
+ 	};
+ 	int extract_selected = 0;
+@@ -209,7 +214,7 @@ static void parse_command_line(int argc, char **argv)
+ 	no_reload = 0;
+ 	priority = 400;
+ 	while ((i =
+-		getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cH", opts,
++		getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cHm", opts,
+ 			    NULL)) != -1) {
+ 		switch (i) {
+ 		case 'b':
+@@ -286,6 +291,9 @@ static void parse_command_line(int argc, char **argv)
+ 		case 'd':
+ 			set_mode(DISABLE_M, optarg);
+ 			break;
++		case 'm':
++			checksum = 1;
++			break;
+ 		case '?':
+ 		default:{
+ 				usage(argv[0]);
+@@ -337,6 +345,61 @@ 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;
++	int result;
++
++	result = semanage_module_key_create(sh, &modkey);
++	if (result != 0) {
++		goto cleanup_extract;
++	}
++
++	result = semanage_module_key_set_name(sh, modkey, module_name);
++	if (result != 0) {
++		goto cleanup_extract;
++	}
++
++	result = semanage_module_key_set_priority(sh, modkey, prio);
++	if (result != 0) {
++		goto cleanup_extract;
++	}
++
++	result = semanage_module_extract(sh, modkey, 1, &data, &data_len,
++									 &extract_info);
++	if (result != 0) {
++		goto cleanup_extract;
++	}
++
++	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:
++	semanage_module_info_destroy(sh, extract_info);
++	free(extract_info);
++	semanage_module_key_destroy(sh, modkey);
++	free(modkey);
++	return sha256_buf;
++}
++
+ int main(int argc, char *argv[])
+ {
+ 	int i, commit = 0;
+@@ -544,6 +607,8 @@ cleanup_extract:
+ 				int modinfos_len = 0;
+ 				semanage_module_info_t *m = NULL;
+ 				int j = 0;
++				char *module_checksum = NULL;
++				uint16_t pri = 0;
+ 
+ 				if (verbose) {
+ 					printf
+@@ -568,7 +633,18 @@ cleanup_extract:
+ 						result = semanage_module_info_get_name(sh, m, &name);
+ 						if (result != 0) goto cleanup_list;
+ 
+-						printf("%s\n", name);
++						result = semanage_module_info_get_priority(sh, m, &pri);
++						if (result != 0) goto cleanup_list;
++
++						printf("%s", name);
++						if (checksum) {
++							module_checksum = hash_module_data(name, pri);
++							if (module_checksum) {
++								printf(" %s", module_checksum);
++								free(module_checksum);
++							}
++						}
++						printf("\n");
+ 					}
+ 				}
+ 				else if (strcmp(mode_arg, "full") == 0) {
+@@ -583,11 +659,12 @@ cleanup_extract:
+ 					}
+ 
+ 					/* calculate column widths */
+-					size_t column[4] = { 0, 0, 0, 0 };
++					size_t column[5] = { 0, 0, 0, 0, 0 };
+ 
+ 					/* fixed width columns */
+ 					column[0] = sizeof("000") - 1;
+ 					column[3] = sizeof("disabled") - 1;
++					column[4] = 64; /* SHA256_HASH_SIZE * 2 */
+ 
+ 					/* variable width columns */
+ 					const char *tmp = NULL;
+@@ -610,7 +687,6 @@ cleanup_extract:
+ 
+ 					/* print out each module */
+ 					for (j = 0; j < modinfos_len; j++) {
+-						uint16_t pri = 0;
+ 						const char *name = NULL;
+ 						int enabled = 0;
+ 						const char *lang_ext = NULL;
+@@ -629,11 +705,20 @@ cleanup_extract:
+ 						result = semanage_module_info_get_lang_ext(sh, m, &lang_ext);
+ 						if (result != 0) goto cleanup_list;
+ 
+-						printf("%0*u %-*s %-*s %-*s\n",
++						printf("%0*u %-*s %-*s %-*s",
+ 							(int)column[0], pri,
+ 							(int)column[1], name,
+ 							(int)column[2], lang_ext,
+ 							(int)column[3], enabled ? "" : "disabled");
++						if (checksum) {
++							module_checksum = hash_module_data(name, pri);
++							if (module_checksum) {
++								printf(" %-*s", (int)column[4], module_checksum);
++								free(module_checksum);
++							}
++						}
++						printf("\n");
++
+ 					}
+ 				}
+ 				else {
+diff --git a/policycoreutils/semodule/sha256.c b/policycoreutils/semodule/sha256.c
+new file mode 100644
+index 000000000000..fe2aeef07f53
+--- /dev/null
++++ b/policycoreutils/semodule/sha256.c
+@@ -0,0 +1,294 @@
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  WjCryptLib_Sha256
++//
++//  Implementation of SHA256 hash function.
++//  Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
++//  Modified by WaterJuice retaining Public Domain license.
++//
++//  This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  IMPORTS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++#include "sha256.h"
++#include <memory.h>
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  MACROS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
++
++#define MIN(x, y) ( ((x)<(y))?(x):(y) )
++
++#define STORE32H(x, y)                                                                     \
++     { (y)[0] = (uint8_t)(((x)>>24)&255); (y)[1] = (uint8_t)(((x)>>16)&255);   \
++       (y)[2] = (uint8_t)(((x)>>8)&255); (y)[3] = (uint8_t)((x)&255); }
++
++#define LOAD32H(x, y)                            \
++     { x = ((uint32_t)((y)[0] & 255)<<24) | \
++           ((uint32_t)((y)[1] & 255)<<16) | \
++           ((uint32_t)((y)[2] & 255)<<8)  | \
++           ((uint32_t)((y)[3] & 255)); }
++
++#define STORE64H(x, y)                                                                     \
++   { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255);     \
++     (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255);     \
++     (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255);     \
++     (y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); }
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  CONSTANTS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++// The K array
++static const uint32_t K[64] = {
++    0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
++    0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
++    0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
++    0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
++    0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
++    0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
++    0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
++    0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
++    0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
++    0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
++    0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
++    0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
++    0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
++};
++
++#define BLOCK_SIZE          64
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  INTERNAL FUNCTIONS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++// Various logical functions
++#define Ch( x, y, z )     (z ^ (x & (y ^ z)))
++#define Maj( x, y, z )    (((x | y) & z) | (x & y))
++#define S( x, n )         ror((x),(n))
++#define R( x, n )         (((x)&0xFFFFFFFFUL)>>(n))
++#define Sigma0( x )       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
++#define Sigma1( x )       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
++#define Gamma0( x )       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
++#define Gamma1( x )       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
++
++#define Sha256Round( a, b, c, d, e, f, g, h, i )       \
++     t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];   \
++     t1 = Sigma0(a) + Maj(a, b, c);                    \
++     d += t0;                                          \
++     h  = t0 + t1;
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  TransformFunction
++//
++//  Compress 512-bits
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++static
++void
++    TransformFunction
++    (
++        Sha256Context*      Context,
++        uint8_t const*      Buffer
++    )
++{
++    uint32_t    S[8];
++    uint32_t    W[64];
++    uint32_t    t0;
++    uint32_t    t1;
++    uint32_t    t;
++    int         i;
++
++    // Copy state into S
++    for( i=0; i<8; i++ )
++    {
++        S[i] = Context->state[i];
++    }
++
++    // Copy the state into 512-bits into W[0..15]
++    for( i=0; i<16; i++ )
++    {
++        LOAD32H( W[i], Buffer + (4*i) );
++    }
++
++    // Fill W[16..63]
++    for( i=16; i<64; i++ )
++    {
++        W[i] = Gamma1( W[i-2]) + W[i-7] + Gamma0( W[i-15] ) + W[i-16];
++    }
++
++    // Compress
++    for( i=0; i<64; i++ )
++    {
++        Sha256Round( S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i );
++        t = S[7];
++        S[7] = S[6];
++        S[6] = S[5];
++        S[5] = S[4];
++        S[4] = S[3];
++        S[3] = S[2];
++        S[2] = S[1];
++        S[1] = S[0];
++        S[0] = t;
++    }
++
++    // Feedback
++    for( i=0; i<8; i++ )
++    {
++        Context->state[i] = Context->state[i] + S[i];
++    }
++}
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  PUBLIC FUNCTIONS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Initialise
++//
++//  Initialises a SHA256 Context. Use this to initialise/reset a context.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Initialise
++    (
++        Sha256Context*      Context         // [out]
++    )
++{
++    Context->curlen = 0;
++    Context->length = 0;
++    Context->state[0] = 0x6A09E667UL;
++    Context->state[1] = 0xBB67AE85UL;
++    Context->state[2] = 0x3C6EF372UL;
++    Context->state[3] = 0xA54FF53AUL;
++    Context->state[4] = 0x510E527FUL;
++    Context->state[5] = 0x9B05688CUL;
++    Context->state[6] = 0x1F83D9ABUL;
++    Context->state[7] = 0x5BE0CD19UL;
++}
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Update
++//
++//  Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
++//  calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Update
++    (
++        Sha256Context*      Context,        // [in out]
++        void const*         Buffer,         // [in]
++        uint32_t            BufferSize      // [in]
++    )
++{
++    uint32_t n;
++
++    if( Context->curlen > sizeof(Context->buf) )
++    {
++       return;
++    }
++
++    while( BufferSize > 0 )
++    {
++        if( Context->curlen == 0 && BufferSize >= BLOCK_SIZE )
++        {
++           TransformFunction( Context, (uint8_t*)Buffer );
++           Context->length += BLOCK_SIZE * 8;
++           Buffer = (uint8_t*)Buffer + BLOCK_SIZE;
++           BufferSize -= BLOCK_SIZE;
++        }
++        else
++        {
++           n = MIN( BufferSize, (BLOCK_SIZE - Context->curlen) );
++           memcpy( Context->buf + Context->curlen, Buffer, (size_t)n );
++           Context->curlen += n;
++           Buffer = (uint8_t*)Buffer + n;
++           BufferSize -= n;
++           if( Context->curlen == BLOCK_SIZE )
++           {
++              TransformFunction( Context, Context->buf );
++              Context->length += 8*BLOCK_SIZE;
++              Context->curlen = 0;
++           }
++       }
++    }
++}
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Finalise
++//
++//  Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
++//  calling this, Sha256Initialised must be used to reuse the context.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Finalise
++    (
++        Sha256Context*      Context,        // [in out]
++        SHA256_HASH*        Digest          // [out]
++    )
++{
++    int i;
++
++    if( Context->curlen >= sizeof(Context->buf) )
++    {
++       return;
++    }
++
++    // Increase the length of the message
++    Context->length += Context->curlen * 8;
++
++    // Append the '1' bit
++    Context->buf[Context->curlen++] = (uint8_t)0x80;
++
++    // if the length is currently above 56 bytes we append zeros
++    // then compress.  Then we can fall back to padding zeros and length
++    // encoding like normal.
++    if( Context->curlen > 56 )
++    {
++        while( Context->curlen < 64 )
++        {
++            Context->buf[Context->curlen++] = (uint8_t)0;
++        }
++        TransformFunction(Context, Context->buf);
++        Context->curlen = 0;
++    }
++
++    // Pad up to 56 bytes of zeroes
++    while( Context->curlen < 56 )
++    {
++        Context->buf[Context->curlen++] = (uint8_t)0;
++    }
++
++    // Store length
++    STORE64H( Context->length, Context->buf+56 );
++    TransformFunction( Context, Context->buf );
++
++    // Copy output
++    for( i=0; i<8; i++ )
++    {
++        STORE32H( Context->state[i], Digest->bytes+(4*i) );
++    }
++}
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Calculate
++//
++//  Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the
++//  buffer.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Calculate
++    (
++        void  const*        Buffer,         // [in]
++        uint32_t            BufferSize,     // [in]
++        SHA256_HASH*        Digest          // [in]
++    )
++{
++    Sha256Context context;
++
++    Sha256Initialise( &context );
++    Sha256Update( &context, Buffer, BufferSize );
++    Sha256Finalise( &context, Digest );
++}
+diff --git a/policycoreutils/semodule/sha256.h b/policycoreutils/semodule/sha256.h
+new file mode 100644
+index 000000000000..406ed869cd82
+--- /dev/null
++++ b/policycoreutils/semodule/sha256.h
+@@ -0,0 +1,89 @@
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  WjCryptLib_Sha256
++//
++//  Implementation of SHA256 hash function.
++//  Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
++//  Modified by WaterJuice retaining Public Domain license.
++//
++//  This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++#pragma once
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  IMPORTS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++#include <stdint.h>
++#include <stdio.h>
++
++typedef struct
++{
++    uint64_t    length;
++    uint32_t    state[8];
++    uint32_t    curlen;
++    uint8_t     buf[64];
++} Sha256Context;
++
++#define SHA256_HASH_SIZE           ( 256 / 8 )
++
++typedef struct
++{
++    uint8_t      bytes [SHA256_HASH_SIZE];
++} SHA256_HASH;
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  PUBLIC FUNCTIONS
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Initialise
++//
++//  Initialises a SHA256 Context. Use this to initialise/reset a context.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Initialise
++    (
++        Sha256Context*      Context         // [out]
++    );
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Update
++//
++//  Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
++//  calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Update
++    (
++        Sha256Context*      Context,        // [in out]
++        void const*         Buffer,         // [in]
++        uint32_t            BufferSize      // [in]
++    );
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Finalise
++//
++//  Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
++//  calling this, Sha256Initialised must be used to reuse the context.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Finalise
++    (
++        Sha256Context*      Context,        // [in out]
++        SHA256_HASH*        Digest          // [out]
++    );
++
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++//  Sha256Calculate
++//
++//  Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the
++//  buffer.
++////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
++void
++    Sha256Calculate
++    (
++        void  const*        Buffer,         // [in]
++        uint32_t            BufferSize,     // [in]
++        SHA256_HASH*        Digest          // [in]
++    );
+-- 
+2.33.1
+
diff --git a/SOURCES/0042-semodule-Fix-lang_ext-column-index.patch b/SOURCES/0042-semodule-Fix-lang_ext-column-index.patch
new file mode 100644
index 0000000..2fa24dc
--- /dev/null
+++ b/SOURCES/0042-semodule-Fix-lang_ext-column-index.patch
@@ -0,0 +1,29 @@
+From 14084bad4f5bcfdb769ba39c9a6f12e4787ab909 Mon Sep 17 00:00:00 2001
+From: Petr Lautrbach <plautrba@redhat.com>
+Date: Tue, 16 Nov 2021 16:11:22 +0100
+Subject: [PATCH] semodule: Fix lang_ext column index
+
+lang_ext is 3. column - index number 2.
+
+Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
+Acked-by: James Carter <jwcart2@gmail.com>
+---
+ policycoreutils/semodule/semodule.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c
+index 300a97d735cc..c677cc4f1d81 100644
+--- a/policycoreutils/semodule/semodule.c
++++ b/policycoreutils/semodule/semodule.c
+@@ -682,7 +682,7 @@ cleanup_extract:
+ 						if (result != 0) goto cleanup_list;
+ 
+ 						size = strlen(tmp);
+-						if (size > column[3]) column[3] = size;
++						if (size > column[2]) column[2] = size;
+ 					}
+ 
+ 					/* print out each module */
+-- 
+2.33.1
+
diff --git a/SOURCES/0043-semodule-Don-t-forget-to-munmap-data.patch b/SOURCES/0043-semodule-Don-t-forget-to-munmap-data.patch
new file mode 100644
index 0000000..799c7e5
--- /dev/null
+++ b/SOURCES/0043-semodule-Don-t-forget-to-munmap-data.patch
@@ -0,0 +1,32 @@
+From 61f05b6d26063e1ebdc06609c29a067d44579b41 Mon Sep 17 00:00:00 2001
+From: Petr Lautrbach <plautrba@redhat.com>
+Date: Tue, 23 Nov 2021 17:38:51 +0100
+Subject: [PATCH] semodule: Don't forget to munmap() data
+
+semanage_module_extract() mmap()'s the module raw data but it leaves on
+the caller to munmap() them.
+
+Reported-by: Ondrej Mosnacek <omosnace@redhat.com>
+Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
+Acked-by: James Carter <jwcart2@gmail.com>
+---
+ policycoreutils/semodule/semodule.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c
+index c677cc4f1d81..dc227058b073 100644
+--- a/policycoreutils/semodule/semodule.c
++++ b/policycoreutils/semodule/semodule.c
+@@ -393,6 +393,9 @@ static char *hash_module_data(const char *module_name, const int prio) {
+ 	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);
+-- 
+2.33.1
+
diff --git a/SOURCES/0044-policycoreutils-Improve-error-message-when-selabel_o.patch b/SOURCES/0044-policycoreutils-Improve-error-message-when-selabel_o.patch
new file mode 100644
index 0000000..634a69b
--- /dev/null
+++ b/SOURCES/0044-policycoreutils-Improve-error-message-when-selabel_o.patch
@@ -0,0 +1,41 @@
+From 69da6239d8505a9d6ca547187f71a351df17f157 Mon Sep 17 00:00:00 2001
+From: Vit Mojzis <vmojzis@redhat.com>
+Date: Mon, 10 Jan 2022 18:35:27 +0100
+Subject: [PATCH] policycoreutils: Improve error message when selabel_open
+ fails
+
+When selabel_open fails to locate file_context files and
+selabel_opt_path is not specified (e.g. when the policy type is
+missconfigured in /etc/selinux/config), perror only prints
+"No such file or directory".
+This can be confusing in case of "restorecon" since it's
+not apparent that the issue is in policy store.
+
+Before:
+  \# restorecon -v /tmp/foo.txt
+  No such file or directory
+After:
+  \# restorecon -v /tmp/foo.txt
+  /etc/selinux/yolo/contexts/files/file_contexts: No such file or directory
+
+Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
+---
+ policycoreutils/setfiles/restore.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/policycoreutils/setfiles/restore.c b/policycoreutils/setfiles/restore.c
+index d3335d1a..ba2668b3 100644
+--- a/policycoreutils/setfiles/restore.c
++++ b/policycoreutils/setfiles/restore.c
+@@ -29,7 +29,7 @@ void restore_init(struct restore_opts *opts)
+ 
+ 	opts->hnd = selabel_open(SELABEL_CTX_FILE, selinux_opts, 3);
+ 	if (!opts->hnd) {
+-		perror(opts->selabel_opt_path);
++		perror(opts->selabel_opt_path ? opts->selabel_opt_path : selinux_file_context_path());
+ 		exit(1);
+ 	}
+ 
+-- 
+2.30.2
+
diff --git a/SOURCES/0045-semodule-libsemanage-move-module-hashing-into-libsem.patch b/SOURCES/0045-semodule-libsemanage-move-module-hashing-into-libsem.patch
new file mode 100644
index 0000000..1c5d05b
--- /dev/null
+++ b/SOURCES/0045-semodule-libsemanage-move-module-hashing-into-libsem.patch
@@ -0,0 +1,539 @@
+From 066007029b3dd250305d7fac0bfd53aa1e4543cf Mon Sep 17 00:00:00 2001
+From: Ondrej Mosnacek <omosnace@redhat.com>
+Date: Thu, 3 Feb 2022 17:53:23 +0100
+Subject: [PATCH] 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>
+---
+ policycoreutils/semodule/Makefile   |   2 +-
+ policycoreutils/semodule/semodule.c |  53 ++---
+ policycoreutils/semodule/sha256.c   | 294 ----------------------------
+ policycoreutils/semodule/sha256.h   |  89 ---------
+ 4 files changed, 17 insertions(+), 421 deletions(-)
+ delete mode 100644 policycoreutils/semodule/sha256.c
+ delete mode 100644 policycoreutils/semodule/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 dc227058..243b1add 100644
+--- a/policycoreutils/semodule/semodule.c
++++ b/policycoreutils/semodule/semodule.c
+@@ -24,8 +24,6 @@
+ 
+ #include <semanage/modules.h>
+ 
+-#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
+@@ -347,60 +345,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;
+-	}
+-
+-	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]);
++		goto cleanup;
+ 	}
+-	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[])
+@@ -667,7 +643,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;
+diff --git a/policycoreutils/semodule/sha256.c b/policycoreutils/semodule/sha256.c
+deleted file mode 100644
+index fe2aeef0..00000000
+--- a/policycoreutils/semodule/sha256.c
++++ /dev/null
+@@ -1,294 +0,0 @@
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  WjCryptLib_Sha256
+-//
+-//  Implementation of SHA256 hash function.
+-//  Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+-//  Modified by WaterJuice retaining Public Domain license.
+-//
+-//  This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  IMPORTS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-#include "sha256.h"
+-#include <memory.h>
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  MACROS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
+-
+-#define MIN(x, y) ( ((x)<(y))?(x):(y) )
+-
+-#define STORE32H(x, y)                                                                     \
+-     { (y)[0] = (uint8_t)(((x)>>24)&255); (y)[1] = (uint8_t)(((x)>>16)&255);   \
+-       (y)[2] = (uint8_t)(((x)>>8)&255); (y)[3] = (uint8_t)((x)&255); }
+-
+-#define LOAD32H(x, y)                            \
+-     { x = ((uint32_t)((y)[0] & 255)<<24) | \
+-           ((uint32_t)((y)[1] & 255)<<16) | \
+-           ((uint32_t)((y)[2] & 255)<<8)  | \
+-           ((uint32_t)((y)[3] & 255)); }
+-
+-#define STORE64H(x, y)                                                                     \
+-   { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255);     \
+-     (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255);     \
+-     (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255);     \
+-     (y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); }
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  CONSTANTS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-// The K array
+-static const uint32_t K[64] = {
+-    0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+-    0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+-    0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+-    0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+-    0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+-    0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+-    0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+-    0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+-    0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+-    0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+-    0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+-    0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+-    0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+-};
+-
+-#define BLOCK_SIZE          64
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  INTERNAL FUNCTIONS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-// Various logical functions
+-#define Ch( x, y, z )     (z ^ (x & (y ^ z)))
+-#define Maj( x, y, z )    (((x | y) & z) | (x & y))
+-#define S( x, n )         ror((x),(n))
+-#define R( x, n )         (((x)&0xFFFFFFFFUL)>>(n))
+-#define Sigma0( x )       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+-#define Sigma1( x )       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+-#define Gamma0( x )       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+-#define Gamma1( x )       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+-
+-#define Sha256Round( a, b, c, d, e, f, g, h, i )       \
+-     t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];   \
+-     t1 = Sigma0(a) + Maj(a, b, c);                    \
+-     d += t0;                                          \
+-     h  = t0 + t1;
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  TransformFunction
+-//
+-//  Compress 512-bits
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-static
+-void
+-    TransformFunction
+-    (
+-        Sha256Context*      Context,
+-        uint8_t const*      Buffer
+-    )
+-{
+-    uint32_t    S[8];
+-    uint32_t    W[64];
+-    uint32_t    t0;
+-    uint32_t    t1;
+-    uint32_t    t;
+-    int         i;
+-
+-    // Copy state into S
+-    for( i=0; i<8; i++ )
+-    {
+-        S[i] = Context->state[i];
+-    }
+-
+-    // Copy the state into 512-bits into W[0..15]
+-    for( i=0; i<16; i++ )
+-    {
+-        LOAD32H( W[i], Buffer + (4*i) );
+-    }
+-
+-    // Fill W[16..63]
+-    for( i=16; i<64; i++ )
+-    {
+-        W[i] = Gamma1( W[i-2]) + W[i-7] + Gamma0( W[i-15] ) + W[i-16];
+-    }
+-
+-    // Compress
+-    for( i=0; i<64; i++ )
+-    {
+-        Sha256Round( S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i );
+-        t = S[7];
+-        S[7] = S[6];
+-        S[6] = S[5];
+-        S[5] = S[4];
+-        S[4] = S[3];
+-        S[3] = S[2];
+-        S[2] = S[1];
+-        S[1] = S[0];
+-        S[0] = t;
+-    }
+-
+-    // Feedback
+-    for( i=0; i<8; i++ )
+-    {
+-        Context->state[i] = Context->state[i] + S[i];
+-    }
+-}
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  PUBLIC FUNCTIONS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Initialise
+-//
+-//  Initialises a SHA256 Context. Use this to initialise/reset a context.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Initialise
+-    (
+-        Sha256Context*      Context         // [out]
+-    )
+-{
+-    Context->curlen = 0;
+-    Context->length = 0;
+-    Context->state[0] = 0x6A09E667UL;
+-    Context->state[1] = 0xBB67AE85UL;
+-    Context->state[2] = 0x3C6EF372UL;
+-    Context->state[3] = 0xA54FF53AUL;
+-    Context->state[4] = 0x510E527FUL;
+-    Context->state[5] = 0x9B05688CUL;
+-    Context->state[6] = 0x1F83D9ABUL;
+-    Context->state[7] = 0x5BE0CD19UL;
+-}
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Update
+-//
+-//  Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
+-//  calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Update
+-    (
+-        Sha256Context*      Context,        // [in out]
+-        void const*         Buffer,         // [in]
+-        uint32_t            BufferSize      // [in]
+-    )
+-{
+-    uint32_t n;
+-
+-    if( Context->curlen > sizeof(Context->buf) )
+-    {
+-       return;
+-    }
+-
+-    while( BufferSize > 0 )
+-    {
+-        if( Context->curlen == 0 && BufferSize >= BLOCK_SIZE )
+-        {
+-           TransformFunction( Context, (uint8_t*)Buffer );
+-           Context->length += BLOCK_SIZE * 8;
+-           Buffer = (uint8_t*)Buffer + BLOCK_SIZE;
+-           BufferSize -= BLOCK_SIZE;
+-        }
+-        else
+-        {
+-           n = MIN( BufferSize, (BLOCK_SIZE - Context->curlen) );
+-           memcpy( Context->buf + Context->curlen, Buffer, (size_t)n );
+-           Context->curlen += n;
+-           Buffer = (uint8_t*)Buffer + n;
+-           BufferSize -= n;
+-           if( Context->curlen == BLOCK_SIZE )
+-           {
+-              TransformFunction( Context, Context->buf );
+-              Context->length += 8*BLOCK_SIZE;
+-              Context->curlen = 0;
+-           }
+-       }
+-    }
+-}
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Finalise
+-//
+-//  Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
+-//  calling this, Sha256Initialised must be used to reuse the context.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Finalise
+-    (
+-        Sha256Context*      Context,        // [in out]
+-        SHA256_HASH*        Digest          // [out]
+-    )
+-{
+-    int i;
+-
+-    if( Context->curlen >= sizeof(Context->buf) )
+-    {
+-       return;
+-    }
+-
+-    // Increase the length of the message
+-    Context->length += Context->curlen * 8;
+-
+-    // Append the '1' bit
+-    Context->buf[Context->curlen++] = (uint8_t)0x80;
+-
+-    // if the length is currently above 56 bytes we append zeros
+-    // then compress.  Then we can fall back to padding zeros and length
+-    // encoding like normal.
+-    if( Context->curlen > 56 )
+-    {
+-        while( Context->curlen < 64 )
+-        {
+-            Context->buf[Context->curlen++] = (uint8_t)0;
+-        }
+-        TransformFunction(Context, Context->buf);
+-        Context->curlen = 0;
+-    }
+-
+-    // Pad up to 56 bytes of zeroes
+-    while( Context->curlen < 56 )
+-    {
+-        Context->buf[Context->curlen++] = (uint8_t)0;
+-    }
+-
+-    // Store length
+-    STORE64H( Context->length, Context->buf+56 );
+-    TransformFunction( Context, Context->buf );
+-
+-    // Copy output
+-    for( i=0; i<8; i++ )
+-    {
+-        STORE32H( Context->state[i], Digest->bytes+(4*i) );
+-    }
+-}
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Calculate
+-//
+-//  Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the
+-//  buffer.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Calculate
+-    (
+-        void  const*        Buffer,         // [in]
+-        uint32_t            BufferSize,     // [in]
+-        SHA256_HASH*        Digest          // [in]
+-    )
+-{
+-    Sha256Context context;
+-
+-    Sha256Initialise( &context );
+-    Sha256Update( &context, Buffer, BufferSize );
+-    Sha256Finalise( &context, Digest );
+-}
+diff --git a/policycoreutils/semodule/sha256.h b/policycoreutils/semodule/sha256.h
+deleted file mode 100644
+index 406ed869..00000000
+--- a/policycoreutils/semodule/sha256.h
++++ /dev/null
+@@ -1,89 +0,0 @@
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  WjCryptLib_Sha256
+-//
+-//  Implementation of SHA256 hash function.
+-//  Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
+-//  Modified by WaterJuice retaining Public Domain license.
+-//
+-//  This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-#pragma once
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  IMPORTS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-#include <stdint.h>
+-#include <stdio.h>
+-
+-typedef struct
+-{
+-    uint64_t    length;
+-    uint32_t    state[8];
+-    uint32_t    curlen;
+-    uint8_t     buf[64];
+-} Sha256Context;
+-
+-#define SHA256_HASH_SIZE           ( 256 / 8 )
+-
+-typedef struct
+-{
+-    uint8_t      bytes [SHA256_HASH_SIZE];
+-} SHA256_HASH;
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  PUBLIC FUNCTIONS
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Initialise
+-//
+-//  Initialises a SHA256 Context. Use this to initialise/reset a context.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Initialise
+-    (
+-        Sha256Context*      Context         // [out]
+-    );
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Update
+-//
+-//  Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
+-//  calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Update
+-    (
+-        Sha256Context*      Context,        // [in out]
+-        void const*         Buffer,         // [in]
+-        uint32_t            BufferSize      // [in]
+-    );
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Finalise
+-//
+-//  Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After
+-//  calling this, Sha256Initialised must be used to reuse the context.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Finalise
+-    (
+-        Sha256Context*      Context,        // [in out]
+-        SHA256_HASH*        Digest          // [out]
+-    );
+-
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-//  Sha256Calculate
+-//
+-//  Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the
+-//  buffer.
+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+-void
+-    Sha256Calculate
+-    (
+-        void  const*        Buffer,         // [in]
+-        uint32_t            BufferSize,     // [in]
+-        SHA256_HASH*        Digest          // [in]
+-    );
+-- 
+2.30.2
+
diff --git a/SOURCES/0046-semodule-add-command-line-option-to-detect-module-ch.patch b/SOURCES/0046-semodule-add-command-line-option-to-detect-module-ch.patch
new file mode 100644
index 0000000..f280b9f
--- /dev/null
+++ b/SOURCES/0046-semodule-add-command-line-option-to-detect-module-ch.patch
@@ -0,0 +1,144 @@
+From e3fc737e43561ecadcb977ce4c9a1db44be636ae Mon Sep 17 00:00:00 2001
+From: Ondrej Mosnacek <omosnace@redhat.com>
+Date: Thu, 3 Feb 2022 17:53:27 +0100
+Subject: [PATCH] semodule: add command-line option to detect module changes
+
+Add a new command-line option "--rebuild-if-modules-changed" to control
+the newly introduced check_ext_changes libsemanage flag.
+
+For example, running `semodule --rebuild-if-modules-changed` will ensure
+that any externally added/removed modules (e.g. by an RPM transaction)
+are reflected in the compiled policy, while skipping the most expensive
+part of the rebuild if no module change was deteceted since the last
+libsemanage transaction.
+
+Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
+---
+ policycoreutils/semodule/semodule.8 |  7 +++++++
+ policycoreutils/semodule/semodule.c | 32 ++++++++++++++++++++++-------
+ 2 files changed, 32 insertions(+), 7 deletions(-)
+
+diff --git a/policycoreutils/semodule/semodule.8 b/policycoreutils/semodule/semodule.8
+index 3a2fb21c..d1735d21 100644
+--- a/policycoreutils/semodule/semodule.8
++++ b/policycoreutils/semodule/semodule.8
+@@ -23,6 +23,13 @@ force a reload of policy
+ .B \-B, \-\-build
+ force a rebuild of policy (also reloads unless \-n is used)
+ .TP
++.B \-\-rebuild-if-modules-changed
++Force a rebuild of the policy if any changes to module content are detected
++(by comparing with checksum from the last transaction).  One can use this
++instead of \-B to ensure that any changes to the module store done by an
++external tool (e.g. a package manager) are applied, while automatically
++skipping the rebuild if there are no new changes.
++.TP
+ .B \-D, \-\-disable_dontaudit
+ Temporarily remove dontaudits from policy.  Reverts whenever policy is rebuilt
+ .TP
+diff --git a/policycoreutils/semodule/semodule.c b/policycoreutils/semodule/semodule.c
+index 243b1add..22a42a75 100644
+--- a/policycoreutils/semodule/semodule.c
++++ b/policycoreutils/semodule/semodule.c
+@@ -46,6 +46,7 @@ static int verbose;
+ static int reload;
+ static int no_reload;
+ static int build;
++static int check_ext_changes;
+ static int disable_dontaudit;
+ static int preserve_tunables;
+ static int ignore_module_cache;
+@@ -148,6 +149,9 @@ static void usage(char *progname)
+ 	printf("  -c, --cil extract module as cil. This only affects module extraction.\n");
+ 	printf("  -H, --hll extract module as hll. This only affects module extraction.\n");
+ 	printf("  -m, --checksum   print module checksum (SHA256).\n");
++	printf("      --rebuild-if-modules-changed\n"
++	       "                   force policy rebuild if module content changed since\n"
++	       "                   last rebuild (based on checksum)\n");
+ }
+ 
+ /* Sets the global mode variable to new_mode, but only if no other
+@@ -179,6 +183,7 @@ static void set_mode(enum client_modes new_mode, char *arg)
+ static void parse_command_line(int argc, char **argv)
+ {
+ 	static struct option opts[] = {
++		{"rebuild-if-modules-changed", 0, NULL, '\0'},
+ 		{"store", required_argument, NULL, 's'},
+ 		{"base", required_argument, NULL, 'b'},
+ 		{"help", 0, NULL, 'h'},
+@@ -206,15 +211,26 @@ static void parse_command_line(int argc, char **argv)
+ 	};
+ 	int extract_selected = 0;
+ 	int cil_hll_set = 0;
+-	int i;
++	int i, longind;
+ 	verbose = 0;
+ 	reload = 0;
+ 	no_reload = 0;
++	check_ext_changes = 0;
+ 	priority = 400;
+ 	while ((i =
+-		getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cHm", opts,
+-			    NULL)) != -1) {
++		getopt_long(argc, argv, "s:b:hi:l::vr:u:RnNBDCPX:e:d:p:S:E:cHm",
++			    opts, &longind)) != -1) {
+ 		switch (i) {
++		case '\0':
++			switch(longind) {
++			case 0: /* --rebuild-if-modules-changed */
++				check_ext_changes = 1;
++				break;
++			default:
++				usage(argv[0]);
++				exit(1);
++			}
++			break;
+ 		case 'b':
+ 			fprintf(stderr, "The --base option is deprecated. Use --install instead.\n");
+ 			set_mode(INSTALL_M, optarg);
+@@ -299,13 +315,13 @@ static void parse_command_line(int argc, char **argv)
+ 			}
+ 		}
+ 	}
+-	if ((build || reload) && num_commands) {
++	if ((build || reload || check_ext_changes) && num_commands) {
+ 		fprintf(stderr,
+ 			"build or reload should not be used with other commands\n");
+ 		usage(argv[0]);
+ 		exit(1);
+ 	}
+-	if (num_commands == 0 && reload == 0 && build == 0) {
++	if (num_commands == 0 && reload == 0 && build == 0 && check_ext_changes == 0) {
+ 		fprintf(stderr, "At least one mode must be specified.\n");
+ 		usage(argv[0]);
+ 		exit(1);
+@@ -392,7 +408,7 @@ int main(int argc, char *argv[])
+ 	}
+ 	parse_command_line(argc, argv);
+ 
+-	if (build)
++	if (build || check_ext_changes)
+ 		commit = 1;
+ 
+ 	sh = semanage_handle_create();
+@@ -431,7 +447,7 @@ int main(int argc, char *argv[])
+ 		}
+ 	}
+ 
+-	if (build) {
++	if (build || check_ext_changes) {
+ 		if ((result = semanage_begin_transaction(sh)) < 0) {
+ 			fprintf(stderr, "%s:  Could not begin transaction:  %s\n",
+ 				argv[0], errno ? strerror(errno) : "");
+@@ -805,6 +821,8 @@ cleanup_disable:
+ 			semanage_set_reload(sh, 0);
+ 		if (build)
+ 			semanage_set_rebuild(sh, 1);
++		if (check_ext_changes)
++			semanage_set_check_ext_changes(sh, 1);
+ 		if (disable_dontaudit)
+ 			semanage_set_disable_dontaudit(sh, 1);
+ 		else if (build)
+-- 
+2.30.2
+
diff --git a/SPECS/policycoreutils.spec b/SPECS/policycoreutils.spec
index 7d87076..9ccd954 100644
--- a/SPECS/policycoreutils.spec
+++ b/SPECS/policycoreutils.spec
@@ -1,6 +1,6 @@
 %global libauditver     3.0
 %global libsepolver     2.9-1
-%global libsemanagever  2.9-2
+%global libsemanagever  2.9-7
 %global libselinuxver   2.9-1
 %global sepolgenver     2.9
 
@@ -12,7 +12,7 @@
 Summary: SELinux policy core utilities
 Name:    policycoreutils
 Version: 2.9
-Release: 15%{?dist}
+Release: 19%{?dist}
 License: GPLv2
 # https://github.com/SELinuxProject/selinux/wiki/Releases
 Source0: https://github.com/SELinuxProject/selinux/releases/download/20190315/policycoreutils-2.9.tar.gz
@@ -78,6 +78,12 @@ Patch0037: 0037-setfiles-drop-ABORT_ON_ERRORS-and-related-code.patch
 Patch0038: 0038-policycoreutils-setfiles-Drop-unused-nerr-variable.patch
 Patch0039: 0039-selinux-8-5-Describe-fcontext-regular-expressions.patch
 Patch0040: 0040-policycoreutils-setfiles-do-not-restrict-checks-agai.patch
+Patch0041: 0041-semodule-add-m-checksum-option.patch
+Patch0042: 0042-semodule-Fix-lang_ext-column-index.patch
+Patch0043: 0043-semodule-Don-t-forget-to-munmap-data.patch
+Patch0044: 0044-policycoreutils-Improve-error-message-when-selabel_o.patch
+Patch0045: 0045-semodule-libsemanage-move-module-hashing-into-libsem.patch
+Patch0046: 0046-semodule-add-command-line-option-to-detect-module-ch.patch
 
 Obsoletes: policycoreutils < 2.0.61-2
 Conflicts: filesystem < 3, selinux-policy-base < 3.13.1-138
@@ -517,6 +523,19 @@ The policycoreutils-restorecond package contains the restorecond service.
 %systemd_postun_with_restart restorecond.service
 
 %changelog
+* Thu Feb 17 2022 Vit Mojzis <vmojzis@redhat.com> - 2.9-19
+- semodule: move module hashing into libsemanage (requires libsemanage-2.9-7)
+- semodule: add command-line option to detect module changes (#2049189)
+
+* Fri Jan 14 2022 Vit Mojzis <vmojzis@redhat.com> - 2.9-18
+- Improve error message when selabel_open fails (#1926511)
+
+* Tue Nov 30 2021 Petr Lautrbach <plautrba@redhat.com> - 2.9-17
+- semodule: add -m | --checksum option
+
+* Thu Sep 16 2021 Vit Mojzis <vmojzis@redhat.com> - 2.9-16
+- Update translations (#1962009)
+
 * Mon Jul 19 2021 Vit Mojzis <vmojzis@redhat.com> - 2.9-15
 - setfiles: do not restrict checks against a binary policy (#1973754)