Add detection for corrupt TPM token objects to opencryptoki
Currently, opencryptoki will happily try and allocate huge buffers
when a file is corrupted and contains an incorrect length. This
change adds a check to see that the length of the requested object is
less than the size of the whole file. If not, then an error is
generated.
BUG=chromium-os:24853
TEST=corrupted a file in .tpm directory, and correctly detected it.
Change-Id: Id1f8a4bbec9e417b33d63c7e89ff623c0f4fa0fe
diff --git a/usr/lib/pkcs11/tpm_stdll/loadsave.c b/usr/lib/pkcs11/tpm_stdll/loadsave.c
index cf752fe..cb6cdfc 100644
--- a/usr/lib/pkcs11/tpm_stdll/loadsave.c
+++ b/usr/lib/pkcs11/tpm_stdll/loadsave.c
@@ -782,6 +782,8 @@
CK_BYTE tmp[PATH_MAX], fname[PATH_MAX], iname[PATH_MAX];
CK_BBOOL priv;
CK_ULONG_32 size;
+ CK_RV rc;
+ struct stat fp2_stat;
struct passwd *pw = NULL;
if ((pw = getpwuid(getuid())) == NULL){
@@ -811,24 +813,55 @@
if (!fp2)
continue;
- fread( &size, sizeof(CK_ULONG_32), 1, fp2 );
- fread( &priv, sizeof(CK_BBOOL), 1, fp2 );
+ // Get the file size for fp2, so we can do sanity checks on
+ // the sizes and skip when the files are corrupted.
+ if ( fstat( fileno(fp2), &fp2_stat ) == -1 ) {
+ LogError( "Unable to stat public token object %s: %s",
+ fname, strerror(errno) );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
+
+ if ( fread( &size, sizeof(CK_ULONG_32), 1, fp2 ) != 1 ||
+ fread( &priv, sizeof(CK_BBOOL), 1, fp2 ) != 1 ) {
+ LogError( "Unable to read public token object %s", fname );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
+
if (priv == TRUE) {
fclose( fp2 );
continue;
}
+ // If the requested size is larger than the entire file or
+ // smaller than what we've already read, then we know it has
+ // to be bogus.
+ if ( size > fp2_stat.st_size ||
+ size < (sizeof(CK_ULONG_32) + sizeof(CK_BBOOL)) ) {
+ LogError( "Corrupt public token object: %s", fname );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
+
// size--;
size = size -sizeof(CK_ULONG_32) - sizeof(CK_BBOOL);
buf = (CK_BYTE *)malloc(size);
if (!buf) {
- fclose(fp1);
- fclose(fp2);
st_err_log(0, __FILE__, __LINE__);
- return CKR_HOST_MEMORY;
+ rc = CKR_HOST_MEMORY;
+ goto error;
}
- fread( buf, size, 1, fp2 );
+ // If the read didn't complete, then the buffer contains at
+ // least some bogus data (and since we know the file is big
+ // enough to read |size| bytes, something else must have
+ // happened).
+ if ( fread( buf, size, 1, fp2 ) != 1 ) {
+ st_err_log( 4, __FILE__, __LINE__, __FUNCTION__ );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
// ... grab object mutex here.
MY_LockMutex(&obj_list_mutex);
@@ -841,6 +874,12 @@
fclose(fp1);
return CKR_OK;
+
+error:
+ if (buf) free( buf );
+ if (fp1) fclose( fp1 );
+ if (fp2) fclose( fp2 );
+ return rc;
}
@@ -856,6 +895,7 @@
CK_BBOOL priv;
CK_ULONG_32 size;
CK_RV rc;
+ struct stat fp2_stat;
struct passwd *pw = NULL;
if ((pw = getpwuid(getuid())) == NULL){
@@ -885,13 +925,37 @@
if (!fp2)
continue;
- fread( &size, sizeof(CK_ULONG_32), 1, fp2 );
- fread( &priv, sizeof(CK_BBOOL), 1, fp2 );
+ // Get the file size for fp2, so we can do sanity checks on
+ // the sizes and skip when the files are corrupted.
+ if (fstat( fileno(fp2), &fp2_stat ) == -1) {
+ LogError( "Unable to stat private token object %s: %s",
+ fname, strerror(errno) );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
+
+ if ( fread( &size, sizeof(CK_ULONG_32), 1, fp2 ) != 1 ||
+ fread( &priv, sizeof(CK_BBOOL), 1, fp2 ) != 1 ) {
+ LogError( "Unable to read private token object %s", fname );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
+
if (priv == FALSE) {
fclose( fp2 );
continue;
}
+ // If the requested size is larger than the entire file or
+ // smaller than what we've already read, then we know it has
+ // to be bogus.
+ if ( size > fp2_stat.st_size ||
+ size < (sizeof(CK_ULONG_32) + sizeof(CK_BBOOL)) ) {
+ LogError( "Corrupt private token object: %s", fname );
+ rc = CKR_FUNCTION_FAILED;
+ goto error;
+ }
+
//size--;
size = size - sizeof(CK_ULONG_32) - sizeof(CK_BBOOL);
buf = (CK_BYTE *)malloc(size);
@@ -901,9 +965,8 @@
goto error;
}
- rc = fread( (char *)buf, size, 1, fp2 );
- if (rc != 1) {
- st_err_log(4, __FILE__, __LINE__, __FUNCTION__);
+ if ( fread( (char *)buf, size, 1, fp2 ) != 1 ) {
+ st_err_log( 4, __FILE__, __LINE__, __FUNCTION__ );
rc = CKR_FUNCTION_FAILED;
goto error;
}