For a few cases where we handle secret information it's good to clear the buffers containing sensitive data before freeing them. Introduce VIR_DISPOSE, VIR_DISPOSE_N and VIR_DISPOSE_STRING that allow simple clearing fo the buffers holding sensitive information on cleanup paths. --- src/libvirt_private.syms | 1 + src/util/viralloc.c | 36 +++++++++++++++++++++++++++++++ src/util/viralloc.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/viralloctest.c | 37 ++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a980a32..9c1abbb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1127,6 +1127,7 @@ virAllocTestInit; virAllocTestOOM; virAllocVar; virDeleteElementsN; +virDispose; virExpandN; virFree; virInsertElementsN; diff --git a/src/util/viralloc.c b/src/util/viralloc.c index 63f43d0..812aa5b 100644 --- a/src/util/viralloc.c +++ b/src/util/viralloc.c @@ -583,3 +583,39 @@ void virFree(void *ptrptr) *(void**)ptrptr = NULL; errno = save_errno; } + + +/** + * virDispose: + * @ptrptr: pointer to pointer for address of memory to be sanitized and freed + * @count: count of elements in the array to dispose + * @elemet_size: size of one element + * @countptr: pointer to the count variable to clear (may be NULL) + * + * Clear and release the chunk of memory in the pointer pointed to by 'prtptr'. + * + * If @countptr is provided, it's value is used instead of @count and it's set + * to 0 after clearing and freeing the memory. + * + * After release, 'ptrptr' will be updated to point to NULL. + */ +void virDispose(void *ptrptr, + size_t count, + size_t element_size, + size_t *countptr) +{ + int save_errno = errno; + + if (countptr) + count = *countptr; + + if (*(void**)ptrptr && count > 0) + memset(*(void **)ptrptr, 0, count * element_size); + + free(*(void**)ptrptr); + *(void**)ptrptr = NULL; + + if (countptr) + *countptr = 0; + errno = save_errno; +} diff --git a/src/util/viralloc.h b/src/util/viralloc.h index bf85c16..5f4e27b 100644 --- a/src/util/viralloc.h +++ b/src/util/viralloc.h @@ -78,6 +78,9 @@ int virAllocVar(void *ptrptr, size_t struct_size, size_t element_size, size_t co ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1); void virFree(void *ptrptr) ATTRIBUTE_NONNULL(1); +void virDispose(void *ptrptr, size_t count, size_t element_size, size_t *countptr) + ATTRIBUTE_NONNULL(1); + /** * VIR_ALLOC: * @ptr: pointer to hold address of allocated memory @@ -561,6 +564,59 @@ void virFree(void *ptrptr) ATTRIBUTE_NONNULL(1); # define VIR_FREE(ptr) virFree(&(ptr)) # endif + +/** + * VIR_DISPOSE_N: + * @ptr: pointer holding address to be cleared and freed + * @count: count of elements in @ptr + * + * Clear the memory of the array of elemets pointed to by 'ptr' of 'count' + * elements and free it. Update the pointer/count to NULL/0. + * + * This macro is safe to use on arguments with side effects. + */ +# if !STATIC_ANALYSIS +/* See explanation in VIR_FREE */ +# define VIR_DISPOSE_N(ptr, count) virDispose(1 ? (void *) &(ptr) : (ptr), 0, \ + sizeof(*(ptr)), &(count)) +# else +# define VIR_DISPOSE_N(ptr, count) virDispose(&(ptr), 0, sizeof(*(ptr)), &(count)) +# endif + + +/** + * VIR_DISPOSE_STRING: + * @ptr: pointer to a string to be cleared and freed + * + * Clears the string and frees the corresponding memory. + * + * This macro is not safe to be used on arguments with side effects. + */ +# if !STATIC_ANALYSIS +/* See explanation in VIR_FREE */ +# define VIR_DISPOSE_STRING(ptr) virDispose(1 ? (void *) &(ptr) : (ptr), \ + (ptr) ? strlen((ptr)) : 0, 1, NULL) +# else +# define VIR_DISPOSE_STRING(ptr) virDispose(&(ptr), (ptr) ? strlen((ptr)) : 1, NULL) +# endif + + +/** + * VIR_DISPOSE: + * @ptr: pointer to memory to be cleared and freed + * + * Clears and frees the corresponding memory. + * + * This macro is safe to be used on arguments with side effects. + */ +# if !STATIC_ANALYSIS +/* See explanation in VIR_FREE */ +# define VIR_DISPOSE(ptr) virDispose(1 ? (void *) &(ptr) : (ptr), 1, sizeof(*(ptr)), NULL) +# else +# define VIR_DISPOSE(ptr) virDispose(&(ptr), 1, sizeof(*(ptr)), NULL) +# endif + + void virAllocTestInit(void); int virAllocTestCount(void); void virAllocTestOOM(int n, int m); diff --git a/tests/viralloctest.c b/tests/viralloctest.c index 8c0826f..dd54f81 100644 --- a/tests/viralloctest.c +++ b/tests/viralloctest.c @@ -384,6 +384,41 @@ testInsertArray(const void *opaque ATTRIBUTE_UNUSED) static int +testDispose(const void *opaque ATTRIBUTE_UNUSED) +{ + int *num = NULL; + int *nums = NULL; + size_t nnums = 0; + char *str = NULL; + + VIR_DISPOSE(num); + VIR_DISPOSE_N(nums, nnums); + VIR_DISPOSE_STRING(str); + + nnums = 10; + VIR_DISPOSE_N(nums, nnums); + + if (VIR_ALLOC(num) < 0) + return -1; + + VIR_DISPOSE(num); + + nnums = 10; + if (VIR_ALLOC_N(nums, nnums) < 0) + return -1; + + VIR_DISPOSE_N(nums, nnums); + + if (VIR_STRDUP(str, "test") < 0) + return -1; + + VIR_DISPOSE_STRING(str); + + return 0; +} + + +static int mymain(void) { int ret = 0; @@ -400,6 +435,8 @@ mymain(void) ret = -1; if (virtTestRun("insert array", testInsertArray, NULL) < 0) ret = -1; + if (virtTestRun("dispose tests", testDispose, NULL) < 0) + ret = -1; return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.8.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list