C/C++ 多線程

2021-05-28 10:07 更新

3.1 【必須】變量應(yīng)確保線程安全性

當(dāng)一個變量可能被多個線程使用時,應(yīng)當(dāng)使用原子操作或加鎖操作。

// Bad
char  g_somechar;
void foo_thread1() {
  g_somechar += 3;
}


void foo_thread2() {
  g_somechar += 1;
}

對于可以使用原子操作的,應(yīng)當(dāng)使用一些可以確保內(nèi)存安全的操作,如:

// Good
volatile char g_somechar;
void foo_thread1() {
  __sync_fetch_and_add(&g_somechar, 3);
}


void foo_thread2() {
  __sync_fetch_and_add(&g_somechar, 1);
}

對于 C 代碼,C11 后推薦使用 atomic 標(biāo)準(zhǔn)庫。 對于 C++代碼,C++11 后,推薦使用 std::atomic

關(guān)聯(lián)漏洞:

  • 高風(fēng)險-內(nèi)存破壞

  • 中風(fēng)險-邏輯問題

3.2 【必須】注意 signal handler 導(dǎo)致的條件競爭

競爭條件經(jīng)常出現(xiàn)在信號處理程序中,因為信號處理程序支持異步操作。攻擊者能夠利用信號處理程序爭用條件導(dǎo)致軟件狀態(tài)損壞,從而可能導(dǎo)致拒絕服務(wù)甚至代碼執(zhí)行。

  1. 當(dāng)信號處理程序中發(fā)生不可重入函數(shù)或狀態(tài)敏感操作時,就會出現(xiàn)這些問題。因為信號處理程序中隨時可以被調(diào)用。比如,當(dāng)在信號處理程序中調(diào)用free時,通常會出現(xiàn)另一個信號爭用條件,從而導(dǎo)致雙重釋放。即使給定指針在釋放后設(shè)置為NULL,在釋放內(nèi)存和將指針設(shè)置為NULL之間仍然存在競爭的可能。
  2. 為多個信號設(shè)置了相同的信號處理程序,這尤其有問題——因為這意味著信號處理程序本身可能會重新進(jìn)入。例如,malloc()和free()是不可重入的,因為它們可能使用全局或靜態(tài)數(shù)據(jù)結(jié)構(gòu)來管理內(nèi)存,并且它們被syslog()等看似無害的函數(shù)間接使用;這些函數(shù)可能會導(dǎo)致內(nèi)存損壞和代碼執(zhí)行。

// Bad
char *log_message;


void Handler(int signum) {
  syslog(LOG_NOTICE, "%s\n", log_m_essage);
  free(log_message);
  sleep(10);
  exit(0);
}


int main (int argc, char* argv[]) {
  log_message = strdup(argv[1]);
  signal(SIGHUP, Handler);
  signal(SIGTERM, Handler);
  sleep(10);
}

可以借由下列操作規(guī)避問題:

  1. 避免在多個處理函數(shù)中共享某些變量。
  2. 在信號處理程序中使用同步操作。
  3. 屏蔽不相關(guān)的信號,從而提供原子性。
  4. 避免在信號處理函數(shù)中調(diào)用不滿足異步信號安全的函數(shù)。

關(guān)聯(lián)漏洞:

  • 高風(fēng)險-內(nèi)存破壞

  • 中風(fēng)險-邏輯問題

3.3 【建議】注意Time-of-check Time-of-use (TOCTOU) 條件競爭

TOCTOU: 軟件在使用某個資源之前檢查該資源的狀態(tài),但是該資源的狀態(tài)可以在檢查和使用之間更改,從而使檢查結(jié)果無效。當(dāng)資源處于這種意外狀態(tài)時,這可能會導(dǎo)致軟件執(zhí)行錯誤操作。

當(dāng)攻擊者可以影響檢查和使用之間的資源狀態(tài)時,此問題可能與安全相關(guān)。這可能發(fā)生在共享資源(如文件、內(nèi)存,甚至多線程程序中的變量)上。在編程時需要注意避免出現(xiàn)TOCTOU問題。

例如,下面的例子中,該文件可能已經(jīng)在檢查和lstat之間進(jìn)行了更新,特別是因為printf有延遲。

struct stat *st;


lstat("...", st);


printf("foo");


if (st->st_mtimespec == ...) {
  printf("Now updating things\n");
  UpdateThings();
}

TOCTOU難以修復(fù),但是有以下緩解方案:

  1. 限制對來自多個進(jìn)程的文件的交叉操作。
  2. 如果必須在多個進(jìn)程或線程之間共享對資源的訪問,那么請嘗試限制”檢查“(CHECK)和”使用“(USE)資源之間的時間量,使他們相距盡量不要太遠(yuǎn)。這不會從根本上解決問題,但可能會使攻擊更難成功。
  3. 在Use調(diào)用之后重新檢查資源,以驗證是否正確執(zhí)行了操作。
  4. 確保一些環(huán)境鎖定機制能夠被用來有效保護(hù)資源。但要確保鎖定是檢查之前進(jìn)行的,而不是在檢查之后進(jìn)行的,以便檢查時的資源與使用時的資源相同。

關(guān)聯(lián)漏洞:

  • 高風(fēng)險-內(nèi)存破壞

  • 中風(fēng)險-邏輯問題
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號