Description
I'm verifying the SymCrypt library and I'm running into unwinding failure for the SymCryptWipeAsm function, which is a simple loop that sets the buffer to 0, but because the loop iteration depends on cbData, I believe CBMC want to unwind it to the max value of cbData(under the proof constrain of 1024). I'm trying to specify invariants to make this loop inductive so that CBMC only unwinds once. I've also tried using __CPROVER_ensures with __CPROVER_forall as specified in this documentation, but I got a parsing error from goto-cc.
Harness(SymCryptWipeAsm is implemented here to overwrite the assembly version):
#include <stdlib.h>
#include "symcrypt.h"
SYMCRYPT_ENVIRONMENT_LINUX_USERMODE
void harness(void)
{
SIZE_T cbData; // unconstrained value
PBYTE pbData;
BYTE abResult[SYMCRYPT_SHA256_RESULT_SIZE];
__CPROVER_assume(cbData <= 1024);
pbData = malloc( cbData );
__CPROVER_assume(pbData != NULL);
SymCryptSha256( pbData, cbData, abResult );
free(pbData);
}
VOID
SYMCRYPT_CALL
SymCryptWipeAsm( _Out_writes_bytes_( cbData ) PVOID pbData, SIZE_T cbData )
{
volatile BYTE * p = (volatile BYTE *) pbData;
SIZE_T i;
__CPROVER_assume( pbData != NULL );
__CPROVER_assume( __CPROVER_w_ok( pbData, cbData ) );
for( i=0; i<cbData; i++ )
__CPROVER_loop_invariant( 0 <= i && i < cbData )
__CPROVER_decreases( cbData - i )
{
p[i] = 0;
}
/* What I've also tried but got parsing error:
for( i=0; i<cbData; i++ )
__CPROVER_ensures(__CPROVER_forall {
SIZE_T i;
(0 <= i && i < SIZE_MAX) ==>
p[i]==0
})
{
p[i] = 0;
}
*/
}
Related source files:
PROJECT_SOURCES += $(SRCDIR)/lib/sha256.c
PROJECT_SOURCES += $(SRCDIR)/lib/env_linuxUserMode.c
PROJECT_SOURCES += $(SRCDIR)/lib/libmain.c
PROJECT_SOURCES += $(SRCDIR)/lib/sha256Par.c
CBMC version: 5.95.1
Operating system: WSL
What behaviour did you expect: The loop become inductive and CBMC unwind once
What happened instead: unwinding failure for unwind --32
Please let me know if you need more information and I appreciate the help!