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

مدل مجوزدهی، نه معجزه

در گنو/لینوکس هر کاربر از ابتدا با کمترین سطح دسترسی ممکن کار می‌کند. فایل‌های سیستمی متعلق به روت هستند و کاربر عادی حتی اگر بخواهد نمی‌تواند بدون وارد کردن رمز روت یک باینری را در مسیرهای سیستمی جایگزین کند یا سرویسی را دستکاری کند. این یعنی حتی اگر یک برنامه مخرب اجرا شود، محدود به فضای کاربری خودش می‌ماند و نمی‌تواند مثل ویندوز قدیم با یک دابل‌کلیک ساده کل سیستم را آلوده کند. مدل sudo هم طوری طراحی شده که هر بار درخواست دسترسی بالا را آشکارا از کاربر می‌گیرد، برخلاف رویه‌ای که در ویندوز تا سال‌ها UAC را می‌شد بی‌فکر تایید کرد.

پکیج‌منیجر و ریپازیتوری رسمی

بیشتر کاربران لینوکس نرم‌افزار را نه از سایت‌های تصادفی، بلکه از ریپازیتوری رسمی توزیع خودشان نصب می‌کنند. این پکیج‌ها معمولاً امضا شده‌اند و از یک منبع مرکزی قابل اعتماد می‌آیند، درست برخلاف عادت رایج در ویندوز که کاربر مجبور است یک نصب‌کننده exe از یک سایت ناشناس دانلود کند. در آرچ و توزیع‌های مبتنی بر آن مثل پارچ، pacman بسته‌ها را با کلید GPG بررسی می‌کند و اگر امضا نامعتبر باشد اصلاً اجازه نصب نمی‌دهد.

تکه‌تکه بودن اکوسیستم، یک مانع واقعی برای بدافزار

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

پس چرا آنتی‌ویروس این‌جا بی‌فایده است؟

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

کرنل لینوکس و انبوه CVEهایی که هر سال منتشر می‌شود

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

کرنل لینوکس چیزی حدود سی میلیون خط کد دارد، شاید هم بیشتر بسته به اینکه چه چیزی را بشمارید. این عدد به تنهایی گویا نیست چون بخش زیادی از این کد درایورهای سخت‌افزاری هستند که فقط روی یک تراشه خاص فعال می‌شوند و در سیستم شما اصلاً بارگذاری نمی‌شوند. اما همان بخش فعال هم به قدری بزرگ است که هیچ تیم انسانی نمی‌تواند ادعا کند همه مسیرهای کد را دستی بررسی کرده. برای همین کرنل سال‌هاست به سمت فازینگ خودکار رفته، ابزاری به اسم syzkaller که گوگل توسعه‌اش داده و مدام ورودی‌های تصادفی و عجیب به سیستم‌کال‌ها می‌فرستد تا حالت‌های کرش یا رفتار نامعتبر پیدا کند. این ابزار به همراه ابزارهای تشخیص خطا مثل KASAN برای پیدا کردن دسترسی نامعتبر به حافظه، و KCSAN برای پیدا کردن شرایط رقابتی بین رشته‌ها، باعث شده تعداد باگ‌های کشف‌شده در کرنل چند برابر شود. این خبر بد نیست، خبر خوب است. باگی که فازینگ خودکار قبل از انتشار عمومی پیدا کرده و پچ شده، باگی است که هرگز فرصت نکرده در دنیای واقعی مورد سوءاستفاده قرار بگیرد. مشکل این‌جاست که هر باگ کشف‌شده لزوماً یک شماره CVE می‌گیرد، حتی اگر شرایط بهره‌برداری از آن عملاً غیرممکن یا بسیار محدود باشد.

گرگ کروآ هارتمن که یکی از نگهدارنده‌های اصلی کرنل و مسئول شاخه‌های پایدار است، سال‌هاست روی این موضع تاکید می‌کند که در کرنل لینوکس هر باگ به طور بالقوه یک باگ امنیتی است. در پروژه‌ای به این اندازه، مرز بین یک باگ معمولی که باعث کرش یک درایور نادر می‌شود و یک آسیب‌پذیری واقعی که به یک مهاجم اجازه اجرای کد در سطح کرنل می‌دهد همیشه روشن نیست. به همین دلیل تیم کرنل تصمیم گرفت هر پچی که به هر نحوی رفتار نامعتبر را اصلاح می‌کند بالقوه واجد شرایط CVE در نظر گرفته شود، و از سال ۲۰۲۴ کرنل لینوکس خودش به عنوان یک مرجع مستقل صدور شماره CVE عمل می‌کند به‌جای اینکه منتظر نهادهای بیرونی بماند. نتیجه این تغییر یک جهش شدید در تعداد CVEهای ثبت‌شده برای کرنل بود، عددی که اگر آن را با هر پروژه نرم‌افزاری دیگری مقایسه کنید مضحک به نظر می‌رسد.

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

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

این‌جا یکی از تفاوت‌های واقعی بین یک توزیع rolling release مثل آرچ با توزیع‌هایی مثل دبیان استیبل یا RHEL نمایان می‌شود. توزیع‌های شاخه پایدار معمولاً یک نسخه کرنل را برای مدت طولانی نگه می‌دارند و به‌جای آپدیت کامل به نسخه جدید، پچ‌های امنیتی خاص را به آن نسخه قدیمی‌تر بازپورت می‌کنند. این کار از نظر پایداری منطقی است ولی بازپورت کردن کار دستی و کند است و همیشه ریسک این وجود دارد که یک پچ به موقع بازپورت نشود. آرچ در مقابل تقریباً همیشه نزدیک‌ترین نسخه به بالادست را ارائه می‌دهد و آپدیت‌ها به محض انتشار بسته‌بندی و در ریپازیتوری قرار می‌گیرند، یعنی فاصله زمانی بین انتشار یک پچ در بالادست و رسیدن آن به دست کاربر آرچ بسیار کوتاه‌تر از بسیاری توزیع‌های دیگر است.

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

نمونه معروف Dirty COW با شماره CVE-2016-5195 دقیقاً از جنس ارتقای امتیاز محلی بود. این آسیب‌پذیری از یک شرایط رقابتی در مکانیزم کپی‌هنگام‌نوشتن مدیریت حافظه کرنل سواستفاده می‌کرد، جایی که یک کاربر بدون امتیاز می‌توانست با فراخوانی همزمان و به‌موقع چند سیستم‌کال به فایل‌های فقط‌خواندنی که متعلق به روت بودند بنویسد. جالب این‌جاست که این باگ سال‌ها در کرنل وجود داشت، از حدود سال ۲۰۰۷ تا زمان کشف در سال ۲۰۱۶.

نمونه جدیدتر Dirty Pipe با شماره CVE-2022-0847 بود که مکس کلمن آن را کشف کرد، مشابه Dirty COW از نظر پیامد اما با مکانیزم فنی متفاوت که به رفتار نادرست بافر پایپ در کرنل مربوط می‌شد. سواستفاده از آن به طرز غیرمعمولی ساده بود، برخلاف بسیاری آسیب‌پذیری‌های کرنل که نیاز به شرایط رقابتی دقیق دارند، و همین سادگی باعث شد خیلی سریع کدهای اثبات مفهوم عمومی منتشر شود.

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

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

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

جمع‌بندی این بخش این نیست که کرنل لینوکس بی‌عیب است، هیچ پروژه‌ای به این اندازه نمی‌تواند چنین ادعایی داشته باشد. جمع‌بندی این است که تعداد بالای CVE به تنهایی هیچ معنایی ندارد مگر بدانید این اعداد از کجا می‌آیند و چه بخشی از آن‌ها واقعاً به سناریوی تهدید شما مربوط است. یک دسکتاپ خانگی که پشت NAT نشسته و هیچ سرویس شبکه‌ای گوش نمی‌دهد، عملاً در برابر اکثریت این CVEها که نیاز به دسترسی محلی از قبل موجود دارند مصون است. اما نکته‌ای که این بخش را به بحث آنتی‌ویروس وصل می‌کند این است، یک آسیب‌پذیری ارتقای امتیاز محلی مثل Dirty COW یا Dirty Pipe با امضای فایل اجرایی هیچ ارتباطی ندارد. این‌ها باگ در منطق مدیریت حافظه یا بافر پایپ خود کرنل هستند، چیزی که با اسکن کردن فایل‌های روی دیسک به دنبال یک الگوی بایتی شناخته‌شده اصلاً قابل شناسایی نیست. آنتی‌ویروس دنبال یک فایل مخرب روی دیسک می‌گردد، در حالی که سواستفاده از این نوع آسیب‌پذیری معمولاً از طریق چند فراخوانی سیستم‌کال دقیق و به‌موقع اتفاق می‌افتد، بدون اینکه لزوماً هیچ فایل باینری جدیدی روی سیستم نوشته شود. تنها چیزی که واقعاً جلوی این دسته حمله را می‌گیرد به‌روز نگه داشتن کرنل است، نه یک دیتابیس امضا.

حمله زنجیره تامین یعنی چه

قبل از رفتن سراغ AUR باید دقیق‌تر بگویم منظور از حمله زنجیره تامین چیست، چون این اصطلاح این روزها زیاد شنیده می‌شود ولی همیشه واضح توضیح داده نمی‌شود. در یک حمله معمولی، مهاجم مستقیماً به سیستم قربانی حمله می‌کند، مثلاً با فرستادن یک فایل آلوده یا سواستفاده از یک سرویس آسیب‌پذیر. در حمله زنجیره تامین، مهاجم به‌جای حمله مستقیم به قربانی نهایی، یکی از حلقه‌های واسط بین تولیدکننده نرم‌افزار و مصرف‌کننده نهایی را هدف می‌گیرد، یعنی یک کتابخانه، یک وابستگی، یک پکیج، یک ابزار build، یا حتی خود نگهدارنده یک پروژه. وقتی این حلقه واسط آلوده شود، آلودگی به‌صورت خودکار و از طریق همان مسیر عادی توزیع نرم‌افزار به دست همه کسانی می‌رسد که به آن پکیج یا کتابخانه اعتماد کرده‌اند و آن را نصب یا آپدیت می‌کنند. زیبایی این حمله از دید مهاجم این است که به‌جای هدف قرار دادن یک قربانی، با آلوده کردن یک نقطه واحد در بالای زنجیره، هزاران یا میلیون‌ها قربانی بالقوه را همزمان و بدون هیچ تلاش اضافی هدف می‌گیرد. و مهم‌تر از آن، چون این آلودگی از مسیر رسمی و مورد اعتماد توزیع نرم‌افزار وارد سیستم می‌شود، از نظر هر ابزار امنیتی که بر اساس اعتماد به منبع کار می‌کند کاملاً قانونی به نظر می‌رسد.

بزرگ‌ترین و پیچیده‌ترین نمونه‌ای که این نوع حمله را به‌طور کامل نشان می‌دهد، حادثه backdoor کتابخانه xz-utils با شماره CVE-2024-3094 است که در اوایل سال ۲۰۲۴ کشف شد. یک شخص با نام مستعار Jia Tan طی چند سال به‌عنوان یک مشارکت‌کننده معمولی و صبور در پروژه xz-utils که یک کتابخانه فشرده‌سازی بسیار پرکاربرد و وابستگی غیرمستقیم تقریباً هر توزیع لینوکسی است فعالیت کرد، تا جایی که به تدریج اعتماد نگهدارنده اصلی را جلب کرد و نقش نگهدارنده مشترک گرفت. سپس طی چند تغییر به‌ظاهر بی‌ضرر، کدی به فرآیند build اضافه کرد که در نسخه‌های فشرده‌شده منتشرشده وجود داشت اما در ریپازیتوری گیت به همان شکل آشکار نبود، و این کد در نهایت یک درپشتی در sshd روی سیستم‌هایی که از این نسخه خاص xz استفاده می‌کردند ایجاد می‌کرد که به مهاجم اجازه اجرای کد از راه دور با کلید خاص خودش را می‌داد. این حمله ماه‌ها یا شاید سال‌ها برنامه‌ریزی شده بود و تنها به دلیل شانس محض، یک مهندس در مایکروسافت به نام آندرس فروند که داشت روی کارایی postgres کار می‌کرد و متوجه چند میلی‌ثانیه تاخیر غیرمعمول در اتصال SSH شد، آن را کشف کرد، درست چند هفته قبل از اینکه این نسخه آلوده به توزیع‌های پایدار اصلی برسد.

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

ساختار AUR و جایی که مدل اعتماد شکننده می‌شود

مخزن AUR یا Arch User Repository از نظر ایده یک چیز فوق‌العاده است. هر کسی می‌تواند یک PKGBUILD بنویسد، آن را برای بسته‌بندی هر نرم‌افزاری که در ریپازیتوری رسمی نیست آپلود کند، و بقیه کاربران می‌توانند آن را با یک AUR helper مثل yay یا paru دانلود، build و نصب کنند. اما این آزادی یک قیمت دارد. هیچ‌کس PKGBUILDهای AUR را به‌صورت رسمی بازبینی نمی‌کند. برخلاف ریپازیتوری core یا extra که هر پکیج باید از یک کاربر مورد اعتماد آرچ عبور کند و امضای GPG آن‌ها روی پکیج نهایی قرار بگیرد، هر کاربری با یک حساب AUR می‌تواند هر PKGBUILDی را که دلش می‌خواهد آپلود کند. سیستم رای و کامنت که در صفحه هر پکیج دیده می‌شود ممکن است شبیه یک مکانیزم اعتماد اجتماعی به نظر برسد، اما در عمل هیچ ضمانتی نیست. رای بالا فقط یعنی افراد زیادی این پکیج را نصب کرده‌اند، نه اینکه کسی خط‌به‌خط PKGBUILD را خوانده و تایید کرده. یک پکیج می‌تواند ماه‌ها بدون مشکل کار کند و بعد نگهدارنده‌اش، یا با نیت بد از ابتدا یا بعد از اینکه حسابش هک شده، یک خط مخرب به build() یا به یک اسکریپت نصب اضافه کند و اکثر کاربرانی که با yay -Syu به‌صورت خودکار همه‌چیز را آپدیت می‌کنند هرگز متوجه این تغییر نمی‌شوند.

برای فهمیدن دقیق سطح ریسک باید بدانید makepkg دقیقاً چه کاری انجام می‌دهد. وقتی یک PKGBUILD اجرا می‌شود، تابع build() و تابع package() به‌صورت پیش‌فرض با کاربر عادی و بدون دسترسی روت اجرا می‌شوند، این بخشی از طراحی امنیتی makepkg است. اما این محدودیت به این معنا نیست که خطر از بین رفته. کاربر عادی هنوز به فایل‌های خانگی خودش، کلیدهای SSH، کوکی‌های مرورگر، فایل‌های پیکربندی، و توکن‌های احراز هویت سرویس‌های ابری دسترسی کامل دارد. یک تابع build() مخرب حتی بدون نیاز به روت می‌تواند به راحتی یک درخواست شبکه به یک سرور بیرونی بزند و محتوای دایرکتوری ssh یا کوکی‌های ذخیره‌شده مرورگر را ارسال کند، و از آن‌جایی که این کار در طول یک build عادی که چند ثانیه یا چند دقیقه طول می‌کشد اتفاق می‌افتد، هیچ علامت هشداردهنده‌ای هم روی صفحه ظاهر نمی‌شود.

خطر جدی‌تر جایی است که ماجرا به اسکریپت‌های نصب می‌رسد. یک PKGBUILD می‌تواند فایل .install داشته باشد که شامل توابعی مثل pre_install، post_install، pre_upgrade و post_upgrade است. این توابع بعد از build، در مرحله‌ای که pacman خود پکیج را با sudo pacman -U نصب می‌کند اجرا می‌شوند، یعنی دقیقاً با دسترسی روت. این‌جا دیگر بحث سرقت فایل‌های خانگی نیست، مهاجم می‌تواند هر کاری با سیستم انجام دهد، از نصب یک درپشتی سیستمی گرفته تا اضافه کردن یک کاربر جدید با دسترسی سودو، تا نصب یک روت‌کیت در سطح کرنل. تعداد کمی از کاربران قبل از تایید نصب یک پکیج AUR واقعاً وقت می‌گذارند تا فایل .install را هم بخوانند.

یکی از حوادث واقعی و مستند مربوط به سال ۲۰۱۸ است، وقتی سه پکیج در AUR شامل acroread، balz و minergate کشف شدند که با هدف نصب یک ماینر ارز دیجیتال روی سیستم قربانی آپدیت شده بودند. نگهدارنده جدیدی که به این پکیج‌ها دسترسی گرفته بود یک اسکریپت اضافه کرد که یک باینری از یک آدرس بیرونی دانلود می‌کرد و آن را به‌عنوان بخشی از build اجرا می‌کرد. تیم آرچ خیلی سریع بعد از گزارش کاربران این پکیج‌ها را از AUR حذف کرد، اما این حادثه نشان داد مسیر از یک پکیج به‌ظاهر بی‌خطر تا اجرای کد دلخواه چقدر کوتاه است.

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

مکانیزم AUR helperها هم خودش بخشی از مسئله است، نه به این دلیل که خود ابزارها بد طراحی شده‌اند بلکه به این دلیل که عادت استفاده از آن‌ها این ریسک را پنهان می‌کند. وقتی کاربر با yay -Syu یا paru -Syu همه‌چیز اعم از ریپازیتوری رسمی و AUR را در یک دستور آپدیت می‌کند، این دو دسته پکیج از نظر تجربه کاربری کاملاً یکسان به نظر می‌رسند در حالی که از نظر مدل اعتماد زمین تا آسمان فرق دارند. بیشتر AUR helperها البته قبل از build یک تفاوت‌نمای تغییرات PKGBUILD نسبت به نسخه قبلی نمایش می‌دهند، اما تجربه واقعی این است که وقتی کاربر ده‌ها پکیج را همزمان آپدیت می‌کند، این تفاوت‌نماها به سرعت اسکرول می‌شوند و عملاً کسی خط‌به‌خط نمی‌خواندشان. عادت استفاده از گزینه بدون تایید که خیلی از کاربران برای راحتی در اسکریپت‌های خودکار به کار می‌برند، این آخرین لایه بازبینی انسانی را هم کاملاً حذف می‌کند.

یک تغییر مثبت در سال‌های اخیر در makepkg، پشتیبانی از build در یک محیط ایزوله با استفاده از bubblewrap بود. این قابلیت که به‌صورت اختیاری قابل فعال‌سازی است، فرآیند build را با دسترسی محدود به فایل‌سیستم و شبکه اجرا می‌کند، اما هنوز به‌صورت پیش‌فرض برای همه فعال نیست، و مهم‌تر اینکه این محیط ایزوله فقط مرحله build را می‌پوشاند، نه اسکریپت‌های نصب که بعداً با روت اجرا می‌شوند.

حالا آنتی‌ویروس در برابر همه این‌ها چه کاری از دستش برمی‌آید؟

پاسخ کوتاه: هیچ کاری. یک تابع build() مخرب که کلیدهای SSH را می‌خواند و به یک سرور بیرونی می‌فرستد، هیچ فایل باینری شناخته‌شده‌ای روی دیسک نمی‌نویسد که در دیتابیس امضا وجود داشته باشد. این یک اسکریپت bash یا یک تابع makepkg است که کاملاً قانونی و متن‌باز به نظر می‌رسد، دقیقاً همان چیزی که هزاران PKGBUILD بی‌خطر دیگر هم دارند. یک اسکریپت نصب که با روت اجرا می‌شود و یک کاربر جدید با دسترسی سودو اضافه می‌کند، از نظر آنتی‌ویروس یک عملیات سیستمی عادی است، نه یک الگوی بدافزار شناخته‌شده. مشکل زنجیره تامین یک مشکل اعتماد است، نه یک مشکل امضا. کد مخرب لباس کد قانونی را پوشیده و از همان مسیری وارد سیستم می‌شود که هزار پکیج بی‌خطر دیگر هم وارد می‌شوند، یعنی از طریق makepkg و pacman، دقیقاً همان ابزارهایی که هر آنتی‌ویروسی به آن‌ها اعتماد کامل دارد چون بخشی از خود سیستم‌عامل هستند.

راه‌حل واقعی، نه از جنس نصب یک نرم‌افزار امنیتی جداگانه است و نه از جنس اعتماد کورکورانه به این‌که چون لینوکس هستیم پس امنیم. راه‌حل کرنل، به‌روزرسانی منظم و نزدیک ماندن به بالادست است. راه‌حل AUR، خواندن PKGBUILD و اسکریپت‌های نصب قبل از هر نصب، نگاه کردن به تاریخچه نگهدارنده، ترجیح دادن ریپازیتوری رسمی به معادل AUR وقتی هر دو موجودند، و کنار گذاشتن عادت آپدیت کورکورانه و بدون تایید است. امنیت گنو/لینوکس از جنس آگاهی و مدل باز بودن است، نه از جنس یک ابزار که پشت سرتان بایستد و به‌جایتان تصمیم بگیرد. آنتی‌ویروس برای مقابله با تهدیدی ساخته شده که این‌جا اصلاً حاکم نیست، و برای تهدیدی که واقعاً حاکم است هیچ ابزاری در چنته ندارد.