diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2018-11-20 15:24:17 +0100 |
---|---|---|
committer | Jérôme Forissier <jerome.forissier@linaro.org> | 2019-01-21 18:28:37 +0100 |
commit | 84e9c40bd82d7f2b0946de15af2784a9707c9887 (patch) | |
tree | 4d2d717753de7257983f7c254686b41af3181656 /core/tee | |
parent | d5c5b0b77b2b589666024d219a8007b3f5b6faeb (diff) |
core: svc_cryp: fix truncated buffer length
Fixes truncated buffer length in multiple crypto syscalls. The buffer
length is truncated on 32-bit systems because a size_t can't hold a
uint64_t which is use to carry the buffer length.
Fixes: "Truncated buffer length in crypto system calls (x4)" as reported
by Riscure.
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Tested-by: Joakim Bech <joakim.bech@linaro.org> (QEMU v7, v8)
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Reported-by: Riscure <inforequest@riscure.com>
Reported-by: Alyssa Milburn <a.a.milburn@vu.nl>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Diffstat (limited to 'core/tee')
-rw-r--r-- | core/tee/tee_svc_cryp.c | 92 |
1 files changed, 46 insertions, 46 deletions
diff --git a/core/tee/tee_svc_cryp.c b/core/tee/tee_svc_cryp.c index 9e002aa0..7420ca86 100644 --- a/core/tee/tee_svc_cryp.c +++ b/core/tee/tee_svc_cryp.c @@ -824,6 +824,28 @@ static const struct attr_ops attr_ops[] = { }, }; +static TEE_Result get_user_u64_as_size_t(size_t *dst, uint64_t *src) +{ + uint64_t d = 0; + TEE_Result res = tee_svc_copy_from_user(&d, src, sizeof(d)); + + /* + * On 32-bit systems a size_t can't hold a uint64_t so we need to + * check that the value isn't too large. + */ + if (!res && ADD_OVERFLOW(0, d, dst)) + return TEE_ERROR_OVERFLOW; + + return res; +} + +static TEE_Result put_user_u64(uint64_t *dst, size_t value) +{ + uint64_t v = value; + + return tee_svc_copy_to_user(dst, &v, sizeof(v)); +} + TEE_Result syscall_cryp_obj_get_info(unsigned long obj, TEE_ObjectInfo *info) { TEE_Result res; @@ -2283,6 +2305,7 @@ TEE_Result syscall_hash_final(unsigned long state, const void *chunk, { TEE_Result res, res2; size_t hash_size; + size_t hlen = 0; struct tee_cryp_state *cs; struct tee_ta_session *sess; @@ -2301,8 +2324,7 @@ TEE_Result syscall_hash_final(unsigned long state, const void *chunk, if (res != TEE_SUCCESS) return res; - uint64_t hlen = 0; - res = tee_svc_copy_from_user(&hlen, hash_len, sizeof(hlen)); + res = get_user_u64_as_size_t(&hlen, hash_len); if (res != TEE_SUCCESS) return res; @@ -2365,8 +2387,7 @@ TEE_Result syscall_hash_final(unsigned long state, const void *chunk, return TEE_ERROR_BAD_PARAMETERS; } out: - hlen = hash_size; - res2 = tee_svc_copy_to_user(hash_len, &hlen, sizeof(*hash_len)); + res2 = put_user_u64(hash_len, hash_size); if (res2 != TEE_SUCCESS) return res2; return res; @@ -2435,7 +2456,7 @@ static TEE_Result tee_svc_cipher_update_helper(unsigned long state, TEE_Result res; struct tee_cryp_state *cs; struct tee_ta_session *sess; - uint64_t dlen; + size_t dlen = 0; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) @@ -2455,7 +2476,7 @@ static TEE_Result tee_svc_cipher_update_helper(unsigned long state, if (!dst_len) { dlen = 0; } else { - res = tee_svc_copy_from_user(&dlen, dst_len, sizeof(dlen)); + res = get_user_u64_as_size_t(&dlen, dst_len); if (res != TEE_SUCCESS) return res; @@ -2489,8 +2510,7 @@ out: dst_len != NULL) { TEE_Result res2; - dlen = src_len; - res2 = tee_svc_copy_to_user(dst_len, &dlen, sizeof(*dst_len)); + res2 = put_user_u64(dst_len, src_len); if (res2 != TEE_SUCCESS) res = res2; } @@ -2994,8 +3014,7 @@ TEE_Result syscall_authenc_update_payload(unsigned long state, TEE_Result res; struct tee_cryp_state *cs; struct tee_ta_session *sess; - uint64_t dlen; - size_t tmp_dlen; + size_t dlen = 0; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) @@ -3012,7 +3031,7 @@ TEE_Result syscall_authenc_update_payload(unsigned long state, if (res != TEE_SUCCESS) return res; - res = tee_svc_copy_from_user(&dlen, dst_len, sizeof(dlen)); + res = get_user_u64_as_size_t(&dlen, dst_len); if (res != TEE_SUCCESS) return res; @@ -3029,16 +3048,13 @@ TEE_Result syscall_authenc_update_payload(unsigned long state, goto out; } - tmp_dlen = dlen; res = crypto_authenc_update_payload(cs->ctx, cs->algo, cs->mode, src_data, src_len, dst_data, - &tmp_dlen); - dlen = tmp_dlen; - + &dlen); out: if (res == TEE_SUCCESS || res == TEE_ERROR_SHORT_BUFFER) { - TEE_Result res2 = tee_svc_copy_to_user(dst_len, &dlen, - sizeof(*dst_len)); + TEE_Result res2 = put_user_u64(dst_len, dlen); + if (res2 != TEE_SUCCESS) res = res2; } @@ -3053,10 +3069,8 @@ TEE_Result syscall_authenc_enc_final(unsigned long state, TEE_Result res; struct tee_cryp_state *cs; struct tee_ta_session *sess; - uint64_t dlen; - uint64_t tlen = 0; - size_t tmp_dlen; - size_t tmp_tlen; + size_t dlen = 0; + size_t tlen = 0; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) @@ -3079,7 +3093,7 @@ TEE_Result syscall_authenc_enc_final(unsigned long state, if (!dst_len) { dlen = 0; } else { - res = tee_svc_copy_from_user(&dlen, dst_len, sizeof(dlen)); + res = get_user_u64_as_size_t(&dlen, dst_len); if (res != TEE_SUCCESS) return res; @@ -3097,7 +3111,7 @@ TEE_Result syscall_authenc_enc_final(unsigned long state, goto out; } - res = tee_svc_copy_from_user(&tlen, tag_len, sizeof(tlen)); + res = get_user_u64_as_size_t(&tlen, tag_len); if (res != TEE_SUCCESS) return res; @@ -3109,26 +3123,20 @@ TEE_Result syscall_authenc_enc_final(unsigned long state, if (res != TEE_SUCCESS) return res; - tmp_dlen = dlen; - tmp_tlen = tlen; res = crypto_authenc_enc_final(cs->ctx, cs->algo, src_data, - src_len, dst_data, &tmp_dlen, tag, - &tmp_tlen); - dlen = tmp_dlen; - tlen = tmp_tlen; + src_len, dst_data, &dlen, tag, &tlen); out: if (res == TEE_SUCCESS || res == TEE_ERROR_SHORT_BUFFER) { TEE_Result res2; if (dst_len != NULL) { - res2 = tee_svc_copy_to_user(dst_len, &dlen, - sizeof(*dst_len)); + res2 = put_user_u64(dst_len, dlen); if (res2 != TEE_SUCCESS) return res2; } - res2 = tee_svc_copy_to_user(tag_len, &tlen, sizeof(*tag_len)); + res2 = put_user_u64(tag_len, tlen); if (res2 != TEE_SUCCESS) return res2; } @@ -3143,8 +3151,7 @@ TEE_Result syscall_authenc_dec_final(unsigned long state, TEE_Result res; struct tee_cryp_state *cs; struct tee_ta_session *sess; - uint64_t dlen; - size_t tmp_dlen; + size_t dlen = 0; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) @@ -3167,7 +3174,7 @@ TEE_Result syscall_authenc_dec_final(unsigned long state, if (!dst_len) { dlen = 0; } else { - res = tee_svc_copy_from_user(&dlen, dst_len, sizeof(dlen)); + res = get_user_u64_as_size_t(&dlen, dst_len); if (res != TEE_SUCCESS) return res; @@ -3192,17 +3199,14 @@ TEE_Result syscall_authenc_dec_final(unsigned long state, if (res != TEE_SUCCESS) return res; - tmp_dlen = dlen; res = crypto_authenc_dec_final(cs->ctx, cs->algo, src_data, src_len, - dst_data, &tmp_dlen, tag, tag_len); - dlen = tmp_dlen; + dst_data, &dlen, tag, tag_len); out: if ((res == TEE_SUCCESS || res == TEE_ERROR_SHORT_BUFFER) && dst_len != NULL) { - TEE_Result res2; + TEE_Result res2 = put_user_u64(dst_len, dlen); - res2 = tee_svc_copy_to_user(dst_len, &dlen, sizeof(*dst_len)); if (res2 != TEE_SUCCESS) return res2; } @@ -3239,7 +3243,6 @@ TEE_Result syscall_asymm_operate(unsigned long state, TEE_Result res; struct tee_cryp_state *cs; struct tee_ta_session *sess; - uint64_t dlen64; size_t dlen; struct tee_obj *o; void *label = NULL; @@ -3265,10 +3268,9 @@ TEE_Result syscall_asymm_operate(unsigned long state, if (res != TEE_SUCCESS) return res; - res = tee_svc_copy_from_user(&dlen64, dst_len, sizeof(dlen64)); + res = get_user_u64_as_size_t(&dlen, dst_len); if (res != TEE_SUCCESS) return res; - dlen = dlen64; res = tee_mmu_check_access_rights( utc, @@ -3393,10 +3395,8 @@ out: free(params); if (res == TEE_SUCCESS || res == TEE_ERROR_SHORT_BUFFER) { - TEE_Result res2; + TEE_Result res2 = put_user_u64(dst_len, dlen); - dlen64 = dlen; - res2 = tee_svc_copy_to_user(dst_len, &dlen64, sizeof(*dst_len)); if (res2 != TEE_SUCCESS) return res2; } |