Author: jhb
Date: Fri May 26 20:20:40 2017
New Revision: 318967
URL: https://svnweb.freebsd.org/changeset/base/318967

Log:
  Fail large requests with EFBIG.
  
  The adapter firmware in general does not accept PDUs larger than 64k - 1
  bytes in size.  Sending crypto requests larger than this size result in
  hangs or incorrect output, so reject them with EFBIG.  For requests
  chaining an AES cipher with an HMAC, the firmware appears to require
  slightly smaller requests (around 512 bytes).
  
  Sponsored by: Chelsio Communications

Modified:
  head/sys/dev/cxgbe/crypto/t4_crypto.c

Modified: head/sys/dev/cxgbe/crypto/t4_crypto.c
==============================================================================
--- head/sys/dev/cxgbe/crypto/t4_crypto.c       Fri May 26 20:15:33 2017        
(r318966)
+++ head/sys/dev/cxgbe/crypto/t4_crypto.c       Fri May 26 20:20:40 2017        
(r318967)
@@ -117,6 +117,13 @@ __FBSDID("$FreeBSD$");
 #define        MAX_RX_PHYS_DSGL_SGE    32
 #define        DSGL_SGE_MAXLEN         65535
 
+/*
+ * The adapter only supports requests with a total input or output
+ * length of 64k-1 or smaller.  Longer requests either result in hung
+ * requests or incorrect results.
+ */
+#define        MAX_REQUEST_SIZE        65535
+
 static MALLOC_DEFINE(M_CCR, "ccr", "Chelsio T6 crypto");
 
 struct ccr_session_hmac {
@@ -412,6 +419,12 @@ ccr_hmac(struct ccr_softc *sc, uint32_t 
        u_int imm_len, iopad_size;
        int error, sgl_nsegs, sgl_len;
 
+       crd = crp->crp_desc;
+
+       /* Reject requests with too large of an input buffer. */
+       if (crd->crd_len > MAX_REQUEST_SIZE)
+               return (EFBIG);
+
        axf = s->hmac.auth_hash;
 
        /* PADs must be 128-bit aligned. */
@@ -425,7 +438,6 @@ ccr_hmac(struct ccr_softc *sc, uint32_t 
        hash_size_in_response = axf->hashsize;
        transhdr_len = HASH_TRANSHDR_SIZE(kctx_len);
 
-       crd = crp->crp_desc;
        if (ccr_use_imm_data(transhdr_len, crd->crd_len)) {
                imm_len = crd->crd_len;
                sgl_nsegs = 0;
@@ -538,6 +550,10 @@ ccr_blkcipher(struct ccr_softc *sc, uint
            (crd->crd_len % AES_BLOCK_LEN) != 0)
                return (EINVAL);
 
+       /* Reject requests with too large of an input buffer. */
+       if (crd->crd_len > MAX_REQUEST_SIZE)
+               return (EFBIG);
+
        iv_loc = IV_NOP;
        if (crd->crd_flags & CRD_F_ENCRYPT) {
                op_type = CHCR_ENCRYPT_OP;
@@ -785,6 +801,13 @@ ccr_authenc(struct ccr_softc *sc, uint32
         * the hash when encrypting.  For decryption it only contains
         * the plain text.
         */
+       if (op_type == CHCR_ENCRYPT_OP) {
+               if (crde->crd_len + hash_size_in_response > MAX_REQUEST_SIZE)
+                       return (EFBIG);
+       } else {
+               if (crde->crd_len > MAX_REQUEST_SIZE)
+                       return (EFBIG);
+       }
        sglist_reset(sc->sg_dsgl);
        error = sglist_append_sglist(sc->sg_dsgl, sc->sg_crp, crde->crd_skip,
            crde->crd_len);
@@ -824,6 +847,17 @@ ccr_authenc(struct ccr_softc *sc, uint32
        } else
                aad_len = 0;
        input_len = aad_len + crde->crd_len;
+
+       /*
+        * The firmware hangs if sent a request which is a
+        * bit smaller than MAX_REQUEST_SIZE.  In particular, the
+        * firmware appears to require 512 - 16 bytes of spare room
+        * along with the size of the hash even if the hash isn't
+        * included in the input buffer.
+        */
+       if (input_len + roundup2(axf->hashsize, 16) + (512 - 16) >
+           MAX_REQUEST_SIZE)
+               return (EFBIG);
        if (op_type == CHCR_DECRYPT_OP)
                input_len += hash_size_in_response;
        if (ccr_use_imm_data(transhdr_len, s->blkcipher.iv_len + input_len)) {
@@ -1105,6 +1139,13 @@ ccr_gcm(struct ccr_softc *sc, uint32_t s
         * the tag when encrypting.  For decryption it only contains
         * the plain text.
         */
+       if (op_type == CHCR_ENCRYPT_OP) {
+               if (crde->crd_len + hash_size_in_response > MAX_REQUEST_SIZE)
+                       return (EFBIG);
+       } else {
+               if (crde->crd_len > MAX_REQUEST_SIZE)
+                       return (EFBIG);
+       }
        sglist_reset(sc->sg_dsgl);
        error = sglist_append_sglist(sc->sg_dsgl, sc->sg_crp, crde->crd_skip,
            crde->crd_len);
@@ -1136,6 +1177,8 @@ ccr_gcm(struct ccr_softc *sc, uint32_t s
        input_len = crda->crd_len + crde->crd_len;
        if (op_type == CHCR_DECRYPT_OP)
                input_len += hash_size_in_response;
+       if (input_len > MAX_REQUEST_SIZE)
+               return (EFBIG);
        if (ccr_use_imm_data(transhdr_len, iv_len + input_len)) {
                imm_len = input_len;
                sgl_nsegs = 0;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to