Tại sao OPENSSL_cleanse trông rất phức tạp và không an toàn theo luồng?
Hàm này phức tạp trong nỗ lực giữ trình tối ưu hóa xóa nó làm mã chết.
Tiêu chuẩn C không cung cấp từ khóa như pin
để đảm bảo tuyên bố không bị xóa. Nếu zeroizer đã được gỡ bỏ, sau đó các trình biên dịch folks sẽ cho bạn biết "... nhưng bạn yêu cầu tối ưu hóa".
C11 cung cấp memset_s
trong Phụ lục K, đảm bảo không bị xóa. Nhưng Drepper và bạn bè phản đối các chức năng "an toàn hơn", vì vậy chúng không có sẵn trên GNU Linux. Xem, ví dụ: glibc library is missing memset_s.
OpenSSL cũng tránh volatile
vì người GCC hiểu tiêu chuẩn để có nghĩa là bộ nhớ được phần cứng hỗ trợ. Đó là, bộ nhớ dễ bay hơi có thể được thay đổi bằng phần cứng, nhưng không phải là một chủ đề khác. Điều này trái ngược với cách giải thích của Microsoft về vòng loại.
Cũng lưu ý rằng trên nền tảng Windows (OpenSSL là nền tảng chéo), OpenSSL có thể sử dụng SecureZeroMemory
. Microsoft đã giải quyết vấn đề của trình tối ưu hóa xóa mã sớm.
EDIT (tháng 2 năm 2016): Dường như OpenSSL 1.1.0 đơn giản hóa các chức năng làm sạch: RT4116: Change cleanse to just memset. Đây là diff trên mem_clr.c
:
diff --git a/crypto/mem_clr.c b/crypto/mem_clr.c
index e6450a1..3389919 100644 (file)
--- a/crypto/mem_clr.c
+++ b/crypto/mem_clr.c
@@ -59,23 +59,16 @@
#include <string.h>
#include <openssl/crypto.h>
-extern unsigned char cleanse_ctr;
-unsigned char cleanse_ctr = 0;
+/*
+ * Pointer to memset is volatile so that compiler must de-reference
+ * the pointer and can't assume that it points to any function in
+ * particular (such as memset, which it then might further "optimize")
+ */
+typedef void *(*memset_t)(void *,int,size_t);
+
+static volatile memset_t memset_func = memset;
void OPENSSL_cleanse(void *ptr, size_t len)
{
- unsigned char *p = ptr;
- size_t loop = len, ctr = cleanse_ctr;
-
- if (ptr == NULL)
- return;
-
- while (loop--) {
- *(p++) = (unsigned char)ctr;
- ctr += (17 + ((size_t)p & 0xF));
- }
- p = memchr(ptr, (unsigned char)ctr, len);
- if (p)
- ctr += (63 + (size_t)p);
- cleanse_ctr = (unsigned char)ctr;
+ memset_func(ptr, 0, len);
}
Xem thêm Issue 455: Reimplement non-asm OPENSSL_cleanse() trên GitHub OpenSSL của.
Một mục đích của nó mà tôi biết là tránh yêu cầu của nó khỏi bị tối ưu hóa bởi trình biên dịch. – updogliu