2014-10-17 58 views
7

這是(通過讀取和寫入全局變量cleanse_ctr)OPENSSL_cleanse的OpenSSL中1.0.1i爲什麼OPENSSL_cleanse看起來如此複雜且線程不安全?

unsigned char cleanse_ctr = 0; 

void OPENSSL_cleanse(void *ptr, size_t len) 
{ 
    unsigned char *p = ptr; 
    size_t loop = len, ctr = cleanse_ctr; 
    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; 
} 

它看起來複雜,線程安全的實現。有人可以請解釋一下這個實現嗎?用戶是否需要關注可能的數據競爭?

+2

我知道的一個目的是避免它被編譯器優化掉。 – updogliu 2014-10-17 21:38:40

回答

4

代碼中存在數據爭用,但它並不重要,因爲變量的要點只是提供可用於填充內存的各種垃圾數據。換句話說,任何給定的線程從該變量讀取的值都不重要。用戶不需要關心它。事實上,數據競賽甚至可能會使該功能更有效。

5

爲什麼OPENSSL_cleanse看起來如此複雜和線程不安全?

該函數很複雜,試圖阻止優化器將其作爲死代碼移除。

C標準沒有提供像pin這樣的關鍵字來確保不刪除語句。如果零化器被移除,那麼編譯器人員會告訴你「...但你要求優化」。

C11在附錄K中提供memset_s,保證不會被刪除。但是Drepper和朋友反對「安全」的功能,所以它們在GNU Linux上不可用。例如,參見glibc library is missing memset_s

OpenSSL也避免了volatile,因爲GCC人員將標準解釋爲硬件支持的內存。就是說,易失性存儲器可以通過硬件來改變,但不能通過另一個線程來改變這與微軟對限定詞的解釋形成鮮明對比。

另請注意,在Windows平臺上(OpenSSL是跨平臺的),OpenSSL可以使用SecureZeroMemory。微軟解決了優化器提前刪除代碼的問題。


EDIT(二月2016):它看起來像OpenSSL的1.1.0簡化了清洗功能:RT4116: Change cleanse to just memset。下面是關於mem_clr.c的DIFF:

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); 
} 

另見Issue 455: Reimplement non-asm OPENSSL_cleanse()上OpenSSL的GitHub上。

相關問題