aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob N <[email protected]>2024-05-25 12:00:29 +1000
committerTony Hutter <[email protected]>2024-07-17 14:54:47 -0700
commit27cc6df760edb26bf3e55e795f83b92d40fcae8f (patch)
tree5f32800627a31318028764c762ee39797a11f6e8
parentd06c8de7484930de6bb932f0d739ebbd9e255cb5 (diff)
Use memset to zero stack allocations containing unions
C99 6.7.8.17 says that when an undesignated initialiser is used, only the first element of a union is initialised. If the first element is not the largest within the union, how the remaining space is initialised is up to the compiler. GCC extends the initialiser to the entire union, while Clang treats the remainder as padding, and so initialises according to whatever automatic/implicit initialisation rules are currently active. When Linux is compiled with CONFIG_INIT_STACK_ALL_PATTERN, -ftrivial-auto-var-init=pattern is added to the kernel CFLAGS. This flag sets the policy for automatic/implicit initialisation of variables on the stack. Taken together, this means that when compiling under CONFIG_INIT_STACK_ALL_PATTERN on Clang, the "zero" initialiser will only zero the first element in a union, and the rest will be filled with a pattern. This is significant for aes_ctx_t, which in aes_encrypt_atomic() and aes_decrypt_atomic() is initialised to zero, but then used as a gcm_ctx_t, which is the fifth element in the union, and thus gets pattern initialisation. Later, it's assumed to be zero, resulting in a hang. As confusing and undiscoverable as it is, by the spec, we are at fault when we initialise a structure containing a union with the zero initializer. As such, this commit replaces these uses with an explicit memset(0). Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Tino Reichardt <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Rob Norris <[email protected]> Closes #16135 Closes #16206
-rw-r--r--cmd/zstream/zstream_redup.c4
-rw-r--r--lib/libzfs/libzfs_sendrecv.c6
-rw-r--r--module/icp/io/aes.c8
-rw-r--r--tests/zfs-tests/cmd/libzfs_input_check.c4
4 files changed, 16 insertions, 6 deletions
diff --git a/cmd/zstream/zstream_redup.c b/cmd/zstream/zstream_redup.c
index c56a09cee..6866639fe 100644
--- a/cmd/zstream/zstream_redup.c
+++ b/cmd/zstream/zstream_redup.c
@@ -186,7 +186,7 @@ static void
zfs_redup_stream(int infd, int outfd, boolean_t verbose)
{
int bufsz = SPA_MAXBLOCKSIZE;
- dmu_replay_record_t thedrr = { 0 };
+ dmu_replay_record_t thedrr;
dmu_replay_record_t *drr = &thedrr;
redup_table_t rdt;
zio_cksum_t stream_cksum;
@@ -194,6 +194,8 @@ zfs_redup_stream(int infd, int outfd, boolean_t verbose)
uint64_t num_records = 0;
uint64_t num_write_byref_records = 0;
+ memset(&thedrr, 0, sizeof (dmu_replay_record_t));
+
#ifdef _ILP32
uint64_t max_rde_size = SMALLEST_POSSIBLE_MAX_RDT_MB << 20;
#else
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index 143aecb94..c6ee7e566 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -2170,7 +2170,8 @@ out:
static int
send_conclusion_record(int fd, zio_cksum_t *zc)
{
- dmu_replay_record_t drr = { 0 };
+ dmu_replay_record_t drr;
+ memset(&drr, 0, sizeof (dmu_replay_record_t));
drr.drr_type = DRR_END;
if (zc != NULL)
drr.drr_u.drr_end.drr_checksum = *zc;
@@ -2272,7 +2273,8 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd,
}
if (!dryrun) {
- dmu_replay_record_t drr = { 0 };
+ dmu_replay_record_t drr;
+ memset(&drr, 0, sizeof (dmu_replay_record_t));
/* write first begin record */
drr.drr_type = DRR_BEGIN;
drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
diff --git a/module/icp/io/aes.c b/module/icp/io/aes.c
index d6f01304f..522c43649 100644
--- a/module/icp/io/aes.c
+++ b/module/icp/io/aes.c
@@ -832,12 +832,14 @@ aes_encrypt_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
crypto_spi_ctx_template_t template)
{
- aes_ctx_t aes_ctx = {{{{0}}}};
+ aes_ctx_t aes_ctx;
off_t saved_offset;
size_t saved_length;
size_t length_needed;
int ret;
+ memset(&aes_ctx, 0, sizeof (aes_ctx_t));
+
ASSERT(ciphertext != NULL);
/*
@@ -956,12 +958,14 @@ aes_decrypt_atomic(crypto_mechanism_t *mechanism,
crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
crypto_spi_ctx_template_t template)
{
- aes_ctx_t aes_ctx = {{{{0}}}};
+ aes_ctx_t aes_ctx;
off_t saved_offset;
size_t saved_length;
size_t length_needed;
int ret;
+ memset(&aes_ctx, 0, sizeof (aes_ctx_t));
+
ASSERT(plaintext != NULL);
/*
diff --git a/tests/zfs-tests/cmd/libzfs_input_check.c b/tests/zfs-tests/cmd/libzfs_input_check.c
index c661718a2..7d9ce4fad 100644
--- a/tests/zfs-tests/cmd/libzfs_input_check.c
+++ b/tests/zfs-tests/cmd/libzfs_input_check.c
@@ -521,13 +521,15 @@ test_send_new(const char *snapshot, int fd)
static void
test_recv_new(const char *dataset, int fd)
{
- dmu_replay_record_t drr = { 0 };
+ dmu_replay_record_t drr;
nvlist_t *required = fnvlist_alloc();
nvlist_t *optional = fnvlist_alloc();
nvlist_t *props = fnvlist_alloc();
char snapshot[MAXNAMELEN + 32];
ssize_t count;
+ memset(&drr, 0, sizeof (dmu_replay_record_t));
+
int cleanup_fd = open(ZFS_DEV, O_RDWR);
if (cleanup_fd == -1) {
(void) fprintf(stderr, "open(%s) failed: %s\n", ZFS_DEV,