From e17619792fa1e342c7f0a819077129adff438cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Wed, 13 Apr 2022 17:56:33 +0200 Subject: [PATCH] libselinux: correctly hash specfiles larger than 4G MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internal Sha1Update() functions only handles buffers up to a size of UINT32_MAX, due to its usage of the type uint32_t. This causes issues when processing more than UINT32_MAX bytes, e.g. with a specfile larger than 4G. 0aa974a4 ("libselinux: limit has buffer size") tried to address this issue, but failed since the overflow check if (digest->hashbuf_size + buf_len < digest->hashbuf_size) { will be done in the widest common type, which is size_t, the type of `buf_len`. Revert the type of `hashbuf_size` to size_t and instead process the data in blocks of supported size. Acked-by: James Carter Signed-off-by: Christian Göttsche Reverts: 0aa974a4 ("libselinux: limit has buffer size") --- libselinux/src/label_internal.h | 2 +- libselinux/src/label_support.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h index 82a762f7c8..782c6aa8cc 100644 --- a/libselinux/src/label_internal.h +++ b/libselinux/src/label_internal.h @@ -57,7 +57,7 @@ int selabel_service_init(struct selabel_handle *rec, struct selabel_digest { unsigned char *digest; /* SHA1 digest of specfiles */ unsigned char *hashbuf; /* buffer to hold specfiles */ - uint32_t hashbuf_size; /* buffer size */ + size_t hashbuf_size; /* buffer size */ size_t specfile_cnt; /* how many specfiles processed */ char **specfile_list; /* and their names */ }; diff --git a/libselinux/src/label_support.c b/libselinux/src/label_support.c index 94ed6e4273..54fd49a5b7 100644 --- a/libselinux/src/label_support.c +++ b/libselinux/src/label_support.c @@ -116,13 +116,25 @@ int read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...) void digest_gen_hash(struct selabel_digest *digest) { Sha1Context context; + size_t remaining_size; + const unsigned char *ptr; /* If SELABEL_OPT_DIGEST not set then just return */ if (!digest) return; Sha1Initialise(&context); - Sha1Update(&context, digest->hashbuf, digest->hashbuf_size); + + /* Process in blocks of UINT32_MAX bytes */ + remaining_size = digest->hashbuf_size; + ptr = digest->hashbuf; + while (remaining_size > UINT32_MAX) { + Sha1Update(&context, ptr, UINT32_MAX); + remaining_size -= UINT32_MAX; + ptr += UINT32_MAX; + } + Sha1Update(&context, ptr, remaining_size); + Sha1Finalise(&context, (SHA1_HASH *)digest->digest); free(digest->hashbuf); digest->hashbuf = NULL;