لینک کوتاه مطلب : https://hsgar.com/?p=5982

مشکل با Symbolic Links در لینوکس

در کنفرانس sambaXP 2022، جرمی آلیسون یک سخنرانی با عنوان “API فایل سیستم یونیکس عمیقاً خراب است: در مورد آن چه باید کرد؟” ارائه کرد.  او صحبت خود را با مشکلاتی که پیوندهای نمادین (“symlink”) برای توسعه دهندگان برنامه ایجاد می کنند آغاز کرد، سپس در مورد اینکه چگونه راه حل های مشکلات ایجاد شده توسط symlink ها منجر به افزایش قابل توجهی در پیچیدگی API های درگیر در کار با مسیرها می شود، بحث کرد.
آلیسون توضیح داد که پیوندهای سخت اولین “اضافه شده جالب” به API اصلی سیستم فایل یونیکس بودند. با این حال، برخلاف سیملینک ها خطرناک نیستند و در واقع استفاده از آنها آسان است. پیوند سخت به سادگی ارتباط بین ورودی دایرکتوری و inode فایل (یا دایرکتوری) است که آن ورودی به آن اشاره دارد. سیستم‌های یونیکس اجازه می‌دهند چندین پیوند به هر فایلی وجود داشته باشند، اما نیاز دارند که ورودی‌های inode و دایرکتوری همه در یک سیستم فایل قرار داشته باشند.

در مقابل، Symlinks حاوی مسیر دیگری به عنوان داده است، و زمانی که سیستم open() یا ()chown   را فراخوانی می کند  هسته به طور شفاف روی فایل در آن مسیر عمل می کند. که در سیملینک فراخوانی می شوند. این ویژگی به ظاهر بی ضرر منجر به اضافه شدن مقادیر باورنکردنی پیچیدگی در تلاش برای برآورده ساختن نیازهای برنامه هایی شد که باید بدانند آیا یک نام مسیر حاوی یک پیوند نمادین است یا خیر. چنین برنامه هایی شامل برنامه های آرشیوی مانند تار، برنامه های همگام سازی و انتقال فایل مانند rsync، سرورهای سیستم فایل شبکه مانند Samba و بسیاری دیگر که در نتیجه عدم توجه کافی به پیوندهای علامت در نام مسیرها از مشکلات امنیتی رنج می برند.

انواع مشکلات امنیتی ناشی از پیوندهای نمادین را می توان در الف مشاهده کرد جستجوی ورودی های CVE، که در زمان اجرای آلیسون 1361 نتیجه به دست آورد. این موارد شامل آسیب‌پذیری‌هایی است که افشای اطلاعات، افزایش امتیازات، و دستکاری دلخواه فایل از جمله حذف، در میان حملات دیگر را تسهیل می‌کند. بدون بحث در مورد CVE خاص، او نمونه‌ای از نوع مشکل امنیتی را که می‌تواند از آسیب‌پذیری‌های مرتبط با symlink ناشی شود، ارائه کرد.

برنامه ای که به صورت روت اجرا می شود ممکن است سعی کند آن را بررسی کند
/data/mydir قبل از باز کردن فایل یک دایرکتوری معمولی است (نه یک پیوند نمادین). /data/mydir/passwd. در فاصله زمانی که برنامه دایرکتوری را بررسی می کند و فایل باز می شود، یک مهاجم می تواند جایگزین آن شود mydir دایرکتوری با یک پیوند نمادین به /و غیره، و اکنون فایل باز شده، به طور غیرمنتظره ای، /etc/passwd. این یک نوع شرایط نژادی است که به عنوان a زمان بررسی تا زمان استفاده (TOCTOU)
نژاد

پیوندهای نمادین و پیچیدگی

آلیسون نظریه‌پردازی کرد، پیوندهای نمادین ایجاد شده‌اند، زیرا پیوندهای سخت به پیوند در یک سیستم فایل محدود می‌شوند، بنابراین اگر مدیری بخواهد بدون تغییر مسیرهای داده‌های کاربران، رسانه‌های ذخیره‌سازی جدیدی را اضافه کند، تنها پیوندهای نمادین (که فاقد این محدودیت هستند) ایجاد می‌شوند. او تبلیغی را برای 4.2BSD نقل کرد که تبلیغ می کرد، “این ویژگی کاربر را از محدودیت های سلسله مراتب سختی که یک ساختار درختی تحمیل می کند آزاد می کند. این انعطاف پذیری برای مدیریت خوب فضای نام ضروری است.”

افزودن پیوندهای نمادین منجر به lstat()

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

گزینه ای به باز کن() تماس سیستمی، O_NOFOLLOW، همان مشکل را نشان می دهد lstat(). O_NOFOLLOW به فراخوانی سیستم دستور می دهد تا با شکست مواجه شود ELOOP اگر آخرین مؤلفه در نام مسیر یک پیوند نمادین باشد، اما آن فقط آخرین جزء را بررسی می کند. را
realpath()

تابع کتابخانه C، پیوندهای نمادین را در یک مسیر دنبال می‌کند و یک نام مسیر مطلق و متعارف تولید می‌کند که برنامه می‌تواند سپس با نسخه اصلی مقایسه کند. آلیسون این را راه حلی جذاب اما نادرست برای مشکل توصیف کرد. فرآیند دیگری می تواند در بین زمان تغییر ایجاد کند realpath() فراخوانی می شود و تابع دیگری برای دستکاری فایل به روشی استفاده می شود. به عبارت دیگر، همان مسابقه TOCTOU در اینجا صدق می کند.

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

اما آلیسون به نقص این تکنیک نیز اشاره کرد. “شما نمی توانید یک فهرست جدید ایجاد کنید باز کن()، نمی توانید یک فایل را حذف کنید، پیوند یک فایل را لغو کنید یا یک دایرکتوری را با یک حذف کنید باز کن() فراخوانی کنید.” بنابراین، توابع بیشتری به دنبال الگوی openat() باید ایجاد می شد:
mkdirat()،
linkat()،
unlinkat()،
renameat()، و بیشتر. برخی هنوز مفقود هستند، مانند
getxattrat() و setxattrat(). بعضی ها مثل
fchownat()

و faccessat()، از الگوی تمیز پیروی نکنید.

آلیسون حرفی نزد: “بنابراین API سیستم فایل POSIX تمیز و زیبای ما دیگر خیلی تمیز و زیبا به نظر نمی رسد… نام مسیرها به عنوان یک مفهوم اکنون در POSIX کاملاً شکسته شده اند.” حداقل تا حدودی می‌توان هر گونه تلخی را به تلاش‌های آلیسون با راه طولانی برای رفع CVE-2021-20316 در سامبا نسبت داد.

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

راه حل ها

سپس آلیسون استفاده از آن را توضیح داد O_PATH پرچم به
باز کن()، که یک توصیفگر فایل را برمی گرداند که فقط برای انتقال به فایل مفید است *at() سیستم به عنوان dirfd
بحث و جدل. متأسفانه برای Samba، توصیفگرهای فایل با باز می شوند
O_PATH نمی توان برای خواندن یا نوشتن ویژگی های توسعه یافته استفاده کرد. او راه‌حلی پیدا کرد که با یک قطعه کد نشان داد که آن را به عنوان «یکی از زیباترین هک‌هایی که تا به حال دیده‌ام، آنقدر زشت است که می‌خواهید استفراغ کنید، اما شگفت‌انگیز است».

    int fd = openat(dirfd, "file", O_PATH|O_NOFOLLOW);
    sprintf(buf, "/proc/self/fd/%d", fd);
    getxattr(buf, ea_name, value, size);

مطالب از /proc/self/fd پیوندهای نمادینی هستند که نشان دهنده هر توصیفگر فایلی هستند که فرآیند باز است. آلیسون کد را توضیح داد: “اگر در بافر چاپ کنید”/proc/self/fd/و سپس شماره توصیفگری که به تازگی از O_PATH دریافت کرده اید، می توانید آن را به آن ارسال کنید
getxattr() یا setxattr() به عنوان یک مسیر، و نمی‌توان آن را با سیم‌لینک مسابقه داد.» او مطمئن نبود که این کد را به توسعه‌دهندگان اندروید یا Red Hat نسبت دهد، اما استفاده مشابهی از /proc/self/fd/ را می توان در پیدا کرد باز کن()
صفحه مرد

آلیسون نکته اصلی سخنرانی خود را تکرار کرد: “مفهوم مسیر نام ها در POSIX، به طور کامل غیرقابل استفاده است. برای یک برنامه کاربردی غیر پیش پا افتاده، برای یک شخص معمولی که روی POSIX کد می نویسد، شما مسابقه های سیم لینک را در کد خود خواهید داشت.”

نمونه‌هایی از CVE (از زمان ثابت) ارائه شد، از جمله یکی در
کتابخانه استاندارد Rust، که در اینجا به طور گسترده مورد بحث قرار گرفت. در چند دقیقه آخر صحبت، آلیسون به چندین راه حل پیشنهادی ارائه شده توسط خوانندگان LWN، از جمله راه حل ویژه اشاره کرد. prctl() تماس و محدودیت در زمانی که پیوندهای نمادین غیر ریشه دنبال می شوند. او گفت که MOUNT_NOSYMFOLLOW گزینه mount، که به سادگی دنبال کردن پیوندهای نمادین در یک سیستم فایل را ممنوع می کند، راه حل ترجیحی او است: “این عالی است. دقیقاً همان کاری را انجام می دهد که ما نیاز داریم.” صحبت آلیسون در این مورد به پایان رسید.

در حالی که مطمئناً ممنوع کردن پیوندهای نمادین به نام پاکسازی API POSIX مطلوب به نظر می رسد، آنها یک ابزار مدیریت سیستم هستند که اغلب استفاده می شود. چندین “مدیر پیوند نمادین” محبوب وجود دارد. گنو استوبرای مثال، راهی برای مدیران فراهم می کند تا برنامه ها را در یک سلسله مراتب فهرست جدید نصب کنند، مانند
/usr/local/stow/packagename-version/و سپس جنگل هایی از پیوندهای نمادین را ایجاد کنید /usr/local/bin/example به
/usr/local/stow/packagename-version/bin/example، با استفاده از حداقل تعداد پیوندهای نمادین لازم. این امکان “حذف” یک بسته را به سادگی با حذف پیوندهای نمادین به کمک می‌دهد انبار -D.

را /etc/alternatives سیستم ایجاد شده توسط دبیان به مدیران اجازه می دهد تا بین بسته های قابل تعویض به روشی مشابه بدون اجبار حذف یا نصب مجدد هر بسته جابجا شوند. در یک روش مشابه، نیکس و Guix توزیع ها به شدت از پیوندهای نمادین استفاده می کنند – نمایه Guix از درختی از پیوندهای نمادین به بسته های نصب شده در داخل تشکیل شده است. /gnu/store/، جابجایی بین ترکیب های گروه بندی شده از نسخه های خاص بسته ها را آسان می کند.

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

لینک منبع

ارسال یک پاسخ

آدرس ایمیل شما منتشر نخواهد شد.