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