crypto: talitos – properly handle split ICV. [Linux 4.9.187]

This Linux kernel change "crypto: talitos – properly handle split ICV" is included in the Linux 4.9.187 release. This change is authored by Christophe Leroy <christophe.leroy [at] c-s.fr> on Tue May 21 13:34:17 2019 +0000. The commit for this change in Linux stable tree is 26b269a (patch) which is from upstream commit eae55a5. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream eae55a5.

crypto: talitos - properly handle split ICV.

[ Upstream commit eae55a586c3c8b50982bad3c3426e9c9dd7a0075 ]

The driver assumes that the ICV is as a single piece in the last
element of the scatterlist. This assumption is wrong.

This patch ensures that the ICV is properly handled regardless of
the scatterlist layout.

Fixes: 9c4a79653b35 ("crypto: talitos - Freescale integrated security engine (SEC) driver")
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 26 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/crypto/talitos.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 0b12772..e7864aa49 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -984,7 +984,6 @@ static void ipsec_esp_encrypt_done(struct device *dev,
    struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
    unsigned int authsize = crypto_aead_authsize(authenc);
    struct talitos_edesc *edesc;
-   struct scatterlist *sg;
    void *icvdata;

    edesc = container_of(desc, struct talitos_edesc, desc);
@@ -998,9 +997,8 @@ static void ipsec_esp_encrypt_done(struct device *dev,
        else
            icvdata = &edesc->link_tbl[edesc->src_nents +
                           edesc->dst_nents + 2];
-       sg = sg_last(areq->dst, edesc->dst_nents);
-       memcpy((char *)sg_virt(sg) + sg->length - authsize,
-              icvdata, authsize);
+       sg_pcopy_from_buffer(areq->dst, edesc->dst_nents ? : 1, icvdata,
+                    authsize, areq->assoclen + areq->cryptlen);
    }

    kfree(edesc);
@@ -1016,7 +1014,6 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
    struct crypto_aead *authenc = crypto_aead_reqtfm(req);
    unsigned int authsize = crypto_aead_authsize(authenc);
    struct talitos_edesc *edesc;
-   struct scatterlist *sg;
    char *oicv, *icv;
    struct talitos_private *priv = dev_get_drvdata(dev);
    bool is_sec1 = has_ftr_sec1(priv);
@@ -1026,9 +1023,18 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
    ipsec_esp_unmap(dev, edesc, req);

    if (!err) {
+       char icvdata[SHA512_DIGEST_SIZE];
+       int nents = edesc->dst_nents ? : 1;
+       unsigned int len = req->assoclen + req->cryptlen;
+
        /* auth check */
-       sg = sg_last(req->dst, edesc->dst_nents ? : 1);
-       icv = (char *)sg_virt(sg) + sg->length - authsize;
+       if (nents > 1) {
+           sg_pcopy_to_buffer(req->dst, nents, icvdata, authsize,
+                      len - authsize);
+           icv = icvdata;
+       } else {
+           icv = (char *)sg_virt(req->dst) + len - authsize;
+       }

        if (edesc->dma_len) {
            if (is_sec1)
@@ -1458,7 +1464,6 @@ static int aead_decrypt(struct aead_request *req)
    struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
    struct talitos_private *priv = dev_get_drvdata(ctx->dev);
    struct talitos_edesc *edesc;
-   struct scatterlist *sg;
    void *icvdata;

    req->cryptlen -= authsize;
@@ -1493,9 +1498,8 @@ static int aead_decrypt(struct aead_request *req)
    else
        icvdata = &edesc->link_tbl[0];

-   sg = sg_last(req->src, edesc->src_nents ? : 1);
-
-   memcpy(icvdata, (char *)sg_virt(sg) + sg->length - authsize, authsize);
+   sg_pcopy_to_buffer(req->src, edesc->src_nents ? : 1, icvdata, authsize,
+              req->assoclen + req->cryptlen - authsize);

    return ipsec_esp(edesc, req, ipsec_esp_decrypt_swauth_done);
 }

Leave a Reply

Your email address will not be published. Required fields are marked *