On Mon, Jul 29, 2024 at 09:43:48AM +0530, Pavitrakumar M wrote: > +static int spacc_aead_setkey(struct crypto_aead *tfm, const u8 *key, > + unsigned int keylen) > +{ > + struct spacc_crypto_ctx *ctx = crypto_aead_ctx(tfm); > + const struct spacc_alg *salg = spacc_tfm_aead(&tfm->base); > + struct spacc_priv *priv; > + struct rtattr *rta = (void *)key; > + struct crypto_authenc_key_param *param; > + unsigned int authkeylen, enckeylen; > + const unsigned char *authkey, *enckey; > + unsigned char xcbc[64]; > + > + int err = -EINVAL; > + int singlekey = 0; > + > + /* are keylens valid? */ > + ctx->ctx_valid = false; > + > + switch (ctx->mode & 0xFF) { > + case CRYPTO_MODE_SM4_GCM: > + case CRYPTO_MODE_SM4_CCM: > + case CRYPTO_MODE_NULL: > + case CRYPTO_MODE_AES_GCM: > + case CRYPTO_MODE_AES_CCM: > + case CRYPTO_MODE_CHACHA20_POLY1305: > + authkey = key; > + authkeylen = 0; > + enckey = key; > + enckeylen = keylen; > + ctx->keylen = keylen; > + singlekey = 1; > + goto skipover; > + } > + > + if (!RTA_OK(rta, keylen) || ^^^^^^^^^^^ This check validates that rta->rta_len is less than keylen. > + rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM || > + RTA_PAYLOAD(rta) < sizeof(*param)) > + return -EINVAL; > + > + param = RTA_DATA(rta); > + enckeylen = be32_to_cpu(param->enckeylen); > + key += RTA_ALIGN(rta->rta_len); > + keylen -= RTA_ALIGN(rta->rta_len); However we're subtracting RTA_ALIGN() not rta->rta_len so there is a chance that this subtraction can make keylen negative (but it's unsigned so a large positive value). Both keylen and rta->rta_len would need have to not be multples of 4. For example, if they were both set to 9. (I'm not a domain expert so maybe here is checking for % 4 at a different level). A high positive value of keylen would lead to memory corruption later in the function. regards, dan carpenter > + > + if (keylen < enckeylen) > + return -EINVAL; > + > + authkeylen = keylen - enckeylen; > + > + /* enckey is at &key[authkeylen] and > + * authkey is at &key[0] > + */ > + authkey = &key[0]; > + enckey = &key[authkeylen]; > + > +skipover: > + /* detect RFC3686/4106 and trim from enckeylen(and copy salt..) */ > + if (ctx->mode & SPACC_MANGLE_IV_FLAG) { > + switch (ctx->mode & 0x7F00) { > + case SPACC_MANGLE_IV_RFC3686: > + case SPACC_MANGLE_IV_RFC4106: > + case SPACC_MANGLE_IV_RFC4543: > + memcpy(ctx->csalt, enckey + enckeylen - 4, 4); > + enckeylen -= 4; > + break; > + case SPACC_MANGLE_IV_RFC4309: > + memcpy(ctx->csalt, enckey + enckeylen - 3, 3); > + enckeylen -= 3; > + break; > + } > + } > + > + if (!singlekey) { > + if (authkeylen > salg->mode->hashlen) { > + dev_warn(ctx->dev, "Auth key size of %u is not valid\n", > + authkeylen); > + return -EINVAL; > + } > + } > + > + if (!spacc_check_keylen(salg, enckeylen)) { > + dev_warn(ctx->dev, "Enc key size of %u is not valid\n", > + enckeylen); > + return -EINVAL; > + } > + > + /* if we're already open close the handle since > + * the size may have changed > + */ > + if (ctx->handle != -1) { > + priv = dev_get_drvdata(ctx->dev); > + spacc_close(&priv->spacc, ctx->handle); > + put_device(ctx->dev); > + ctx->handle = -1; > + } > + > + /* Open a handle and > + * search all devices for an open handle > + */ > + priv = NULL; > + priv = dev_get_drvdata(salg->dev[0]); > + > + /* increase reference */ > + ctx->dev = get_device(salg->dev[0]); > + > + /* check if its a valid mode ... */ > + if (spacc_isenabled(&priv->spacc, salg->mode->aead.ciph & 0xFF, > + enckeylen) && > + spacc_isenabled(&priv->spacc, > + salg->mode->aead.hash & 0xFF, authkeylen)) { > + /* try to open spacc handle */ > + ctx->handle = spacc_open(&priv->spacc, > + salg->mode->aead.ciph & 0xFF, > + salg->mode->aead.hash & 0xFF, > + -1, 0, spacc_aead_cb, tfm); > + } > + > + if (ctx->handle < 0) { > + put_device(salg->dev[0]); > + pr_debug("Failed to open SPAcc context\n"); > + return -EIO; > + } > + > + /* setup XCBC key */ > + if (salg->mode->aead.hash == CRYPTO_MODE_MAC_XCBC) { > + err = spacc_compute_xcbc_key(&priv->spacc, > + salg->mode->aead.hash, > + ctx->handle, authkey, > + authkeylen, xcbc); > + if (err < 0) { > + dev_warn(ctx->dev, "Failed to compute XCBC key: %d\n", > + err); > + return -EIO; > + } > + authkey = xcbc; > + authkeylen = 48; > + } > + > + /* handle zero key/zero len DEC condition for SM4/AES GCM mode */ > + ctx->zero_key = 0; > + if (!key[0]) { > + int i, val = 0; > + > + for (i = 0; i < keylen ; i++) > + val += key[i]; > + > + if (val == 0) > + ctx->zero_key = 1; > + } > + > + err = spacc_write_context(&priv->spacc, ctx->handle, > + SPACC_CRYPTO_OPERATION, enckey, > + enckeylen, NULL, 0); > + > + if (err) { > + dev_warn(ctx->dev, > + "Could not write ciphering context: %d\n", err); > + return -EIO; > + } > + > + if (!singlekey) { > + err = spacc_write_context(&priv->spacc, ctx->handle, > + SPACC_HASH_OPERATION, authkey, > + authkeylen, NULL, 0); > + if (err) { > + dev_warn(ctx->dev, > + "Could not write hashing context: %d\n", err); > + return -EIO; > + } > + } > + > + /* set expand key */ > + spacc_set_key_exp(&priv->spacc, ctx->handle); > + ctx->ctx_valid = true; > + > + memset(xcbc, 0, sizeof(xcbc)); > + > + /* copy key to ctx for fallback */ > + memcpy(ctx->key, key, keylen); > + > + return 0; > +}