Date: Fri, 26 May 2017 20:20:40 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r318967 - head/sys/dev/cxgbe/crypto Message-ID: <201705262020.v4QKKecL096648@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201705262020.v4QKKecL096648>