]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Use memset to zero stack allocations containing unions
authorRob N <robn@despairlabs.com>
Sat, 25 May 2024 02:00:29 +0000 (12:00 +1000)
committerGitHub <noreply@github.com>
Sat, 25 May 2024 02:00:29 +0000 (19:00 -0700)
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 <milky-zfs@mcmilk.de>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #16135
Closes #16206

cmd/zstream/zstream_redup.c
lib/libzfs/libzfs_sendrecv.c
module/icp/io/aes.c
tests/zfs-tests/cmd/libzfs_input_check.c

index c56a09cee75dfd3ede93195538c0342568c49f38..6866639fe465903d3c4859208889bf96498e7740 100644 (file)
@@ -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
index 526f57ea403c6cdbb295740eb3991ef7487a7ecc..0370112c022a9f8489cf28891f2a5ec505b71528 100644 (file)
@@ -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;
index d6f01304f56bfecd28a6f2c778c345eb6f2e8774..522c436497bc8704b0635246f5fd20db5a178db7 100644 (file)
@@ -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);
 
        /*
index c661718a296cdfef3e7fa6fcb80a632d6fbda3ec..7d9ce4fada1b0a8d5bf704a12ad16659aac0a286 100644 (file)
@@ -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,