RAND_bytes thất bại trong OpenVPN: lỗi thư viện hoặc thiếu nút
Một lỗi RAND_bytes có thể nghĩa là nguồn entropi bị từ chối hoặc một nút bị jail che khuất. Hãy đọc hàng đợi lỗi và góc nhìn tiến trình trước khi tạo thiết bị.
RAND_bytes() failed là một phát biểu về một nguyên thủy cục bộ, không phải về tài khoản, khóa chia sẻ trước hay cổng từ xa. Hai lỗi rất khác nhau tạo ra cùng một dòng và để lại bằng chứng khác nhau. Một là backend mật mã từ chối phát ra byte; còn lại là tiến trình không chạm tới nguồn entropi mà mã của nó được xây dựng để dùng. Phân tách chúng cần một lần đọc hàng đợi lỗi và một lần nhìn vào góc nhìn hệ thống tệp của chính tiến trình bị giam, và việc kiểm tra đó phải diễn ra trước khi bất cứ thứ gì được tạo dưới /dev.
Giá trị trả về phân biệt điều gì
Hợp đồng được ghi chép phân biệt ba kết cục, không phải hai: 1 cho thành công, -1 khi phương thức RAND đã nạp không hỗ trợ yêu cầu, và 0 cho các lỗi khác, với phần giải thích để lại trong hàng đợi lỗi. Tài liệu tham chiếu RAND_bytes thêm một điểm dễ bỏ qua: bộ sinh mặc định lấy hạt giống từ hệ điều hành trên các nền tảng được hỗ trợ, và khi việc gieo hạt đó thất bại, nó vẫn ở trạng thái lỗi thay vì trả về các byte có thể đoán trước.
Chỉ một trong những con số đó mô tả môi trường. -1 là câu hỏi về bản dựng, nhà cung cấp hoặc tính năng, vì mã yêu cầu thứ mà cách triển khai đang hoạt động không cung cấp. 0 kèm phàn nàn về gieo hạt là câu hỏi môi trường, vì bộ sinh hoàn toàn không lấy được entropi. Bản thân con số không bao giờ nói là cái nào, và tên hàm cũng vậy.
Khi một nút thiết bị bị che là nguyên nhân thật
Dịch vụ bị giới hạn nhìn thấy một cây khác với shell bạn đang gõ. Chroot jail, image container và tệp unit được gia cố thường xuyên trình ra một /dev chứa ít nút hơn của máy chủ. Nếu cách triển khai thất bại mở /dev/urandom theo tên đường dẫn, khác biệt đó đủ để phá vỡ quá trình khởi động trong khi bản thân máy chủ trông hoàn toàn khỏe mạnh. Một thiết bị tồn tại ngoài jail không chứng minh gì về việc tiến trình bị giam được phép mở gì.
Không phải mọi giao diện ngẫu nhiên đều cần đường dẫn. Lệnh gọi hệ thống getrandom của Linux không nhận tên tệp cũng không nhận bộ mô tả tệp, và trang hướng dẫn của nó ghi nhận rằng đặc tính này hữu ích đúng ở nơi chroot che giấu đường dẫn thiết bị.
Vì vậy lời giải thích về nút thiếu là một giả thuyết về một nhánh mã, không phải quy tắc về số ngẫu nhiên nói chung. Nó đứng vững khi bằng chứng nêu một đường dẫn, và là phỏng đoán khi bằng chứng nêu thứ khác.
Đọc hàng đợi lỗi, rồi đến góc nhìn tiến trình
Cách nhanh nhất để giải quyết câu hỏi là đọc những gì thư viện đã ghi lại, rồi nhìn trực tiếp vào góc nhìn bên trong jail. Bắt đầu với bản dựng OpenSSL mà dịch vụ thực sự đã nạp, vì các chồng nhà cung cấp khác nhau giữa các phiên bản chính và giữa các bản phân phối. Sau đó hỏi systemd tiến trình nào đang chạy và những hạn chế nào áp dụng cho nó. Chỉ khi cả hai sự thật đã ở trên bàn mới đáng liệt kê các nút mà tiến trình đó có thể thấy.
openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random
Thực hiện những lần đọc đó trên cùng một tiến trình, không phải trên shell tình cờ đang mở. So sánh /dev của máy chủ với góc nhìn của một tiến trình không liên quan chính là cách phụ thuộc sai được sửa hai lần.
Chỉ thêm phụ thuộc sau khi bạn gọi được tên nó
Khi bằng chứng thật sự nêu một đường dẫn, việc sửa chữa là nhỏ: làm cho đúng đường dẫn đó khả dụng bên trong jail và để mọi thứ khác yên. Một bind mount của nút đơn thường là đủ, và mknod với số major và minor tiêu chuẩn của nút cho cùng kết quả trên những bản cài đặt nơi mount không phải lựa chọn. Mở rộng sandbox, cấp quyền truy cập cho mọi thiết bị ký tự hoặc tắt PrivateDevices đánh đổi một bản sửa có mục tiêu lấy một thoái hóa bảo mật vĩnh viễn.
Một daemon entropi không thay thế bản sửa đó. Các gói như haveged thay đổi cách bể nhân được nuôi; chúng không thể tạo ra một tên đường dẫn mà tiến trình bị giam được phép mở. Cài một cái có thể làm biểu đồ sức khỏe trông đẹp hơn trong khi lệnh gọi mở vẫn thất bại. Giữ hai vấn đề tách biệt, nếu không lỗi tiếp theo sẽ lại bị quy cho lớp sai.
Kiểm tra riêng bộ sinh và đường hầm
Khởi động lại là phép thử duy nhất dùng lại cùng cấu hình, cùng tệp unit và cùng cách ly đã tạo ra lỗi. Hãy chạy nó, rồi đọc các mục nhật ký mới nhất thay vì một mẫu từ lần khởi động trước.
sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'
Tìm hai thứ riêng biệt trong đầu ra đó: thông báo về nguồn ngẫu nhiên biến mất, và đường hầm đạt mốc khởi động thường lệ. Một bộ sinh hoạt động lại loại bỏ một lỗi cục bộ và không nói gì về danh tính máy chủ, thông tin xác thực hay định tuyến. Hãy thử điều đó với cùng cấu hình máy khách đã thất bại trước đây, để kết quả có thể so sánh chứ không chỉ tốt hơn.