Cách biên dịch trình biên dịch C từ đầu, sau đó biên dịch Unix / Linux từ đầu


64

Giả sử tôi làm việc cho một tổ chức dịch vụ lớn bên ngoài Hoa Kỳ / Vương quốc Anh. Chúng tôi sử dụng máy chủ UNIX và Linux rộng rãi.

Đọc qua bài viết này, nó đề cập rằng sẽ dễ dàng chèn một cửa hậu vào trình biên dịch C, sau đó bất kỳ mã nào được biên dịch với trình biên dịch đó cũng sẽ chứa một cửa hậu. Hiện đã có những rò rỉ gần đây liên quan đến nhiệm vụ của NSA / GCHQ trong việc đặt các điểm yếu / điểm yếu trong tất cả các phương pháp mã hóa, phần cứng và phần mềm, trình biên dịch hiện là một điểm nghiêm trọng. Có khả năng tất cả các bản phân phối UNIX / Linix tiêu chuẩn có thể bị xâm phạm. Chúng tôi không thể đủ khả năng để hệ thống, dữ liệu và dữ liệu khách hàng của chúng tôi bị xâm phạm bởi các chính phủ lừa đảo.

Với thông tin này, tôi muốn xây dựng một trình biên dịch đáng tin cậy từ đầu, sau đó tôi có một cơ sở an toàn để xây dựng để tôi có thể xây dựng Hệ điều hành và các ứng dụng từ mã nguồn bằng trình biên dịch đó.

Câu hỏi

Cách chính xác (và an toàn) để biên dịch trình biên dịch từ mã nguồn (kịch bản có vẻ như trứng gà) sau đó biên dịch bản phân phối Unix / Linux đáng tin cậy từ đầu là gì?

Bạn có thể giả sử tôi hoặc người khác có khả năng đọc và hiểu mã nguồn cho các lỗi bảo mật, vì vậy mã nguồn sẽ được xem xét trước khi biên dịch. Những gì tôi thực sự là một hướng dẫn làm việc để sản xuất trình biên dịch này từ đầu một cách an toàn và có thể được sử dụng để biên dịch kernel, các phần khác của HĐH và các ứng dụng.

Ngăn xếp bảo mật phải bắt đầu ở cấp cơ sở nếu chúng ta có niềm tin vào hệ điều hành hoặc các ứng dụng đang chạy trên ngăn xếp đó. Có, tôi hiểu rằng có thể có các cửa sổ phần cứng có thể chèn một số vi mã vào trình biên dịch khi nó được xây dựng. Hiện tại chúng tôi không thể làm gì nhiều về điều đó ngoại trừ có thể sử dụng chip không được thiết kế ở Mỹ. Chúng ta hãy sắp xếp lớp này để bắt đầu và giả sử tôi có thể xây dựng nó trên một máy tính cũ có khả năng trước khi bất kỳ backtime nào được chèn vào.

Như Bruce Schneier nói: "Đối với các kỹ sư, tôi nói điều này: chúng tôi đã xây dựng internet và một số người trong chúng tôi đã giúp phá hủy nó. Bây giờ, những người yêu thích tự do phải sửa nó."

Liên kết bổ sung:


7
Chết tiệt, đây là một câu hỏi rất thú vị và tôi không muốn di chuyển nó nhưng tôi thực sự không nghĩ nó là chủ đề ở đây. Nó phù hợp hơn với stackoverflow.com vì câu hỏi cơ bản của bạn là về cách biên dịch trình biên dịch từ đầu, điều này khá giống với bất khả tri của hệ điều hành và rất nhiều câu hỏi về lập trình. Nếu sau một thời gian bạn không nhận được câu trả lời, hãy cân nhắc sử dụng liên kết "cờ" bên dưới thẻ câu hỏi của bạn và yêu cầu người điều hành chuyển câu hỏi này sang SO.
terdon

2
@terdon Nó thực sự có thể phù hợp hơn với Lập trình viên. Vì nó liên quan đến các vấn đề lập trình chung hơn là một vấn đề phát triển cụ thể. Trong thực tế, nó có thể là một bản sao ở đó .
một CVn

2
GCC là nguồn mở, làm thế nào bất kỳ cửa hậu sẽ được chèn?
Michael Pankov

2
Hãy nhớ rằng việc khai thác ổn định của Thompson yêu cầu mã có thể nhận ra khi chương trình đăng nhập hoặc trình biên dịch đang được biên dịch. Nếu bạn có thể tự chuyển đổi nguồn thành một dạng không thể nhận ra đối với trình biên dịch là một trong những chương trình đó, thì cửa hậu sẽ không được truyền bá.
Russell Borogove

2
@Constantius - đọc bài viết của Thompson được liên kết trong dòng đầu tiên. Ai biên dịch trình biên dịch?
Russell Borogove

Câu trả lời:


30

AFAIK cách duy nhất để hoàn toàn chắc chắn về bảo mật là viết trình biên dịch bằng ngôn ngữ lắp ráp (hoặc tự sửa đổi đĩa trực tiếp ). Chỉ sau đó bạn mới có thể đảm bảo rằng trình biên dịch của bạn không chèn một cửa hậu - điều này hoạt động vì bạn thực sự đang loại bỏ hoàn toàn trình biên dịch.

Từ đó, bạn có thể sử dụng trình biên dịch từ đầu để bootstrap, ví dụ như chuỗi công cụ GNU. Sau đó, bạn có thể sử dụng chuỗi công cụ tùy chỉnh của mình để biên dịch hệ thống Linux From Scratch .

Lưu ý rằng để làm cho mọi thứ dễ dàng hơn với chính bạn, bạn có thể có một trình biên dịch trung gian thứ hai, được viết bằng C (hoặc bất kỳ ngôn ngữ nào khác). Vì vậy, bạn sẽ viết trình biên dịch A trong tập hợp, sau đó viết lại trình biên dịch đó trong C / C ++ / Python / Brainfuck / bất cứ điều gì để có được trình biên dịch B, mà bạn sẽ biên dịch bằng trình biên dịch A. Sau đó, bạn sẽ sử dụng trình biên dịch B để biên dịch gcc và bạn bè.


13
Mặc dù vậy, điều này vẫn chỉ bảo vệ chống lại một trình biên dịch độc hại. Bạn vẫn cần tin tưởng vào hệ thống mà trình biên dịch thực thi. Không có phần mềm tồn tại trong sự cô lập.
một CVn

3
Bất cứ điều gì tự chủ là nguy hiểm. Bạn đang đề xuất một cách hiệu quả một trình biên dịch toolchain (mặc dù là một trình lạ) có nghĩa là nó có thể được sửa đổi theo cách chính xác mà bạn đang cố gắng tránh. Thậm chí tốt hơn, nó có thể được sửa đổi trong quá cảnh thông qua MitM.
strugee

1
Các bạn phải nhận ra rằng câu trả lời này đến từ một đứa trẻ 15 tuổi. Hãy tiếp tục đi!
mtahmed

3
Bạn cũng không nên quên viết trình soạn thảo mã từ đầu - ai biết nếu <code> vim </ code> được biên dịch trước của bạn hoặc <code> vim </ code> bạn biên dịch với trình biên dịch tốt của bạn từ nguồn mà bạn đã kiểm tra chỉ bằng cách sử dụng <code> vim </ code> có đáng tin không?
Hagen von Eitzen

1
Đừng bao giờ quên, trừ khi bạn đích thân viết mã máy đầu tiên (không phải lắp ráp. Mã máy thực tế) và bạn là một chuyên gia trong việc nhận ra các lỗ hổng bảo mật được sử dụng, và đọc và kiểm tra từng dòng mã bạn đang biên dịch hoặc ít nhất là biết người đã làm điều đó cá nhân , tin tưởng anh ta để làm điều này .... không ai trong số này sẽ giúp được gì cả. Đó là lý do tại sao cố gắng để Kickstarter này, đang phá hỏng toàn bộ vấn đề. Đó là: Độ tin cậy cao.
Evi1M4chine

22

Một cách có thể, mặc dù nó sẽ mất một thời gian cực kỳ lâu trong thực tế, sẽ là quay trở lại cội nguồn. Sự phát triển của GNU bắt đầu vào năm 1984 và phiên bản gốc của Minix (được sử dụng trong quá trình phát triển Linux ban đầu cho mục đích bootstrapping) đã được phát hành vào năm 1987.

Toàn bộ câu trả lời này dựa trên tiền đề của bạn rằng "[bạn] hoặc người khác có khả năng đọc và hiểu mã nguồn cho các lỗi bảo mật, vì vậy mã nguồn sẽ được xem xét trước khi biên dịch" và bạn có thể tin tưởng vào kết quả phân tích như vậy . Không có điều đó, câu trả lời này có lẽ tồi tệ hơn vô giá trị, vì bạn sẽ dành một lượng thời gian khổng lồ mà hoàn toàn không có lợi ích gì.

Nếu bạn có thể tìm thấy một bản sao của cuốn sách Minix gốc với mã nguồn, bạn có thể nhập nó từ cuốn sách. Biên dịch nó, và sau đó sử dụng một trình dịch ngược khác nhau trên một hệ thống khác để xác minh rằng trình biên dịch tạo ra đầu ra nhị phân của ngôn ngữ máy dự kiến. (Mã chỉ có 12.000 dòng, có lẽ là C, do đó, việc này rất tốn thời gian nhưng vẫn có lý do nếu bạn nghiêm túc với một dự án như vậy.) Bạn thậm chí có thể viết trình dịch ngược của chính mình; Điều đó không nên rất khó khăn.

Nắm bắt các phiên bản cũ nhất của các tiện ích GNU mà bạn có thể có trong tay (vì chúng có thể có ít mã hơn và ít phụ thuộc hơn vào các thư viện bên ngoài), đi qua mã, xây dựng nó cho Minix (mặc dù điều này có thể mất một số công việc hoàn toàn muốn tránh là điều chỉnh mã nguồn, vì điều đó sẽ khiến việc thêm các bản vá sau này rất dễ bị lỗi) và trải qua một chu trình xác minh tháo rời tương tự cho các công cụ GNU. Tại thời điểm đó, bạn tin tưởng vào HĐH và chuỗi công cụ, vì vậy bạn chỉ cần xem qua mã nguồn trong bản vá (mọi thứ không có trong bản vá đã được tin cậy), nhưng các công cụ vẫn sẽ rất thô sơ và thô sơ so với những gì bạn đang sử dụng đến ngày hôm nay. Chẳng hạn, không mong đợi gì hơn chức năng cơ bản nhất của các công cụ hệ thống đang hoạt động.Đọc nhiều XKCD.

Tại một số điểm, bạn sẽ có một hệ thống có thể biên dịch và khởi động phiên bản đầu tiên của nhân Linux, giống như nó đã được thực hiện vào đầu những năm 1990 khi Linux bắt đầu có được lực kéo giữa các tin tặc. Tôi khuyên bạn nên chuyển sang Linux vào thời điểm đó (xây dựng lại các thư viện hệ thống và chuỗi công cụ chống lại Linux, xây dựng nhân Linux, khởi động vào Linux và có thể xây dựng lại nhân Linux và chuỗi công cụ GNU trong Linux; lưu trữ), nhưng điều đó phần lớn phụ thuộc vào bạn. Tiếp tục xác minh các bản vá, vá kernel, thư viện và các công cụ GNU cơ bản và xây dựng lại cho đến khi bạn có được các phiên bản hiện đại.

Đó là khi bạn có một hệ điều hành và trình biên dịch cơ bản đáng tin cậy có thể được sử dụng để xây dựng phần mềm hiện đại. Đến lúc đó, bạn có thể làm theo, ví dụ như các hướng dẫn Linux From Scratch để xây dựng một hệ thống có khả năng thực hiện các tác vụ hữu ích .

Không bao giờ có thể kết nối hệ thống "trình biên dịch" với một mạng theo bất kỳ cách nào (kể cả dưới dạng VM trên máy chủ được nối mạng); bạn có nguy cơ thâm nhập thông qua bất kỳ thành phần nào có khả năng kết nối mạng bao gồm cả kernel. Nếu bạn lo lắng về một cuộc tấn công trình biên dịch Thompson , bạn phải hy vọng rằng bất kỳ máy chủ VM nào cũng có thể bị xâm phạm. Sử dụng sneakernet để lấy mã nguồn và nhị phân từ máy chủ vật lý mà bạn đang biên dịch mọi thứ trên đó. Mong đợi sự cố khi bật và tắt tệp ít nhất là trước khi bạn đến điểm hỗ trợ lưu trữ dung lượng lớn USB. Nếu bạn thực sự hoang tưởng, hãy in danh sách mã nguồn và nhập chúng bằng tay (và hy vọng rằng trình điều khiển máy in và máy in không có mã tương tự trong đó) hoặc đọc mã trên một màn hình máy tính và nhập mã vào một máy tính khác bên cạnh nhưng không được kết nối với nó.

Vâng, điều này sẽ mất rất nhiều thời gian. Nhưng lợi thế của phương pháp này là mỗi bước được tăng dần, có nghĩa là sẽ khó khăn hơn nhiều cho bất kỳ thứ gì độc hại để vượt qua trừ khi nó được giới thiệu dần dần trong một khoảng thời gian của nhiều phiên bản; điều này là do tập hợp các thay đổi ở mỗi bước tương đối nhỏ và do đó dễ nhìn hơn nhiều. So sánh bản vá với thay đổi và đảm bảo bạn có thể xác định chính xác mục nhập thay đổi nào tương ứng với mọi thay đổi trong mã nguồn. Một lần nữa, điều này giả định rằng bạn có khả năng (có thể thông qua người mà bạn tin tưởng) để xác minh rằng những thay đổi đó chưa được đưa vào codebase, nhưng nó sẽ giúp bạn tiến gần đến một hệ thống đáng tin cậy như một phần mềm ngoại trừ - phương pháp phần mềm có thể.


Phương pháp xác minh tách rời là rất thiếu sót, vì nó vẫn đưa ra giả định rất lớn, rằng máy xác minh hoàn toàn đáng tin cậy. Trừ khi bạn xây dựng cỗ máy đó và phần mềm của nó từ đầu, hoặc biết người đã đích thân và tin tưởng cô ấy, điều này sẽ không xảy ra. Vì vậy, điều này vẫn không an toàn. Lấy làm tiếc. Ngoài ra, trong những vấn đề này, gần như với Giáo dục, vẫn có nghĩa là không an toàn, vì nó chỉ yêu cầu một điểm không đáng tin cậy để phá hỏng toàn bộ vấn đề.
Evi1M4chine

9

Nếu bạn cần một trình biên dịch đáng tin cậy, bạn có thể xem công việc học tập, như dự án compcert . Đó là một trình biên dịch được xây dựng bởi INRIA (một phòng thí nghiệm công cộng CNTT của Pháp) được thiết kế để được 'chứng nhận' ', nghĩa là tạo ra một mã thực thi hoàn toàn tương đương với mã (và tất nhiên, nó đã được chứng minh về mặt toán học).


1
Mọi người đều cần một trình biên dịch đáng tin cậy. Làm thế nào để các toán học hoạt động mà họ có thể tạo ra một trình biên dịch "đáng tin cậy"?
David J

@DavidJ Bootstrapping, rất có thể. Xây dựng một số phần nhỏ mà bạn hoàn toàn có thể xác minh và chứng minh chính xác, sau đó sử dụng nó làm nền tảng để xây dựng các trình biên dịch phức tạp hơn.
một CVn

1
"" "Điều gì bộ CompCert C ngoài từ bất kỳ trình biên dịch sản xuất khác, là nó được chính thức xác nhận, sử dụng chứng minh toán học máy hỗ trợ, để được miễn các vấn đề miscompilation." "" Compcert.inria.fr/compcert-C.html Compilation không phải là kinh nghiệm như trước đây.
lgeorget

1
@ MichaelKjorling có lẽ không tính đến việc hạt nhân có thể bị xâm phạm để đưa một cửa hậu vào nguồn trình biên dịch khi được đọc bởi trình biên dịch
ratchet freak

1
Tôi cũng tìm thấy liên kết này có thể làm việc quá.
David J

2

Trong khi tự tạo trình biên dịch của riêng bạn làm điểm bắt đầu sẽ an toàn nhất, một tùy chọn khác là cài đặt hệ thống từ đĩa CD cài đặt 5 (hoặc 10) năm mà bạn tin tưởng đã được tạo trước khi các khai thác này tồn tại. Sau đó sử dụng nó làm nền tảng để biên dịch nguồn được kiểm toán mới từ.


5
Cuộc tấn công đã được biết đến công khai từ năm 1984. Có lẽ Thompson không phải là người đầu tiên nghĩ về khả năng này. Quay trở lại xa như vậy có nghĩa là hầu hết những điều chúng ta cho là ngày nay không có ở đây; xem xét những gì máy tính có khả năng làm 20 năm trước và so sánh nó với tình trạng hiện tại của chúng. Ngay cả hệ thống bootstrap Linux ban đầu Minix cũng không được phát hành cho đến '87 và sự phát triển của GNU bắt đầu từ '84. Vì vậy, trong lý thuyết, điều này có thể trả lời câu hỏi, trong thực tế, nó hầu như vô dụng như một câu trả lời.
một CVn

2
Máy tính đầu tiên mà tôi có khả năng có thể sử dụng sẽ là một chiếc 286. Tôi sẽ phải xem ông bà tôi còn dùng nó không.
David J

1
Điểm thưởng cho việc thực sự xem xét rằng :-). @DavidJ
11684

@ MichaelKjorling: Không thực sự; vì nó chỉ làm cho chuỗi bootstrapping của bạn dài hơn. Nhưng có lẽ không lâu bằng việc viết trình biên dịch của riêng bạn từ đầu bằng ngôn ngữ máy.
Evi1M4chine
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.