Auto sync2gitlab import of libsemanage-2.9-8.el8.src.rpm

This commit is contained in:
James Antill 2022-06-06 22:25:30 -04:00
parent a5dc5db292
commit 06717130ed
17 changed files with 4110 additions and 1 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/libsemanage-2.9.tar.gz

View File

@ -0,0 +1,66 @@
From dc105dcb5e34e256bcbcf547fea590cfcee06933 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <plautrba@redhat.com>
Date: Wed, 7 Nov 2018 18:17:34 +0100
Subject: [PATCH] libsemanage: Fix RESOURCE_LEAK and USE_AFTER_FREE coverity
scan defects
---
libsemanage/src/direct_api.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index c58961be..8e4d116d 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -1028,7 +1028,7 @@ static int semanage_direct_write_langext(semanage_handle_t *sh,
fp = NULL;
- ret = 0;
+ return 0;
cleanup:
if (fp != NULL) fclose(fp);
@@ -2177,7 +2177,6 @@ cleanup:
semanage_module_info_destroy(sh, modinfo);
free(modinfo);
- if (fp != NULL) fclose(fp);
return status;
}
@@ -2342,16 +2341,6 @@ static int semanage_direct_get_module_info(semanage_handle_t *sh,
free(tmp);
tmp = NULL;
- if (fclose(fp) != 0) {
- ERR(sh,
- "Unable to close %s module lang ext file.",
- (*modinfo)->name);
- status = -1;
- goto cleanup;
- }
-
- fp = NULL;
-
/* lookup enabled/disabled status */
ret = semanage_module_get_path(sh,
*modinfo,
@@ -2395,7 +2384,13 @@ cleanup:
free(modinfos);
}
- if (fp != NULL) fclose(fp);
+ if (fp != NULL && fclose(fp) != 0) {
+ ERR(sh,
+ "Unable to close %s module lang ext file.",
+ (*modinfo)->name);
+ status = -1;
+ }
+
return status;
}
--
2.21.0

View File

@ -0,0 +1,48 @@
From d68976d353bf334c43fd084f9cc4535874860006 Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Tue, 8 Oct 2019 14:22:12 +0200
Subject: [PATCH] libsemanage: Add support for DCCP and SCTP protocols
This is necessary for "semanage port" to be able to handle DCCP and SCTP
protocols.
Fixes:
"port_parse" only handles TCP and UDP protocols
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
---
libsemanage/include/semanage/port_record.h | 2 ++
libsemanage/src/ports_file.c | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/libsemanage/include/semanage/port_record.h b/libsemanage/include/semanage/port_record.h
index 20ae4bd9..71074800 100644
--- a/libsemanage/include/semanage/port_record.h
+++ b/libsemanage/include/semanage/port_record.h
@@ -16,6 +16,8 @@ typedef struct semanage_port_key semanage_port_key_t;
#define SEMANAGE_PROTO_UDP 0
#define SEMANAGE_PROTO_TCP 1
+#define SEMANAGE_PROTO_DCCP 2
+#define SEMANAGE_PROTO_SCTP 3
/* Key */
extern int semanage_port_compare(const semanage_port_t * port,
diff --git a/libsemanage/src/ports_file.c b/libsemanage/src/ports_file.c
index 46ee2f00..4738d467 100644
--- a/libsemanage/src/ports_file.c
+++ b/libsemanage/src/ports_file.c
@@ -84,6 +84,10 @@ static int port_parse(semanage_handle_t * handle,
semanage_port_set_proto(port, SEMANAGE_PROTO_TCP);
else if (!strcasecmp(str, "udp"))
semanage_port_set_proto(port, SEMANAGE_PROTO_UDP);
+ else if (!strcasecmp(str, "dccp"))
+ semanage_port_set_proto(port, SEMANAGE_PROTO_DCCP);
+ else if (!strcasecmp(str, "sctp"))
+ semanage_port_set_proto(port, SEMANAGE_PROTO_SCTP);
else {
ERR(handle, "invalid protocol \"%s\" (%s: %u):\n%s", str,
info->filename, info->lineno, info->orig_line);
--
2.21.0

View File

@ -0,0 +1,156 @@
From dc4f1d03d6e17d851283f9b10b2faeeca9b10e14 Mon Sep 17 00:00:00 2001
From: Stephen Smalley <stephen.smalley.work@gmail.com>
Date: Wed, 13 May 2020 15:34:19 -0400
Subject: [PATCH] libsemanage: fsync final files before rename
Prior to rename(2)'ing the final selinux policy files into place,
fsync(2) them to ensure the contents will be fully written prior to
rename. While we are here, also fix checking of write(2) to detect
short writes and treat them as an error. This code could be more
generally improved but keeping to the minimal changes required to fix
this bug.
Fixes: https://github.com/SELinuxProject/selinux/issues/237
Signed-off-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
Source:
https://github.com/SELinuxProject/selinux/commit/331a109f91ea46473fd858c2494f6eab1ef43f66
---
libsemanage/src/direct_api.c | 10 +++++-----
libsemanage/src/semanage_store.c | 20 +++++++++++++++-----
libsemanage/src/semanage_store.h | 4 +++-
3 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index 8e4d116d..abc3a4cb 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -1188,7 +1188,7 @@ cleanup:
* overwrite it. If source doesn't exist then return success.
* Returns 0 on success, -1 on error. */
static int copy_file_if_exists(const char *src, const char *dst, mode_t mode){
- int rc = semanage_copy_file(src, dst, mode);
+ int rc = semanage_copy_file(src, dst, mode, false);
return (rc < 0 && errno != ENOENT) ? rc : 0;
}
@@ -1481,7 +1481,7 @@ rebuild:
retval = semanage_copy_file(path,
semanage_path(SEMANAGE_TMP,
SEMANAGE_STORE_SEUSERS),
- 0);
+ 0, false);
if (retval < 0)
goto cleanup;
pseusers->dtable->drop_cache(pseusers->dbase);
@@ -1499,7 +1499,7 @@ rebuild:
retval = semanage_copy_file(path,
semanage_path(SEMANAGE_TMP,
SEMANAGE_USERS_EXTRA),
- 0);
+ 0, false);
if (retval < 0)
goto cleanup;
pusers_extra->dtable->drop_cache(pusers_extra->dbase);
@@ -1588,7 +1588,7 @@ rebuild:
retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL),
- sh->conf->file_mode);
+ sh->conf->file_mode, false);
if (retval < 0) {
goto cleanup;
}
@@ -1627,7 +1627,7 @@ rebuild:
retval = semanage_copy_file(
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_HOMEDIRS),
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_HOMEDIRS),
- sh->conf->file_mode);
+ sh->conf->file_mode, false);
if (retval < 0) {
goto cleanup;
}
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index 58dded6e..733df8da 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -707,7 +707,8 @@ static int semanage_filename_select(const struct dirent *d)
/* Copies a file from src to dst. If dst already exists then
* overwrite it. Returns 0 on success, -1 on error. */
-int semanage_copy_file(const char *src, const char *dst, mode_t mode)
+int semanage_copy_file(const char *src, const char *dst, mode_t mode,
+ bool syncrequired)
{
int in, out, retval = 0, amount_read, n, errsv = errno;
char tmp[PATH_MAX];
@@ -735,8 +736,11 @@ int semanage_copy_file(const char *src, const char *dst, mode_t mode)
}
umask(mask);
while (retval == 0 && (amount_read = read(in, buf, sizeof(buf))) > 0) {
- if (write(out, buf, amount_read) < 0) {
- errsv = errno;
+ if (write(out, buf, amount_read) != amount_read) {
+ if (errno)
+ errsv = errno;
+ else
+ errsv = EIO;
retval = -1;
}
}
@@ -745,6 +749,10 @@ int semanage_copy_file(const char *src, const char *dst, mode_t mode)
retval = -1;
}
close(in);
+ if (syncrequired && fsync(out) < 0) {
+ errsv = errno;
+ retval = -1;
+ }
if (close(out) < 0) {
errsv = errno;
retval = -1;
@@ -811,7 +819,8 @@ static int semanage_copy_dir_flags(const char *src, const char *dst, int flag)
umask(mask);
} else if (S_ISREG(sb.st_mode) && flag == 1) {
mask = umask(0077);
- if (semanage_copy_file(path, path2, sb.st_mode) < 0) {
+ if (semanage_copy_file(path, path2, sb.st_mode,
+ false) < 0) {
umask(mask);
goto cleanup;
}
@@ -1640,7 +1649,8 @@ static int semanage_install_final_tmp(semanage_handle_t * sh)
goto cleanup;
}
- ret = semanage_copy_file(src, dst, sh->conf->file_mode);
+ ret = semanage_copy_file(src, dst, sh->conf->file_mode,
+ true);
if (ret < 0) {
ERR(sh, "Could not copy %s to %s.", src, dst);
goto cleanup;
diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
index 34bf8523..b9ec5664 100644
--- a/libsemanage/src/semanage_store.h
+++ b/libsemanage/src/semanage_store.h
@@ -24,6 +24,7 @@
#ifndef SEMANAGE_MODULE_STORE_H
#define SEMANAGE_MODULE_STORE_H
+#include <stdbool.h>
#include <sys/time.h>
#include <sepol/module.h>
#include <sepol/cil/cil.h>
@@ -162,6 +163,7 @@ int semanage_nc_sort(semanage_handle_t * sh,
size_t buf_len,
char **sorted_buf, size_t * sorted_buf_len);
-int semanage_copy_file(const char *src, const char *dst, mode_t mode);
+int semanage_copy_file(const char *src, const char *dst, mode_t mode,
+ bool syncrequired);
#endif
--
2.25.4

View File

@ -0,0 +1,55 @@
From 11e381e5aa3468aa5c2634f14706336c7824f226 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <plautrba@redhat.com>
Date: Wed, 27 Jan 2021 12:00:55 +0100
Subject: [PATCH] libsemanage: sync filesystem with sandbox
Commit 331a109f91ea ("libsemanage: fsync final files before rename")
added fsync() for policy files and improved situation when something
unexpected happens right after rename(). However the module store could
be affected as well. After the following steps module files could be 0
size:
1. Run `semanage fcontext -a -t var_t "/tmp/abc"`
2. Force shutdown the server during the command is run, or right after
it's finished
3. Boot the system and look for empty files:
# find /var/lib/selinux/targeted/ -type f -size 0 | wc -l
1266
It looks like this situation can be avoided if the filesystem with the
sandbox is sync()ed before we start to rename() directories in the
store.
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: Nicolas Iooss <nicolas.iooss@m4x.org>
---
libsemanage/src/semanage_store.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index 733df8da37c2..ae023582e907 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -1737,6 +1737,19 @@ static int semanage_commit_sandbox(semanage_handle_t * sh)
}
close(fd);
+ /* sync changes in sandbox to filesystem */
+ fd = open(sandbox, O_DIRECTORY);
+ if (fd == -1) {
+ ERR(sh, "Error while opening %s for syncfs(): %d", sandbox, errno);
+ return -1;
+ }
+ if (syncfs(fd) == -1) {
+ ERR(sh, "Error while syncing %s to filesystem: %d", sandbox, errno);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
retval = commit_number;
if (semanage_get_active_lock(sh) < 0) {
--
2.30.0

View File

@ -0,0 +1,76 @@
From ac10bc27090916fe8fcdaf4a9f0e8cc0165f7210 Mon Sep 17 00:00:00 2001
From: Unto Sten <sten.unto@gmail.com>
Date: Sat, 11 May 2019 01:04:16 +0300
Subject: [PATCH] Trivial style fixes
---
libsemanage/src/direct_api.c | 2 +-
libsemanage/src/modules.c | 2 +-
libsemanage/src/seusers_local.c | 2 +-
libsemanage/src/users_local.c | 4 ++--
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index abc3a4cb..b037890a 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -517,7 +517,7 @@ ssize_t bunzip(semanage_handle_t *sh, FILE *f, char **data)
size_t size = 1<<18;
size_t bufsize = size;
int bzerror;
- size_t total=0;
+ size_t total = 0;
char* uncompress = NULL;
char* tmpalloc = NULL;
int ret = -1;
diff --git a/libsemanage/src/modules.c b/libsemanage/src/modules.c
index 62af1018..fa84d33e 100644
--- a/libsemanage/src/modules.c
+++ b/libsemanage/src/modules.c
@@ -1130,7 +1130,7 @@ int semanage_module_install_info(semanage_handle_t *sh,
int semanage_module_remove_key(semanage_handle_t *sh,
const semanage_module_key_t *modkey)
{
- if (sh->funcs->remove_key== NULL) {
+ if (sh->funcs->remove_key == NULL) {
ERR(sh,
"No remove key function defined for this connection type.");
return -1;
diff --git a/libsemanage/src/seusers_local.c b/libsemanage/src/seusers_local.c
index a79e2d3d..3e2761c4 100644
--- a/libsemanage/src/seusers_local.c
+++ b/libsemanage/src/seusers_local.c
@@ -133,7 +133,7 @@ int semanage_seuser_modify_local(semanage_handle_t * handle,
semanage_seuser_t *new = NULL;
if (!sename) {
- errno=EINVAL;
+ errno = EINVAL;
return -1;
}
rc = semanage_seuser_clone(handle, data, &new);
diff --git a/libsemanage/src/users_local.c b/libsemanage/src/users_local.c
index 7aa43d44..8193476d 100644
--- a/libsemanage/src/users_local.c
+++ b/libsemanage/src/users_local.c
@@ -38,7 +38,7 @@ static int lookup_seuser(semanage_handle_t * handle, const semanage_user_key_t *
semanage_seuser_list_local(handle,
&records,
&count);
- for(i=0; i<count; i++) {
+ for(i = 0; i < count; i++) {
sename = semanage_seuser_get_sename(records[i]);
if (strcmp(name, sename) == 0) {
errno = EINVAL;
@@ -47,7 +47,7 @@ static int lookup_seuser(semanage_handle_t * handle, const semanage_user_key_t *
rc = -1;
}
}
- for(i=0; i<count; i++)
+ for(i = 0; i < count; i++)
semanage_seuser_free(records[i]);
free(records);
semanage_user_free(user);
--
2.30.2

View File

@ -0,0 +1,31 @@
From e14a8a078b2cfecb0498ff98ddff08403b3be1cd Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 17 Dec 2020 15:59:49 +0100
Subject: [PATCH] libsemanage: Free contents of modkey in
semanage_direct_remove
semanage_direct_remove allocates struct semanage_module_key_t on
stack, then calls semanage_module_key_set_name which allocates
modkey->name on heap, but modkey->name wasn't free()-d anywhere,
creating a small leak.
Signed-off-by: Jakub Hrozek <jhrozek@redhat.com>
---
libsemanage/src/direct_api.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index b037890a..c32939c0 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -1944,6 +1944,7 @@ static int semanage_direct_remove(semanage_handle_t * sh, char *module_name)
status = semanage_direct_remove_key(sh, &modkey);
cleanup:
+ semanage_module_key_destroy(sh, &modkey);
return status;
}
--
2.30.2

View File

@ -0,0 +1,42 @@
From 30da7a4907893bd43fe9da40728a3bcabdf3d7a4 Mon Sep 17 00:00:00 2001
From: Petr Lautrbach <plautrba@redhat.com>
Date: Wed, 28 Jul 2021 11:21:35 +0200
Subject: [PATCH] libsemanage: Fix USE_AFTER_FREE (CWE-672) in
semanage_direct_write_langext()
>From fclose(3):
Upon successful completion, 0 is returned. Otherwise, EOF is returned
and errno is set to indicate the error. In either case, any further
access (including another call to fclose()) to the stream results in
undefined behavior.
Fixes:
Error: USE_AFTER_FREE (CWE-672): [#def1]
libsemanage-3.2/src/direct_api.c:1023: freed_arg: "fclose" frees "fp".
libsemanage-3.2/src/direct_api.c:1034: use_closed_file: Calling "fclose" uses file handle "fp" after closing it.
# 1032|
# 1033| cleanup:
# 1034|-> if (fp != NULL) fclose(fp);
# 1035|
# 1036| return ret;
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
---
libsemanage/src/direct_api.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index c32939c0..7638653a 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -1022,6 +1022,7 @@ static int semanage_direct_write_langext(semanage_handle_t *sh,
if (fclose(fp) != 0) {
ERR(sh, "Unable to close %s module ext file.", modinfo->name);
+ fp = NULL;
ret = -1;
goto cleanup;
}
--
2.30.2

View File

@ -0,0 +1,37 @@
From ecf6e6a9fda1a28cc3df36841b44326ed0c12312 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Thu, 3 Feb 2022 17:53:22 +0100
Subject: [PATCH] libsemanage: add missing include to boolean_record.c
It uses asprintf(3), but doesn't directly include <stdio.h> - fix it.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
libsemanage/src/boolean_record.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/libsemanage/src/boolean_record.c b/libsemanage/src/boolean_record.c
index c234094e..bdddfa23 100644
--- a/libsemanage/src/boolean_record.c
+++ b/libsemanage/src/boolean_record.c
@@ -7,6 +7,9 @@
*/
#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <sepol/boolean_record.h>
#include "handle_internal.h"
@@ -21,7 +24,6 @@ typedef semanage_bool_key_t record_key_t;
#include "boolean_internal.h"
#include "handle.h"
#include "database.h"
-#include <stdlib.h>
#include <selinux/selinux.h>
/* Key */
--
2.30.2

View File

@ -0,0 +1,555 @@
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>
---
libsemanage/include/semanage/modules.h | 26 +++
libsemanage/src/libsemanage.map | 4 +
libsemanage/src/modules.c | 59 +++++
libsemanage/src/sha256.c | 294 +++++++++++++++++++++++++
libsemanage/src/sha256.h | 89 ++++++++
5 files changed, 472 insertions(+)
create mode 100644 libsemanage/src/sha256.c
create mode 100644 libsemanage/src/sha256.h
diff --git a/libsemanage/include/semanage/modules.h b/libsemanage/include/semanage/modules.h
index 4b93e54e..26ac40b2 100644
--- a/libsemanage/include/semanage/modules.h
+++ b/libsemanage/include/semanage/modules.h
@@ -282,4 +282,30 @@ 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 02036696..a986b2d2 100644
--- a/libsemanage/src/libsemanage.map
+++ b/libsemanage/src/libsemanage.map
@@ -63,3 +63,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 fa84d33e..3a82d275 100644
--- a/libsemanage/src/modules.c
+++ b/libsemanage/src/modules.c
@@ -34,11 +34,13 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <errno.h>
#include <ctype.h>
#include "handle.h"
#include "modules.h"
+#include "sha256.h"
#include "debug.h"
asm(".symver semanage_module_get_enabled_1_1,semanage_module_get_enabled@@LIBSEMANAGE_1.1");
@@ -1146,3 +1148,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/sha256.c b/libsemanage/src/sha256.c
new file mode 100644
index 00000000..fe2aeef0
--- /dev/null
+++ b/libsemanage/src/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/libsemanage/src/sha256.h b/libsemanage/src/sha256.h
new file mode 100644
index 00000000..406ed869
--- /dev/null
+++ b/libsemanage/src/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.30.2

View File

@ -0,0 +1,824 @@
From f8c74eaf19df123deabe9e2c71bd5b3c2beba06a Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Thu, 3 Feb 2022 17:53:24 +0100
Subject: [PATCH] libsemanage: move compressed file handling into a separate
object
In order to reduce exisiting and future code duplication and to avoid
some unnecessary allocations and copying, factor the compressed file
utility functions out into a separate C/header file and refactor their
interface.
Note that this change effectively removes the __fsetlocking(3) call from
semanage_load_files() - I haven't been able to figure out what purpose
it serves, but it seems pointless...
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
libsemanage/src/compressed_file.c | 224 +++++++++++++++++++++++++
libsemanage/src/compressed_file.h | 78 +++++++++
libsemanage/src/direct_api.c | 263 +++++-------------------------
libsemanage/src/direct_api.h | 4 -
libsemanage/src/semanage_store.c | 52 ++----
5 files changed, 354 insertions(+), 267 deletions(-)
create mode 100644 libsemanage/src/compressed_file.c
create mode 100644 libsemanage/src/compressed_file.h
diff --git a/libsemanage/src/compressed_file.c b/libsemanage/src/compressed_file.c
new file mode 100644
index 00000000..5546b830
--- /dev/null
+++ b/libsemanage/src/compressed_file.c
@@ -0,0 +1,224 @@
+/* Author: Jason Tang <jtang@tresys.com>
+ * Christopher Ashworth <cashworth@tresys.com>
+ * Ondrej Mosnacek <omosnacek@gmail.com>
+ *
+ * Copyright (C) 2004-2006 Tresys Technology, LLC
+ * Copyright (C) 2005-2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <bzlib.h>
+
+#include "compressed_file.h"
+
+#include "debug.h"
+
+#define BZ2_MAGICSTR "BZh"
+#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
+
+/* bzip() a data to a file, returning the total number of compressed bytes
+ * in the file. Returns -1 if file could not be compressed. */
+static int bzip(semanage_handle_t *sh, const char *filename, void *data,
+ size_t num_bytes)
+{
+ BZFILE* b;
+ size_t size = 1<<16;
+ int bzerror;
+ size_t total = 0;
+ size_t len = 0;
+ FILE *f;
+
+ if ((f = fopen(filename, "wb")) == NULL) {
+ return -1;
+ }
+
+ if (!sh->conf->bzip_blocksize) {
+ if (fwrite(data, 1, num_bytes, f) < num_bytes) {
+ fclose(f);
+ return -1;
+ }
+ fclose(f);
+ return 0;
+ }
+
+ b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
+ if (bzerror != BZ_OK) {
+ BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
+ fclose(f);
+ return -1;
+ }
+
+ while ( num_bytes > total ) {
+ if (num_bytes - total > size) {
+ len = size;
+ } else {
+ len = num_bytes - total;
+ }
+ BZ2_bzWrite ( &bzerror, b, (uint8_t *)data + total, len );
+ if (bzerror == BZ_IO_ERROR) {
+ BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
+ fclose(f);
+ return -1;
+ }
+ total += len;
+ }
+
+ BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
+ fclose(f);
+ if (bzerror == BZ_IO_ERROR) {
+ return -1;
+ }
+ return 0;
+}
+
+/* bunzip() a file to '*data', returning the total number of uncompressed bytes
+ * in the file. Returns -1 if file could not be decompressed. */
+static ssize_t bunzip(semanage_handle_t *sh, FILE *f, void **data)
+{
+ BZFILE* b = NULL;
+ size_t nBuf;
+ uint8_t* buf = NULL;
+ size_t size = 1<<18;
+ size_t bufsize = size;
+ int bzerror;
+ size_t total = 0;
+ uint8_t* uncompress = NULL;
+ uint8_t* tmpalloc = NULL;
+ int ret = -1;
+
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ ERR(sh, "Failure allocating memory.");
+ goto exit;
+ }
+
+ /* Check if the file is bzipped */
+ bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
+ rewind(f);
+ if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
+ goto exit;
+ }
+
+ b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
+ if ( bzerror != BZ_OK ) {
+ ERR(sh, "Failure opening bz2 archive.");
+ goto exit;
+ }
+
+ uncompress = malloc(size);
+ if (uncompress == NULL) {
+ ERR(sh, "Failure allocating memory.");
+ goto exit;
+ }
+
+ while ( bzerror == BZ_OK) {
+ nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
+ if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
+ if (total + nBuf > size) {
+ size *= 2;
+ tmpalloc = realloc(uncompress, size);
+ if (tmpalloc == NULL) {
+ ERR(sh, "Failure allocating memory.");
+ goto exit;
+ }
+ uncompress = tmpalloc;
+ }
+ memcpy(&uncompress[total], buf, nBuf);
+ total += nBuf;
+ }
+ }
+ if ( bzerror != BZ_STREAM_END ) {
+ ERR(sh, "Failure reading bz2 archive.");
+ goto exit;
+ }
+
+ ret = total;
+ *data = uncompress;
+
+exit:
+ BZ2_bzReadClose ( &bzerror, b );
+ free(buf);
+ if ( ret < 0 ) {
+ free(uncompress);
+ }
+ return ret;
+}
+
+int map_compressed_file(semanage_handle_t *sh, const char *path,
+ struct file_contents *contents)
+{
+ ssize_t size = -1;
+ void *uncompress;
+ int ret = 0, fd = -1;
+ FILE *file = NULL;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ ERR(sh, "Unable to open %s\n", path);
+ return -1;
+ }
+
+ file = fdopen(fd, "r");
+ if (file == NULL) {
+ ERR(sh, "Unable to open %s\n", path);
+ close(fd);
+ return -1;
+ }
+
+ if ((size = bunzip(sh, file, &uncompress)) >= 0) {
+ contents->data = uncompress;
+ contents->len = size;
+ contents->compressed = 1;
+ } else {
+ struct stat sb;
+ if (fstat(fd, &sb) == -1 ||
+ (uncompress = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
+ MAP_FAILED) {
+ ret = -1;
+ } else {
+ contents->data = uncompress;
+ contents->len = sb.st_size;
+ contents->compressed = 0;
+ }
+ }
+ fclose(file);
+ return ret;
+}
+
+void unmap_compressed_file(struct file_contents *contents)
+{
+ if (!contents->data)
+ return;
+
+ if (contents->compressed) {
+ free(contents->data);
+ } else {
+ munmap(contents->data, contents->len);
+ }
+}
+
+int write_compressed_file(semanage_handle_t *sh, const char *path,
+ void *data, size_t len)
+{
+ return bzip(sh, path, data, len);
+}
diff --git a/libsemanage/src/compressed_file.h b/libsemanage/src/compressed_file.h
new file mode 100644
index 00000000..96cfb4b6
--- /dev/null
+++ b/libsemanage/src/compressed_file.h
@@ -0,0 +1,78 @@
+/* Author: Jason Tang <jtang@tresys.com>
+ * Christopher Ashworth <cashworth@tresys.com>
+ * Ondrej Mosnacek <omosnacek@gmail.com>
+ *
+ * Copyright (C) 2004-2006 Tresys Technology, LLC
+ * Copyright (C) 2005-2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _SEMANAGE_CIL_FILE_H_
+#define _SEMANAGE_CIL_FILE_H_
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include "handle.h"
+
+struct file_contents {
+ void *data; /** file contents (uncompressed) */
+ size_t len; /** length of contents */
+ int compressed; /** whether file was compressed */
+};
+
+/**
+ * Map/read a possibly-compressed file into memory.
+ *
+ * If the file is bzip compressed map_file will uncompress the file into
+ * @p contents. The caller is responsible for calling
+ * @ref unmap_compressed_file on @p contents on success.
+ *
+ * @param sh semanage handle
+ * @param path path to the file
+ * @param contents pointer to struct file_contents, which will be
+ * populated with data pointer, size, and an indication whether
+ * the file was compressed or not
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int map_compressed_file(semanage_handle_t *sh, const char *path,
+ struct file_contents *contents);
+
+/**
+ * Destroy a previously mapped possibly-compressed file.
+ *
+ * If all fields of @p contents are zero/NULL, the function is
+ * guaranteed to do nothing.
+ *
+ * @param contents pointer to struct file_contents to destroy
+ */
+void unmap_compressed_file(struct file_contents *contents);
+
+/**
+ * Write bytes into a file, using compression if configured.
+ *
+ * @param sh semanage handle
+ * @param path path to the file
+ * @param data pointer to the data
+ * @param len length of the data
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int write_compressed_file(semanage_handle_t *sh, const char *path,
+ void *data, size_t len);
+
+#endif
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index 7638653a..63a18808 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -50,6 +50,7 @@
#include "debug.h"
#include "handle.h"
+#include "compressed_file.h"
#include "modules.h"
#include "direct_api.h"
#include "semanage_store.h"
@@ -446,194 +447,6 @@ static int parse_module_headers(semanage_handle_t * sh, char *module_data,
return 0;
}
-#include <stdlib.h>
-#include <bzlib.h>
-#include <string.h>
-#include <sys/sendfile.h>
-
-/* bzip() a data to a file, returning the total number of compressed bytes
- * in the file. Returns -1 if file could not be compressed. */
-static ssize_t bzip(semanage_handle_t *sh, const char *filename, char *data,
- size_t num_bytes)
-{
- BZFILE* b;
- size_t size = 1<<16;
- int bzerror;
- size_t total = 0;
- size_t len = 0;
- FILE *f;
-
- if ((f = fopen(filename, "wb")) == NULL) {
- return -1;
- }
-
- if (!sh->conf->bzip_blocksize) {
- if (fwrite(data, 1, num_bytes, f) < num_bytes) {
- fclose(f);
- return -1;
- }
- fclose(f);
- return num_bytes;
- }
-
- b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
- if (bzerror != BZ_OK) {
- BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
- return -1;
- }
-
- while ( num_bytes > total ) {
- if (num_bytes - total > size) {
- len = size;
- } else {
- len = num_bytes - total;
- }
- BZ2_bzWrite ( &bzerror, b, &data[total], len );
- if (bzerror == BZ_IO_ERROR) {
- BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
- return -1;
- }
- total += len;
- }
-
- BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
- fclose(f);
- if (bzerror == BZ_IO_ERROR) {
- return -1;
- }
- return total;
-}
-
-#define BZ2_MAGICSTR "BZh"
-#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
-
-/* bunzip() a file to '*data', returning the total number of uncompressed bytes
- * in the file. Returns -1 if file could not be decompressed. */
-ssize_t bunzip(semanage_handle_t *sh, FILE *f, char **data)
-{
- BZFILE* b = NULL;
- size_t nBuf;
- char* buf = NULL;
- size_t size = 1<<18;
- size_t bufsize = size;
- int bzerror;
- size_t total = 0;
- char* uncompress = NULL;
- char* tmpalloc = NULL;
- int ret = -1;
-
- buf = malloc(bufsize);
- if (buf == NULL) {
- ERR(sh, "Failure allocating memory.");
- goto exit;
- }
-
- /* Check if the file is bzipped */
- bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
- rewind(f);
- if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
- goto exit;
- }
-
- b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
- if ( bzerror != BZ_OK ) {
- ERR(sh, "Failure opening bz2 archive.");
- goto exit;
- }
-
- uncompress = malloc(size);
- if (uncompress == NULL) {
- ERR(sh, "Failure allocating memory.");
- goto exit;
- }
-
- while ( bzerror == BZ_OK) {
- nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
- if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
- if (total + nBuf > size) {
- size *= 2;
- tmpalloc = realloc(uncompress, size);
- if (tmpalloc == NULL) {
- ERR(sh, "Failure allocating memory.");
- goto exit;
- }
- uncompress = tmpalloc;
- }
- memcpy(&uncompress[total], buf, nBuf);
- total += nBuf;
- }
- }
- if ( bzerror != BZ_STREAM_END ) {
- ERR(sh, "Failure reading bz2 archive.");
- goto exit;
- }
-
- ret = total;
- *data = uncompress;
-
-exit:
- BZ2_bzReadClose ( &bzerror, b );
- free(buf);
- if ( ret < 0 ) {
- free(uncompress);
- }
- return ret;
-}
-
-/* mmap() a file to '*data',
- * If the file is bzip compressed map_file will uncompress
- * the file into '*data'.
- * Returns the total number of bytes in memory .
- * Returns -1 if file could not be opened or mapped. */
-static ssize_t map_file(semanage_handle_t *sh, const char *path, char **data,
- int *compressed)
-{
- ssize_t size = -1;
- char *uncompress;
- int fd = -1;
- FILE *file = NULL;
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- ERR(sh, "Unable to open %s\n", path);
- return -1;
- }
-
- file = fdopen(fd, "r");
- if (file == NULL) {
- ERR(sh, "Unable to open %s\n", path);
- close(fd);
- return -1;
- }
-
- if ((size = bunzip(sh, file, &uncompress)) > 0) {
- *data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
- if (*data == MAP_FAILED) {
- free(uncompress);
- fclose(file);
- return -1;
- } else {
- memcpy(*data, uncompress, size);
- }
- free(uncompress);
- *compressed = 1;
- } else {
- struct stat sb;
- if (fstat(fd, &sb) == -1 ||
- (*data = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
- MAP_FAILED) {
- size = -1;
- } else {
- size = sb.st_size;
- }
- *compressed = 0;
- }
-
- fclose(file);
-
- return size;
-}
-
/* Writes a block of data to a file. Returns 0 on success, -1 on
* error. */
static int write_file(semanage_handle_t * sh,
@@ -1045,15 +858,12 @@ static int semanage_compile_module(semanage_handle_t *sh,
char *compiler_path = NULL;
char *cil_data = NULL;
char *err_data = NULL;
- char *hll_data = NULL;
char *start = NULL;
char *end = NULL;
- ssize_t hll_data_len = 0;
- ssize_t bzip_status;
int status = 0;
- int compressed;
size_t cil_data_len = 0;
size_t err_data_len = 0;
+ struct file_contents hll_contents = {};
if (!strcasecmp(modinfo->lang_ext, "cil")) {
goto cleanup;
@@ -1084,13 +894,15 @@ static int semanage_compile_module(semanage_handle_t *sh,
goto cleanup;
}
- if ((hll_data_len = map_file(sh, hll_path, &hll_data, &compressed)) <= 0) {
+ status = map_compressed_file(sh, hll_path, &hll_contents);
+ if (status < 0) {
ERR(sh, "Unable to read file %s\n", hll_path);
- status = -1;
goto cleanup;
}
- status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len);
+ status = semanage_pipe_data(sh, compiler_path, hll_contents.data,
+ hll_contents.len, &cil_data, &cil_data_len,
+ &err_data, &err_data_len);
if (err_data_len > 0) {
for (start = end = err_data; end < err_data + err_data_len; end++) {
if (*end == '\n') {
@@ -1110,10 +922,9 @@ static int semanage_compile_module(semanage_handle_t *sh,
goto cleanup;
}
- bzip_status = bzip(sh, cil_path, cil_data, cil_data_len);
- if (bzip_status == -1) {
- ERR(sh, "Failed to bzip %s\n", cil_path);
- status = -1;
+ status = write_compressed_file(sh, cil_path, cil_data, cil_data_len);
+ if (status == -1) {
+ ERR(sh, "Failed to write %s\n", cil_path);
goto cleanup;
}
@@ -1131,9 +942,7 @@ static int semanage_compile_module(semanage_handle_t *sh,
}
cleanup:
- if (hll_data_len > 0) {
- munmap(hll_data, hll_data_len);
- }
+ unmap_compressed_file(&hll_contents);
free(cil_data);
free(err_data);
free(compiler_path);
@@ -1749,19 +1558,17 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
{
int retval = -1;
- char *data = NULL;
- ssize_t data_len = 0;
- int compressed = 0;
char *path = NULL;
char *filename;
char *lang_ext = NULL;
char *module_name = NULL;
char *separator;
char *version = NULL;
+ struct file_contents contents = {};
- if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) {
+ retval = map_compressed_file(sh, install_filename, &contents);
+ if (retval < 0) {
ERR(sh, "Unable to read file %s\n", install_filename);
- retval = -1;
goto cleanup;
}
@@ -1774,7 +1581,7 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
filename = basename(path);
- if (compressed) {
+ if (contents.compressed) {
separator = strrchr(filename, '.');
if (separator == NULL) {
ERR(sh, "Compressed module does not have a valid extension.");
@@ -1798,7 +1605,8 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
}
if (strcmp(lang_ext, "pp") == 0) {
- retval = parse_module_headers(sh, data, data_len, &module_name, &version);
+ retval = parse_module_headers(sh, contents.data, contents.len,
+ &module_name, &version);
free(version);
if (retval != 0)
goto cleanup;
@@ -1815,10 +1623,11 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
fprintf(stderr, "Warning: SELinux userspace will refer to the module from %s as %s rather than %s\n", install_filename, module_name, filename);
}
- retval = semanage_direct_install(sh, data, data_len, module_name, lang_ext);
+ retval = semanage_direct_install(sh, contents.data, contents.len,
+ module_name, lang_ext);
cleanup:
- if (data_len > 0) munmap(data, data_len);
+ unmap_compressed_file(&contents);
free(module_name);
free(path);
@@ -1837,10 +1646,8 @@ static int semanage_direct_extract(semanage_handle_t * sh,
enum semanage_module_path_type file_type;
int rc = -1;
semanage_module_info_t *_modinfo = NULL;
- ssize_t _data_len;
- char *_data;
- int compressed;
struct stat sb;
+ struct file_contents contents = {};
/* get path of module */
rc = semanage_module_get_path(
@@ -1896,19 +1703,33 @@ static int semanage_direct_extract(semanage_handle_t * sh,
}
}
- _data_len = map_file(sh, input_file, &_data, &compressed);
- if (_data_len <= 0) {
+ rc = map_compressed_file(sh, input_file, &contents);
+ if (rc < 0) {
ERR(sh, "Error mapping file: %s", input_file);
- rc = -1;
goto cleanup;
}
+ /* The API promises an mmap'ed pointer */
+ if (contents.compressed) {
+ *mapped_data = mmap(NULL, contents.len, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ if (*mapped_data == MAP_FAILED) {
+ ERR(sh, "Unable to map memory");
+ rc = -1;
+ goto cleanup;
+ }
+ memcpy(*mapped_data, contents.data, contents.len);
+ free(contents.data);
+ } else {
+ *mapped_data = contents.data;
+ }
+
*modinfo = _modinfo;
- *data_len = (size_t)_data_len;
- *mapped_data = _data;
+ *data_len = contents.len;
cleanup:
if (rc != 0) {
+ unmap_compressed_file(&contents);
semanage_module_info_destroy(sh, _modinfo);
free(_modinfo);
}
@@ -2857,8 +2678,8 @@ static int semanage_direct_install_info(semanage_handle_t *sh,
goto cleanup;
}
- ret = bzip(sh, path, data, data_len);
- if (ret <= 0) {
+ ret = write_compressed_file(sh, path, data, data_len);
+ if (ret < 0) {
ERR(sh, "Error while writing to %s.", path);
status = -3;
goto cleanup;
diff --git a/libsemanage/src/direct_api.h b/libsemanage/src/direct_api.h
index e56107b2..ffd428eb 100644
--- a/libsemanage/src/direct_api.h
+++ b/libsemanage/src/direct_api.h
@@ -39,8 +39,4 @@ int semanage_direct_access_check(struct semanage_handle *sh);
int semanage_direct_mls_enabled(struct semanage_handle *sh);
-#include <stdio.h>
-#include <unistd.h>
-ssize_t bunzip(struct semanage_handle *sh, FILE *f, char **data);
-
#endif
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index ae023582..c5ce071c 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -59,6 +59,7 @@ typedef struct dbase_policydb dbase_t;
#include "debug.h"
#include "utilities.h"
+#include "compressed_file.h"
#define SEMANAGE_CONF_FILE "semanage.conf"
/* relative path names to enum semanage_paths to special files and
@@ -2055,60 +2056,27 @@ int semanage_direct_get_serial(semanage_handle_t * sh)
int semanage_load_files(semanage_handle_t * sh, cil_db_t *cildb, char **filenames, int numfiles)
{
- int retval = 0;
- FILE *fp;
- ssize_t size;
- char *data = NULL;
+ int i, retval = 0;
char *filename;
- int i;
+ struct file_contents contents = {};
for (i = 0; i < numfiles; i++) {
filename = filenames[i];
- if ((fp = fopen(filename, "rb")) == NULL) {
- ERR(sh, "Could not open module file %s for reading.", filename);
- goto cleanup;
- }
-
- if ((size = bunzip(sh, fp, &data)) <= 0) {
- rewind(fp);
- __fsetlocking(fp, FSETLOCKING_BYCALLER);
-
- if (fseek(fp, 0, SEEK_END) != 0) {
- ERR(sh, "Failed to determine size of file %s.", filename);
- goto cleanup;
- }
- size = ftell(fp);
- rewind(fp);
-
- data = malloc(size);
- if (fread(data, size, 1, fp) != 1) {
- ERR(sh, "Failed to read file %s.", filename);
- goto cleanup;
- }
- }
+ retval = map_compressed_file(sh, filename, &contents);
+ if (retval < 0)
+ return -1;
- fclose(fp);
- fp = NULL;
+ retval = cil_add_file(cildb, filename, contents.data, contents.len);
+ unmap_compressed_file(&contents);
- retval = cil_add_file(cildb, filename, data, size);
if (retval != SEPOL_OK) {
ERR(sh, "Error while reading from file %s.", filename);
- goto cleanup;
+ return -1;
}
-
- free(data);
- data = NULL;
}
- return retval;
-
- cleanup:
- if (fp != NULL) {
- fclose(fp);
- }
- free(data);
- return -1;
+ return 0;
}
/*
--
2.30.2

View File

@ -0,0 +1,150 @@
From 129e121c9ab17f726a9a6294cfe04db97016e7ef Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Thu, 3 Feb 2022 17:53:25 +0100
Subject: [PATCH] libsemanage: clean up semanage_direct_commit() a bit
Do some minor cosmetic cleanup, mainly to eliminate the 'rebuilt' goto
label.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
libsemanage/src/direct_api.c | 91 ++++++++++++++++++------------------
1 file changed, 45 insertions(+), 46 deletions(-)
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index 63a18808..7e99a59f 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -994,6 +994,16 @@ cleanup:
return status;
}
+/* Files that must exist in order to skip policy rebuild. */
+static const int semanage_computed_files[] = {
+ SEMANAGE_STORE_KERNEL,
+ SEMANAGE_STORE_FC,
+ SEMANAGE_STORE_SEUSERS,
+ SEMANAGE_LINKED,
+ SEMANAGE_SEUSERS_LINKED,
+ SEMANAGE_USERS_EXTRA_LINKED
+};
+
/* Copies a file from src to dst. If dst already exists then
* overwrite it. If source doesn't exist then return success.
* Returns 0 on success, -1 on error. */
@@ -1053,6 +1063,14 @@ static int semanage_direct_commit(semanage_handle_t * sh)
seusers_modified = seusers->dtable->is_modified(seusers->dbase);
fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
+ /* Before we do anything else, flush the join to its component parts.
+ * This *does not* flush to disk automatically */
+ if (users->dtable->is_modified(users->dbase)) {
+ retval = users->dtable->flush(sh, users->dbase);
+ if (retval < 0)
+ goto cleanup;
+ }
+
/* Rebuild if explicitly requested or any module changes occurred. */
do_rebuild = sh->do_rebuild | sh->modules_modified;
@@ -1119,14 +1137,6 @@ static int semanage_direct_commit(semanage_handle_t * sh)
}
}
- /* Before we do anything else, flush the join to its component parts.
- * This *does not* flush to disk automatically */
- if (users->dtable->is_modified(users->dbase)) {
- retval = users->dtable->flush(sh, users->dbase);
- if (retval < 0)
- goto cleanup;
- }
-
/*
* This is for systems that have already migrated with an older version
* of semanage_migrate_store. The older version did not copy
@@ -1135,48 +1145,20 @@ static int semanage_direct_commit(semanage_handle_t * sh)
* in order to skip re-linking are present; otherwise, we force
* a rebuild.
*/
- if (!do_rebuild) {
- int files[] = {SEMANAGE_STORE_KERNEL,
- SEMANAGE_STORE_FC,
- SEMANAGE_STORE_SEUSERS,
- SEMANAGE_LINKED,
- SEMANAGE_SEUSERS_LINKED,
- SEMANAGE_USERS_EXTRA_LINKED};
-
- for (i = 0; i < (int) ARRAY_SIZE(files); i++) {
- path = semanage_path(SEMANAGE_TMP, files[i]);
- if (stat(path, &sb) != 0) {
- if (errno != ENOENT) {
- ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
- retval = -1;
- goto cleanup;
- }
-
- do_rebuild = 1;
- goto rebuild;
+ for (i = 0; !do_rebuild && i < (int)ARRAY_SIZE(semanage_computed_files); i++) {
+ path = semanage_path(SEMANAGE_TMP, semanage_computed_files[i]);
+ if (stat(path, &sb) != 0) {
+ if (errno != ENOENT) {
+ ERR(sh, "Unable to access %s: %s\n", path, strerror(errno));
+ retval = -1;
+ goto cleanup;
}
+
+ do_rebuild = 1;
+ break;
}
}
-rebuild:
- /*
- * Now that we know whether or not a rebuild is required,
- * we can determine what else needs to be done.
- * We need to write the kernel policy if we are rebuilding
- * or if any other policy component that lives in the kernel
- * policy has been modified.
- * We need to install the policy files if any of the managed files
- * that live under /etc/selinux (kernel policy, seusers, file contexts)
- * will be modified.
- */
- do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified |
- ibendports_modified |
- bools->dtable->is_modified(bools->dbase) |
- ifaces->dtable->is_modified(ifaces->dbase) |
- nodes->dtable->is_modified(nodes->dbase) |
- users->dtable->is_modified(users_base->dbase);
- do_install = do_write_kernel | seusers_modified | fcontexts_modified;
-
/*
* If there were policy changes, or explicitly requested, or
* any required files are missing, rebuild the policy.
@@ -1323,6 +1305,23 @@ rebuild:
}
}
+ /*
+ * Determine what else needs to be done.
+ * We need to write the kernel policy if we are rebuilding
+ * or if any other policy component that lives in the kernel
+ * policy has been modified.
+ * We need to install the policy files if any of the managed files
+ * that live under /etc/selinux (kernel policy, seusers, file contexts)
+ * will be modified.
+ */
+ do_write_kernel = do_rebuild | ports_modified | ibpkeys_modified |
+ ibendports_modified |
+ bools->dtable->is_modified(bools->dbase) |
+ ifaces->dtable->is_modified(ifaces->dbase) |
+ nodes->dtable->is_modified(nodes->dbase) |
+ users->dtable->is_modified(users_base->dbase);
+ do_install = do_write_kernel | seusers_modified | fcontexts_modified;
+
/* Attach our databases to the policydb we just created or loaded. */
dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase, out);
dbase_policydb_attach((dbase_policydb_t *) pports->dbase, out);
--
2.30.2

View File

@ -0,0 +1,492 @@
From 090a82e33be97d42eaa75bec85a32ccb6b7a13e8 Mon Sep 17 00:00:00 2001
From: Ondrej Mosnacek <omosnace@redhat.com>
Date: Thu, 3 Feb 2022 17:53:26 +0100
Subject: [PATCH] libsemanage: optionally rebuild policy when modules are
changed externally
In Fedora/RHEL's selinux-policy package we ship a pre-built SELinux
policy store in the RPMs. When updating the main policy RPM, care must
be taken to rebuild the policy using `semodule -B` if there are any
other SELinux modules installed (whether shipped via another RPM or
manually installed locally).
However, this way of shipping/managing the policy creates complications
on systems, where system files are managed by rpm-ostree (such as Fedora
CoreOS or Red Hat CoreOS), where the "package update" process is more
sophisticated.
(Disclaimer: The following is written according to my current limited
understanding of rpm-ostree and may not be entirely accurate, but the
gist of it should match the reality.)
Basically, one can think of rpm-ostree as a kind of Git for system
files. The package content is provided on a "branch", where each
"commit" represents a set of package updates layered on top of the
previous commit (i.e. it is a rolling release with some defined
package content snapshots). The user can then maintain their own branch
with additional package updates/installations/... and "rebase" it on top
of the main branch as needed. On top of that, the user can also have
additional configuration files (or modifications to existing files) in
/etc, which represent an additional layer on top of the package content.
When updating the system (i.e. rebasing on a new "commit" of the "main
branch"), the files on the running system are not touched and the new
system state is prepared under a new root directory, which is chrooted
into on the next reboot.
When an rpm-ostree system is updated, there are three moments when the
SELinux module store needs to be rebuilt to ensure that all modules are
included in the binary policy:
1. When the local RPM installations are applied on top of the base
system snapshot.
2. When local user configuartion is applied on top of that.
3. On system shutdown, to ensure that any changes in local configuration
performed since (2.) are reflected in the final new system image.
Forcing a full rebuild at each step is not optimal and in many cases is
not necessary, as the user may not have any custom modules installed.
Thus, this patch extends libsemanage to compute a checksum of the
content of all enabled modules, which is stored in the store, and adds a
flag to the libsemanage handle that instructs it to check the module
content checksum against the one from the last successful transaction
and force a full policy rebuild if they don't match.
This will allow rpm-ostree systems to potentially reduce delays when
reconciling the module store when applying updates.
I wasn't able to measure any noticeable overhead of the hash
computation, which is now added for every transaction (both before and
after this change a full policy rebuild took about 7 seconds on my test
x86 VM). With the new option check_ext_changes enabled, rebuilding a
policy store with unchanged modules took only about 0.96 seconds.
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
libsemanage/include/semanage/handle.h | 5 +
libsemanage/src/direct_api.c | 187 +++++++++++++++++++++-----
libsemanage/src/handle.c | 11 +-
libsemanage/src/handle.h | 1 +
libsemanage/src/libsemanage.map | 1 +
libsemanage/src/modules.c | 4 +-
libsemanage/src/modules.h | 3 +
libsemanage/src/semanage_store.c | 1 +
libsemanage/src/semanage_store.h | 1 +
9 files changed, 175 insertions(+), 39 deletions(-)
diff --git a/libsemanage/include/semanage/handle.h b/libsemanage/include/semanage/handle.h
index c8165900..7f298a49 100644
--- a/libsemanage/include/semanage/handle.h
+++ b/libsemanage/include/semanage/handle.h
@@ -66,6 +66,11 @@ void semanage_set_reload(semanage_handle_t * handle, int do_reload);
* 1 for yes, 0 for no (default) */
void semanage_set_rebuild(semanage_handle_t * handle, int do_rebuild);
+/* set whether to rebuild the policy on commit when potential changes
+ * to module files since last rebuild are detected,
+ * 1 for yes (default), 0 for no */
+extern void semanage_set_check_ext_changes(semanage_handle_t * handle, int do_check);
+
/* Fills *compiler_path with the location of the hll compiler sh->conf->compiler_directory_path
* corresponding to lang_ext.
* Upon success returns 0, -1 on error. */
diff --git a/libsemanage/src/direct_api.c b/libsemanage/src/direct_api.c
index 7e99a59f..bbdca2b2 100644
--- a/libsemanage/src/direct_api.c
+++ b/libsemanage/src/direct_api.c
@@ -33,6 +33,8 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
#include <limits.h>
#include <errno.h>
#include <dirent.h>
@@ -56,8 +58,7 @@
#include "semanage_store.h"
#include "database_policydb.h"
#include "policy.h"
-#include <sys/mman.h>
-#include <sys/wait.h>
+#include "sha256.h"
#define PIPE_READ 0
#define PIPE_WRITE 1
@@ -450,7 +451,7 @@ static int parse_module_headers(semanage_handle_t * sh, char *module_data,
/* Writes a block of data to a file. Returns 0 on success, -1 on
* error. */
static int write_file(semanage_handle_t * sh,
- const char *filename, char *data, size_t num_bytes)
+ const char *filename, const char *data, size_t num_bytes)
{
int out;
@@ -850,8 +851,21 @@ cleanup:
return ret;
}
+static void update_checksum_with_len(Sha256Context *context, size_t s)
+{
+ int i;
+ uint8_t buffer[8];
+
+ for (i = 0; i < 8; i++) {
+ buffer[i] = s & 0xff;
+ s >>= 8;
+ }
+ Sha256Update(context, buffer, 8);
+}
+
static int semanage_compile_module(semanage_handle_t *sh,
- semanage_module_info_t *modinfo)
+ semanage_module_info_t *modinfo,
+ Sha256Context *context)
{
char cil_path[PATH_MAX];
char hll_path[PATH_MAX];
@@ -922,6 +936,11 @@ static int semanage_compile_module(semanage_handle_t *sh,
goto cleanup;
}
+ if (context) {
+ update_checksum_with_len(context, cil_data_len);
+ Sha256Update(context, cil_data, cil_data_len);
+ }
+
status = write_compressed_file(sh, cil_path, cil_data, cil_data_len);
if (status == -1) {
ERR(sh, "Failed to write %s\n", cil_path);
@@ -950,18 +969,40 @@ cleanup:
return status;
}
+static int modinfo_cmp(const void *a, const void *b)
+{
+ const semanage_module_info_t *ma = a;
+ const semanage_module_info_t *mb = b;
+
+ return strcmp(ma->name, mb->name);
+}
+
static int semanage_compile_hll_modules(semanage_handle_t *sh,
- semanage_module_info_t *modinfos,
- int num_modinfos)
+ semanage_module_info_t *modinfos,
+ int num_modinfos,
+ char *cil_checksum)
{
- int status = 0;
- int i;
+ /* to be incremented when checksum input data format changes */
+ static const size_t CHECKSUM_EPOCH = 1;
+
+ int i, status = 0;
char cil_path[PATH_MAX];
struct stat sb;
+ Sha256Context context;
+ SHA256_HASH hash;
+ struct file_contents contents = {};
assert(sh);
assert(modinfos);
+ /* Sort modules by name to get consistent ordering. */
+ qsort(modinfos, num_modinfos, sizeof(*modinfos), &modinfo_cmp);
+
+ Sha256Initialise(&context);
+ update_checksum_with_len(&context, CHECKSUM_EPOCH);
+
+ /* prefix with module count to avoid collisions */
+ update_checksum_with_len(&context, num_modinfos);
for (i = 0; i < num_modinfos; i++) {
status = semanage_module_get_path(
sh,
@@ -969,29 +1010,91 @@ static int semanage_compile_hll_modules(semanage_handle_t *sh,
SEMANAGE_MODULE_PATH_CIL,
cil_path,
sizeof(cil_path));
- if (status != 0) {
- goto cleanup;
- }
+ if (status != 0)
+ return -1;
- if (semanage_get_ignore_module_cache(sh) == 0 &&
- (status = stat(cil_path, &sb)) == 0) {
- continue;
- }
- if (status != 0 && errno != ENOENT) {
- ERR(sh, "Unable to access %s: %s\n", cil_path, strerror(errno));
- goto cleanup; //an error in the "stat" call
+ if (!semanage_get_ignore_module_cache(sh)) {
+ status = stat(cil_path, &sb);
+ if (status == 0) {
+ status = map_compressed_file(sh, cil_path, &contents);
+ if (status < 0) {
+ ERR(sh, "Error mapping file: %s", cil_path);
+ return -1;
+ }
+
+ /* prefix with length to avoid collisions */
+ update_checksum_with_len(&context, contents.len);
+ Sha256Update(&context, contents.data, contents.len);
+
+ unmap_compressed_file(&contents);
+ continue;
+ } else if (errno != ENOENT) {
+ ERR(sh, "Unable to access %s: %s\n", cil_path,
+ strerror(errno));
+ return -1; //an error in the "stat" call
+ }
}
- status = semanage_compile_module(sh, &modinfos[i]);
- if (status < 0) {
- goto cleanup;
+ status = semanage_compile_module(sh, &modinfos[i], &context);
+ if (status < 0)
+ return -1;
+ }
+ Sha256Finalise(&context, &hash);
+
+ semanage_hash_to_checksum_string(hash.bytes, cil_checksum);
+ return 0;
+}
+
+static int semanage_compare_checksum(semanage_handle_t *sh, const char *reference)
+{
+ const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
+ struct stat sb;
+ int fd, retval;
+ char *data;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ ERR(sh, "Unable to open %s: %s\n", path, strerror(errno));
+ return -1;
}
+ /* Checksum file not present - force a rebuild. */
+ return 1;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ ERR(sh, "Unable to stat %s\n", path);
+ retval = -1;
+ goto out_close;
}
- status = 0;
+ if (sb.st_size != (off_t)CHECKSUM_CONTENT_SIZE) {
+ /* Incompatible/invalid hash type - just force a rebuild. */
+ WARN(sh, "Module checksum invalid - forcing a rebuild\n");
+ retval = 1;
+ goto out_close;
+ }
-cleanup:
- return status;
+ data = mmap(NULL, CHECKSUM_CONTENT_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED) {
+ ERR(sh, "Unable to mmap %s\n", path);
+ retval = -1;
+ goto out_close;
+ }
+
+ retval = memcmp(data, reference, CHECKSUM_CONTENT_SIZE) != 0;
+ munmap(data, sb.st_size);
+out_close:
+ close(fd);
+ return retval;
+}
+
+static int semanage_write_modules_checksum(semanage_handle_t *sh,
+ const char *checksum)
+{
+ const char *path = semanage_path(SEMANAGE_TMP, SEMANAGE_MODULES_CHECKSUM);
+
+ return write_file(sh, path, checksum, CHECKSUM_CONTENT_SIZE);
}
/* Files that must exist in order to skip policy rebuild. */
@@ -1030,6 +1133,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
semanage_module_info_t *modinfos = NULL;
mode_t mask = umask(0077);
struct stat sb;
+ char modules_checksum[CHECKSUM_CONTENT_SIZE + 1 /* '\0' */];
int do_rebuild, do_write_kernel, do_install;
int fcontexts_modified, ports_modified, seusers_modified,
@@ -1159,28 +1263,45 @@ static int semanage_direct_commit(semanage_handle_t * sh)
}
}
- /*
- * If there were policy changes, or explicitly requested, or
- * any required files are missing, rebuild the policy.
- */
- if (do_rebuild) {
- /* =================== Module expansion =============== */
-
+ if (do_rebuild || sh->check_ext_changes) {
retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos);
if (retval < 0) {
goto cleanup;
}
+ /* No modules - nothing to rebuild. */
if (num_modinfos == 0) {
goto cleanup;
}
- retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos);
+ retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos,
+ modules_checksum);
if (retval < 0) {
ERR(sh, "Failed to compile hll files into cil files.\n");
goto cleanup;
}
+ if (!do_rebuild && sh->check_ext_changes) {
+ retval = semanage_compare_checksum(sh, modules_checksum);
+ if (retval < 0)
+ goto cleanup;
+ do_rebuild = retval;
+ }
+
+ retval = semanage_write_modules_checksum(sh, modules_checksum);
+ if (retval < 0) {
+ ERR(sh, "Failed to write module checksum file.\n");
+ goto cleanup;
+ }
+ }
+
+ /*
+ * If there were policy changes, or explicitly requested, or
+ * any required files are missing, rebuild the policy.
+ */
+ if (do_rebuild) {
+ /* =================== Module expansion =============== */
+
retval = semanage_get_cil_paths(sh, modinfos, num_modinfos, &mod_filenames);
if (retval < 0)
goto cleanup;
@@ -1696,7 +1817,7 @@ static int semanage_direct_extract(semanage_handle_t * sh,
goto cleanup;
}
- rc = semanage_compile_module(sh, _modinfo);
+ rc = semanage_compile_module(sh, _modinfo, NULL);
if (rc < 0) {
goto cleanup;
}
diff --git a/libsemanage/src/handle.c b/libsemanage/src/handle.c
index e5109aef..8a01c53a 100644
--- a/libsemanage/src/handle.c
+++ b/libsemanage/src/handle.c
@@ -118,20 +118,23 @@ semanage_handle_t *semanage_handle_create(void)
void semanage_set_rebuild(semanage_handle_t * sh, int do_rebuild)
{
-
assert(sh != NULL);
sh->do_rebuild = do_rebuild;
- return;
}
void semanage_set_reload(semanage_handle_t * sh, int do_reload)
{
-
assert(sh != NULL);
sh->do_reload = do_reload;
- return;
+}
+
+void semanage_set_check_ext_changes(semanage_handle_t * sh, int do_check)
+{
+ assert(sh != NULL);
+
+ sh->check_ext_changes = do_check;
}
int semanage_get_hll_compiler_path(semanage_handle_t *sh,
diff --git a/libsemanage/src/handle.h b/libsemanage/src/handle.h
index a91907b0..c4a6e7ea 100644
--- a/libsemanage/src/handle.h
+++ b/libsemanage/src/handle.h
@@ -62,6 +62,7 @@ struct semanage_handle {
int is_in_transaction;
int do_reload; /* whether to reload policy after commit */
int do_rebuild; /* whether to rebuild policy if there were no changes */
+ int check_ext_changes; /* whether to rebuild if external changes are detected via checksum */
int commit_err; /* set by semanage_direct_commit() if there are
* any errors when building or committing the
* sandbox to kernel policy at /etc/selinux
diff --git a/libsemanage/src/libsemanage.map b/libsemanage/src/libsemanage.map
index a986b2d2..1ef664be 100644
--- a/libsemanage/src/libsemanage.map
+++ b/libsemanage/src/libsemanage.map
@@ -66,4 +66,5 @@ LIBSEMANAGE_1.1 {
LIBSEMANAGE_3.4 {
semanage_module_compute_checksum;
+ semanage_set_check_ext_changes;
} LIBSEMANAGE_1.1;
diff --git a/libsemanage/src/modules.c b/libsemanage/src/modules.c
index 3a82d275..f1fe160d 100644
--- a/libsemanage/src/modules.c
+++ b/libsemanage/src/modules.c
@@ -1149,9 +1149,9 @@ int semanage_module_remove_key(semanage_handle_t *sh,
}
static const char CHECKSUM_TYPE[] = "sha256";
-static const size_t CHECKSUM_CONTENT_SIZE = sizeof(CHECKSUM_TYPE) + 1 + 2 * SHA256_HASH_SIZE;
+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)
+void semanage_hash_to_checksum_string(const uint8_t *hash, char *checksum)
{
size_t i;
diff --git a/libsemanage/src/modules.h b/libsemanage/src/modules.h
index 8a5c01f4..b828a534 100644
--- a/libsemanage/src/modules.h
+++ b/libsemanage/src/modules.h
@@ -109,4 +109,7 @@ int semanage_module_get_path(semanage_handle_t *sh,
char *path,
size_t len);
+extern const size_t CHECKSUM_CONTENT_SIZE;
+void semanage_hash_to_checksum_string(const uint8_t *hash, char *checksum);
+
#endif
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
index c5ce071c..1fff667d 100644
--- a/libsemanage/src/semanage_store.c
+++ b/libsemanage/src/semanage_store.c
@@ -115,6 +115,7 @@ static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
"/disable_dontaudit",
"/preserve_tunables",
"/modules/disabled",
+ "/modules_checksum",
"/policy.kern",
"/file_contexts.local",
"/file_contexts.homedirs",
diff --git a/libsemanage/src/semanage_store.h b/libsemanage/src/semanage_store.h
index b9ec5664..1fc77da8 100644
--- a/libsemanage/src/semanage_store.h
+++ b/libsemanage/src/semanage_store.h
@@ -60,6 +60,7 @@ enum semanage_sandbox_defs {
SEMANAGE_DISABLE_DONTAUDIT,
SEMANAGE_PRESERVE_TUNABLES,
SEMANAGE_MODULES_DISABLED,
+ SEMANAGE_MODULES_CHECKSUM,
SEMANAGE_STORE_KERNEL,
SEMANAGE_STORE_FC_LOCAL,
SEMANAGE_STORE_FC_HOMEDIRS,
--
2.30.2

1
EMPTY
View File

@ -1 +0,0 @@

1517
libsemanage.spec Normal file

File diff suppressed because it is too large Load Diff

59
semanage.conf Normal file
View File

@ -0,0 +1,59 @@
# Authors: Jason Tang <jtang@tresys.com>
#
# Copyright (C) 2004-2005 Tresys Technology, LLC
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# Specify how libsemanage will interact with a SELinux policy manager.
# The four options are:
#
# "source" - libsemanage manipulates a source SELinux policy
# "direct" - libsemanage will write directly to a module store.
# /foo/bar - Write by way of a policy management server, whose
# named socket is at /foo/bar. The path must begin
# with a '/'.
# foo.com:4242 - Establish a TCP connection to a remote policy
# management server at foo.com. If there is a colon
# then the remainder is interpreted as a port number;
# otherwise default to port 4242.
module-store = direct
# When generating the final linked and expanded policy, by default
# semanage will set the policy version to POLICYDB_VERSION_MAX, as
# given in <sepol/policydb.h>. Change this setting if a different
# version is necessary.
#policy-version = 19
# expand-check check neverallow rules when executing all semanage
# commands. There might be a penalty in execution time if this
# option is enabled.
expand-check=0
# usepasswd check tells semanage to scan all pass word records for home directories
# and setup the labeling correctly. If this is turned off, SELinux will label only /home
# and home directories of users with SELinux login mappings defined, see
# semanage login -l for the list of such users.
# If you want to use a different home directory, you will need to use semanage fcontext command.
# For example, if you had home dirs in /althome directory you would have to execute
# semanage fcontext -a -e /home /althome
usepasswd=False
bzip-small=true
bzip-blocksize=5
ignoredirs=/root;/bin;/boot;/dev;/etc;/lib;/lib64;/proc;/run;/sbin;/sys;/tmp;/usr;/var
[sefcontext_compile]
path = /usr/sbin/sefcontext_compile
args = -r $@
[end]

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (libsemanage-2.9.tar.gz) = ea2924e8ce97d376519d40d499145b3db413cf9cc1eb995ed338b95c131e043d8c43b87b2012cee2bb6354a6e3161ebf5ce4a1200278d3ecd4294b43d177a5c2