ltq-deu: aes: do not read/write behind buffer
authorMathias Kresin <dev@kresin.me>
Sun, 18 Apr 2021 12:26:01 +0000 (14:26 +0200)
committerHauke Mehrtens <hauke@hauke-m.de>
Wed, 5 Jan 2022 22:05:38 +0000 (23:05 +0100)
When handling non-aligned remaining data (not padded to 16 byte
[AES_BLOCK_SIZE]), a full 16 byte block is read from the input buffer
and written to the output buffer after en-/decryption.

While code already assumes that an input buffer could have less than 16
byte remaining, as it can be seen by the code zeroing the remaining
bytes till AES_BLOCK_SIZE, the full AES_BLOCK_SIZE is read.

An output buffer size of a multiple of AES_BLOCK_SIZE is expected but
never validated.

To get rid of the read/write behind buffer, use a temporary buffer when
dealing with not padded data and only write as much bytes to the output
as we read.

Do not memcpy directly to the register, to make used of the endian swap
macro and to trigger the crypto start operator via the ID0R to trigger
the register. Since we might need an endian swap for the output in
future, use a temporary buffer for the output as well.

The issue could not be observed so far, since all caller of ifx_deu_aes
will ignore the padded (remaining) data. Considering that the minimum
blocksize for the algorithm is set to AES_BLOCK_SIZE, the behaviour
could be called expected.

Signed-off-by: Mathias Kresin <dev@kresin.me>
[fix commit title prefix]
Signed-off-by: Daniel Kestrel <kestrel1974@t-online.de>
package/kernel/lantiq/ltq-deu/src/ifxmips_aes.c

index 7ce6df0ac64b25fa61bb4b1557b6185793ab8a86..62ce5631819dc15f8a0131831298d68831be33f9 100644 (file)
@@ -251,23 +251,25 @@ void ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
 
     /* To handle all non-aligned bytes (not aligned to 16B size) */
     if (byte_cnt) {
-        aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 0));
-        aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 1));
-        aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 2));
-        aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 3));    /* start crypto */
+        u8 *input[16];
+        u8 *output[16];
+
+        memcpy(input, ((u32 *) in_arg + (i * 4)), byte_cnt);
+
+        aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *) input + (i * 4) + 0));
+        aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *) input + (i * 4) + 1));
+        aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *) input + (i * 4) + 2));
+        aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *) input + (i * 4) + 3));    /* start crypto */
 
         while (aes->controlr.BUS) {
         }
 
-        *((volatile u32 *) out_arg + (i * 4) + 0) = aes->OD3R;
-        *((volatile u32 *) out_arg + (i * 4) + 1) = aes->OD2R;
-        *((volatile u32 *) out_arg + (i * 4) + 2) = aes->OD1R;
-        *((volatile u32 *) out_arg + (i * 4) + 3) = aes->OD0R;
-
-        /* to ensure that the extended pages are clean */
-        memset (out_arg + (i * 16) + (nbytes % AES_BLOCK_SIZE), 0,
-                (AES_BLOCK_SIZE - (nbytes % AES_BLOCK_SIZE)));
+        *((volatile u32 *) output + (i * 4) + 0) = aes->OD3R;
+        *((volatile u32 *) output + (i * 4) + 1) = aes->OD2R;
+        *((volatile u32 *) output + (i * 4) + 2) = aes->OD1R;
+        *((volatile u32 *) output + (i * 4) + 3) = aes->OD0R;
 
+        memcpy(((u32 *) out_arg + (i * 4)), output, byte_cnt);
     }
 
     //tc.chen : copy iv_arg back