2014-10-17 11 views
7

Đây là việc thực hiện các OPENSSL_cleanse trong OpenSSL 1.0.1iTại sao OPENSSL_cleanse trông rất phức tạp và không an toàn theo luồng?

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

Có vẻ phức tạp và thread-an toàn (bằng cách đọc và viết biến toàn cầu cleanse_ctr). Ai đó có thể xin giải thích một chút về việc thực hiện này? Người dùng có cần phải quan tâm đến cuộc đua dữ liệu có thể có trong đó không?

+2

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

Trả lời

4

Có một cuộc đua dữ liệu trong mã, nhưng nó không quan trọng vì điểm của biến chỉ là cung cấp dữ liệu rác khác nhau để điền vào một phần bộ nhớ. Nói cách khác, nó không bao giờ thực sự quan trọng giá trị bất kỳ chủ đề nào được đọc từ biến đó. Người dùng không cần phải lo lắng về nó. Trong thực tế, cuộc đua dữ liệu thậm chí có thể làm cho chức năng hiệu quả hơn.

5

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.

Các vấn đề liên quan