RAND_bytes() failed گزاره‌ای درباره یک ابتدایی محلی است، نه درباره حساب، کلید از پیش به‌اشتراک‌گذاشته یا درگاه راه دور. دو خرابی بسیار متفاوت همان خط را تولید می‌کنند و ردپای متفاوتی بر جای می‌گذارند. یکی بک‌اند رمزنگاری است که از بیرون دادن بایت خودداری می‌کند؛ دیگری فرایندی است که به منبع آنتروپی‌ای که کدش برای آن ساخته شده نمی‌رسد. جدا کردن آن‌ها به یک خواندن صف خطا و یک نگاه به نمای فایل‌سیستم فرایند زندانی نیاز دارد، و این بررسی باید پیش از هر چیزی که زیر /dev ساخته می‌شود انجام شود.

مقدار بازگشتی چه چیزی را از هم جدا می‌کند

قرارداد مستندشده سه پیامد را از هم جدا می‌کند، نه دو: 1 برای موفقیت، -1 هنگامی که روش RAND بارگذاری‌شده درخواست را پشتیبانی نمی‌کند، و 0 برای دیگر خرابی‌ها، با توضیحی که در صف خطا می‌ماند. مرجع RAND_bytes نکته‌ای را می‌افزاید که آسان از نظر می‌گذرد: مولد پیش‌فرض روی پلتفرم‌های پشتیبانی‌شده بذر را از سیستم‌عامل می‌گیرد، و وقتی این بذرگیری شکست بخورد در وضعیت خطا می‌ماند به‌جای بازگرداندن بایت‌های قابل پیش‌بینی.

تنها یکی از آن اعداد محیط را توصیف می‌کند. 1- پرسشی درباره ساخت، ارائه‌دهنده یا قابلیت است، چون کد چیزی را خواسته که پیاده‌سازی فعال ارائه نمی‌کند. 0 همراه با شکایت بذرگیری پرسشی محیطی است، چون مولد اصلاً نتوانست آنتروپی به دست آورد. خود عدد هرگز نمی‌گوید کدام، و نام تابع هم نمی‌گوید.

وقتی گره دستگاه پنهان علت واقعی است

سرویس محدودشده درختی متفاوت از پوسته‌ای که در آن تایپ می‌کنید می‌بیند. زندان‌های chroot، تصاویر کانتینر و فایل‌های unit سخت‌شده مرتباً /dev را ارائه می‌دهند که گره‌های کمتری از میزبان دارد. اگر پیاده‌سازی خراب‌شده /dev/urandom را بر اساس نام مسیر باز کند، همین تفاوت برای شکستن راه‌اندازی کافی است در حالی که خود میزبان کاملاً سالم به نظر می‌رسد. دستگاهی که بیرون از زندان وجود دارد چیزی را درباره آنچه فرایند زندانی اجازه باز کردنش را دارد ثابت نمی‌کند.

با این حال هر رابط تصادفی به مسیر نیاز ندارد. فراخوان سیستمی getrandom در لینوکس نه نام فایل می‌پذیرد و نه توصیفگر فایل، و صفحه راهنمای آن یادآوری می‌کند که این ویژگی دقیقاً جایی سودمند است که chroot مسیرهای دستگاه را پنهان می‌کند.

پس توضیح گره گمشده فرضیه‌ای درباره یک شاخه کد است، نه قاعده‌ای درباره اعداد تصادفی به‌طور کلی. وقتی شواهد مسیری را نام می‌برند پابرجا می‌ماند، و وقتی شواهد چیز دیگری را نام می‌برند حدس است.

نخست صف خطا را بخوانید، سپس نمای فرایند

سریع‌ترین راه برای فیصله دادن به پرسش این است که آنچه کتابخانه ثبت کرده بخوانید و سپس مستقیم به نمای درون زندان نگاه کنید. با ساخت OpenSSL که سرویس واقعاً بارگذاری کرده شروع کنید، چون پشته‌های ارائه‌دهنده میان نسخه‌های اصلی و میان توزیع‌ها تفاوت دارند. سپس از systemd بپرسید کدام فرایند در حال اجراست و چه محدودیت‌هایی بر آن اعمال می‌شود. تنها وقتی هر دو واقعیت روی میز است ارزش دارد گره‌هایی را فهرست کنید که آن فرایند می‌بیند.

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

این خواندن‌ها را روی همان فرایند انجام دهید، نه روی پوسته‌ای که تصادفاً باز است. مقایسه /dev میزبان با نمای یک فرایند بی‌ربط همان راهی است که وابستگی نادرست دو بار تعمیر می‌شود.

وابستگی را تنها وقتی اضافه کنید که می‌توانید نامش را ببرید

وقتی شواهد واقعاً مسیری را نام می‌برند، تعمیر کوچک است: همان یک مسیر را درون زندان در دسترس کنید و بقیه را رها کنید. یک bind mount از همان گره واحد معمولاً کافی است، و mknod با شماره‌های major و minor استاندارد گره همان نتیجه را در نصب‌هایی می‌دهد که mount گزینه نیست. گسترش sandbox، دادن دسترسی به هر دستگاه نویسه یا خاموش کردن PrivateDevices تعمیری هدفمند را با پس‌رفت امنیتی دائمی معاوضه می‌کند.

شبح آنتروپی جایگزین آن تعمیر نیست. بسته‌هایی مانند haveged تغییر می‌دهند که استخر هسته چگونه تغذیه می‌شود؛ آن‌ها نمی‌توانند مسیری بسازند که فرایند زندانی اجازه باز کردنش را داشته باشد. نصب یکی می‌تواند نمودار سلامت را بهتر نشان دهد در حالی که فراخوان باز کردن هنوز شکست می‌خورد. دو مشکل را جدا نگه دارید، وگرنه خرابی بعدی دوباره به لایه نادرست نسبت داده می‌شود.

مولد و تونل را جداگانه بررسی کنید

راه‌اندازی مجدد تنها آزمونی است که همان پیکربندی، همان فایل unit و همان محدودسازی‌ای را که خرابی را پدید آورد دوباره به کار می‌گیرد. آن را اجرا کنید و سپس جدیدترین مدخل‌های ژورنال را بخوانید، نه نمونه‌ای از یک راه‌اندازی پیشین.

sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'

در آن خروجی دو چیز جداگانه را جست‌وجو کنید: ناپدید شدن پیام منبع تصادفی، و رسیدن تونل به نقطه عطف معمول راه‌اندازی. مولدی که دوباره کار می‌کند یک خرابی محلی را برمی‌دارد و چیزی درباره هویت سرور، اعتبارنامه‌ها یا مسیریابی نمی‌گوید. آن را با همان پیکربندی کلاینتی که پیش‌تر شکست خورد بیازمایید، تا نتیجه قابل مقایسه باشد و نه فقط بهتر.

مقالات مرتبط