}
 
+/* If invalid preauth context warn but use what we requested, SHA-512 */
 static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
 {
        unsigned int len = le16_to_cpu(ctxt->DataLength);
 
-       /* If invalid preauth context warn but use what we requested, SHA-512 */
+       /*
+        * Caller checked that DataLength remains within SMB boundary. We still
+        * need to confirm that one HashAlgorithms member is accounted for.
+        */
        if (len < MIN_PREAUTH_CTXT_DATA_LEN) {
                pr_warn_once("server sent bad preauth context\n");
                return;
 {
        unsigned int len = le16_to_cpu(ctxt->DataLength);
 
-       /* sizeof compress context is a one element compression capbility struct */
+       /*
+        * Caller checked that DataLength remains within SMB boundary. We still
+        * need to confirm that one CompressionAlgorithms member is accounted
+        * for.
+        */
        if (len < 10) {
                pr_warn_once("server sent bad compression cntxt\n");
                return;
        unsigned int len = le16_to_cpu(ctxt->DataLength);
 
        cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len);
+       /*
+        * Caller checked that DataLength remains within SMB boundary. We still
+        * need to confirm that one Cipher flexible array member is accounted
+        * for.
+        */
        if (len < MIN_ENCRYPT_CTXT_DATA_LEN) {
                pr_warn_once("server sent bad crypto ctxt len\n");
                return -EINVAL;
 {
        unsigned int len = le16_to_cpu(pctxt->DataLength);
 
+       /*
+        * Caller checked that DataLength remains within SMB boundary. We still
+        * need to confirm that one SigningAlgorithms flexible array member is
+        * accounted for.
+        */
        if ((len < 4) || (len > 16)) {
                pr_warn_once("server sent bad signing negcontext\n");
                return;
        for (i = 0; i < ctxt_cnt; i++) {
                int clen;
                /* check that offset is not beyond end of SMB */
-               if (len_of_ctxts == 0)
-                       break;
-
                if (len_of_ctxts < sizeof(struct smb2_neg_context))
                        break;
 
                pctx = (struct smb2_neg_context *)(offset + (char *)rsp);
-               clen = le16_to_cpu(pctx->DataLength);
+               clen = sizeof(struct smb2_neg_context)
+                       + le16_to_cpu(pctx->DataLength);
+               /*
+                * 2.2.4 SMB2 NEGOTIATE Response
+                * Subsequent negotiate contexts MUST appear at the first 8-byte
+                * aligned offset following the previous negotiate context.
+                */
+               if (i + 1 != ctxt_cnt)
+                       clen = ALIGN(clen, 8);
                if (clen > len_of_ctxts)
                        break;
 
                else
                        cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
                                le16_to_cpu(pctx->ContextType));
-
                if (rc)
                        break;
-               /* offsets must be 8 byte aligned */
-               clen = ALIGN(clen, 8);
-               offset += clen + sizeof(struct smb2_neg_context);
+
+               offset += clen;
                len_of_ctxts -= clen;
        }
        return rc;