تغییرات sudo-rs در Ubuntu 26.04 و فایل sudoers
در Ubuntu 26.04 استفاده از sudo-rs به جای sudo پیشفرض شده است. این تغییر باعث میشود wildcard در آرگومانهای فایل sudoers دیگر کار نکند. راهکار جایگزین را اینجا ببینید.
تغییرات sudo-rs در Ubuntu
نسخه Ubuntu 26.04 LTS بهصورت پیشفرض از sudo-rs به جای sudo استفاده میکند، بنابراین دستور sudo در یک سرور تازه، پیادهسازی مبتنی بر Rust را به جای برنامه اصلی C اجرا میکند. اکثر فایلهای sudoers بدون تغییر به کار خود ادامه میدهند. قانونی که دچار اختلال میشود، قانونی است که در آرگومانهای یک دستور از wildcard استفاده میکند، زیرا sudo-rs الگوهای glob را با متن آرگومانها تطبیق نمیدهد.
نسخه Ubuntu 25.10 اولین نسخهای بود که این تغییر را اعمال کرد و Ubuntu 26.04 LTS نیز آن را حفظ کرده است. نسخه Ubuntu 24.04 LTS تحت تأثیر این تغییر قرار نمیگیرد، زیرا تا زمانی که sudo-rs را بهصورت دستی نصب نکنید، همچنان از sudo اصلی استفاده میکند. اهمیت این موضوع زمانی مشخص میشود که شما از Ubuntu 24.04 به 26.04 ارتقا دهید، یا زمانی که یک سرور جدید با نسخه جدیدتر راهاندازی کنید. اگر از نسخههای میاندورهای (interim) نیز استفاده میکنید، مطلب تفاوت نسخههای LTS و میاندورهای Ubuntu در سرور توضیح میدهد که کدام ماشین زودتر با چنین تغییری مواجه میشود.
بررسی اینکه سرور شما واقعاً از کدام sudo استفاده میکند
این موضوع را از روی شماره نسخه حدس نزنید. از خود ماشین بپرسید.
sudo --version
update-alternatives --config sudo
dpkg -l 'sudo*'به sudo --version روی سیستم خودتان بیش از هر جدول نسخهای در اینترنت، از جمله این صفحه، اعتماد کنید. update-alternatives --config sudo نیمه دیگر پاسخ است: این دستور تمام ارائهدهندگان نصبشده /usr/bin/sudo را فهرست کرده و گزینه انتخابشده را مشخص میکند. نصب بودن یک بسته به معنای انتخاب شدن آن نیست، بنابراین به جای فهرست بستهها، وضعیت انتخاب را بخوانید.
هر دو پیادهسازی در طول دوره انتقال بستهبندی میشوند. نسخه Rust با نام sudo-rs شناخته میشود که در نسخه 26.04 تا آگوست 2026 در نسخه 0.2.13 قرار دارد. نسخه اصلی که توسط Todd C. Miller نگهداری میشود، همچنان بسته sudo است؛ تغییری که رخ داده این است که برنامههای آن دارای پسوند .ws هستند تا هر دو بتوانند همزمان نصب باشند: /usr/bin/sudo.ws و /usr/bin/visudo.ws، در کنار cvtsudoers.ws و sudoreplay.ws. طبق بررسی انجامشده روی آرشیو 26.04 در سپتامبر 2026: dpkg -L sudo باینریهای دارای پسوند را فهرست میکند و sudo-rs فایل /usr/bin/sudo-rs را در کنار آنها ارائه میدهد.
چرا اوبونتو به سراغ sudo-rs رفت
برنامه sudo دارای قابلیت setuid root است. هر کاربری در سیستم میتواند آن را اجرا کند و برنامه با دسترسی کامل شروع به کار میکند؛ بنابراین یک باگ حافظه در آن، یک آسیبپذیری برای دسترسی root محلی محسوب میشود. مورد CVE-2021-3156 دقیقاً همین بود: یک سرریز بافر heap که توسط هر کاربر محلی قابل بهرهبرداری بود و حدود 10 سال در کدهای منتشرشده باقی مانده بود. زبان Rust این دسته از باگها را در زمان کامپایل شناسایی میکند و این تمام استدلال برای بازنویسی آن است.
دلیل دوم، دامنهٔ عملکرد است که مستقیماً بر پیکربندی شما تأثیر میگذارد. برنامه sudo اصلی طی سه دهه، مجموعه ویژگیهای گستردهای را جمعآوری کرده است و هر ویژگی به معنای کدهای بیشتری است که با دسترسی root اجرا میشوند. برنامه sudo-rs عمداً زیرمجموعهای از این قابلیتها را پیادهسازی کرده است. هر چیزی که نویسندگان آن، خاص یا ذاتاً مخرب تشخیص دادهاند، حذف شده است؛ بنابراین ممکن است یک دستور در فایل sudoers که سالها کار میکرد، اکنون وجود نداشته باشد. قانون wildcard شما یکی از همین موارد است.
امنیت حافظه یک دسته از باگها را حذف میکند، اما به این معنا نیست که برنامه بدون باگ است. sudo-rs نیز از زمانی که به گزینه پیشفرض تبدیل شده، اصلاحات امنیتی خاص خود را منتشر کرده است. آن را مانند هر نرمافزار دیگری بهروزرسانی (Patch) کنید.
کدام قوانین sudoers همچنان کار میکنند
این فایل همان فایل قبلی است. sudo-rs فایل /etc/sudoers و فایلهای موجود در /etc/sudoers.d/ را میخواند و موارد معمولی که یک مدیر سرور مینویسد، پشتیبانی میشوند:
deploy ALL=(ALL:ALL) ALLو فرمهای گروهی مانند%sudo ALL=(ALL:ALL) ALL- تگهای
NOPASSWD:وPASSWD: User_Alias،Runas_Alias،Host_AliasوCmnd_Alias- دستوری با لیست آرگومانهای دقیق، برای مثال
/usr/bin/systemctl restart app-api - دستوری که به
""ختم میشود، که اجازه اجرای دستور را فقط بدون هیچ آرگومانی میدهد - دستوری که با
*به عنوان آخرین آرگومان همراه است، که اجازه هرگونه آرگومان اضافی را میدهد - مسیر دایرکتوری که به
/ختم میشود، که اجازه اجرای هر دستوری در آن دایرکتوری را میدهد !برای حذف یک دستور از لیست- زیرمجموعه مفیدی از
Defaults، شاملsecure_path،env_keep،env_check،timestamp_timeout،passwd_tries،editor،umask،targetpw،rootpwوuse_pty
دو مورد پیشفرض رفتار متفاوتی دارند و ممکن است باعث سردرگمی شوند. env_reset در sudo-rs قابل غیرفعالسازی نیست: این قابلیت همیشه فعال است. use_pty بهصورت پیشفرض فعال است، بنابراین دستور در pseudo-terminal اختصاصی خود اجرا میشود.
چرا قانون wildcard در sudoers دیگر مطابقت ندارد
استفاده از wildcardها هنوز در یک بخش مجاز است: نام فایلِ دستور. قانونی مانند %ops ALL = /sbin/fsck* همچنان اجازه اجرای sudo fsck و sudo fsck_exfat را میدهد، زیرا * بخشی از مسیری است که با فایلسیستم تطبیق داده میشود.
در لیست آرگومانها، sudo-rs تنها دو فرم خاص را میپذیرد و هیچکدام از آنها الگو (pattern) نیستند. "" به معنای بدون آرگومان است. یک * در انتها به معنای هرگونه آرگومان اضافی در ادامه است. هر آرگومان دیگری به صورت متن دقیق (literal) مقایسه میشود. بنابراین %ops ALL = /sbin/service ntp * مشکلی ندارد، زیرا ntp یک متن دقیق است و * در انتها قرار دارد. با این حال، قانونی مانند نمونه زیر، هیچکدام از دسترسیهای مورد نظر شما را اعطا نمیکند:
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart app-*app-* یک الگو در میان یک آرگومان است. sudo-rs آن را بسط نمیدهد، بنابراین این قانون شامل systemctl restart app-api نمیشود و sudo اجرای دستور را رد میکند. دو دستور وجود دارند که حقیقت را درباره هر قانونی روی سرور شما میگویند: sudo -l -U deploy که با دسترسی root اجرا میشود و نشان میدهد آن حساب کاربری واقعاً چه دستوراتی را میتواند اجرا کند، و sudo visudo -c که به شما میگوید آیا فایل اصلاً قابل تجزیه (parse) هست یا خیر. پیش از آنکه بهصورت تصادفی شروع به ویرایش کنید، این دستورات را اجرا کنید.
قانون wildcard همیشه یک حفره امنیتی بوده است
در نسخه اصلی sudo، آرگومانهایی که تایپ میکنید به یک رشته واحد تبدیل شده و با استفاده از glob با رشته آرگومان موجود در قانون تطبیق داده میشوند. یک glob با فضای خالی (whitespace) نیز مطابقت دارد. این همان نکتهای است که تقریباً همه از آن غافل میشوند.
مستندات sudo-rs واضحترین نمونه را ارائه میدهد. یک قانون به صورت /bin/rm *.txt، اجرای sudo rm -rf /home .txt را نیز مجاز میکند، زیرا آن * تمام -rf /home را در بر میگیرد و رشته نهایی همچنان به .txt ختم میشود. این قانون به ظاهر «فقط فایلهای متنی» را مجاز میداند، اما در عمل به معنای «هر آرگومانی، به شرطی که خط به .txt ختم شود» است.
همین موضوع در مورد مثال systemctl نیز صدق میکند. از آنجا که آرگومانها به عنوان یک رشته واحد مقایسه میشوند، الگوی انتهایی با هر چیزی که پس از آن اضافه کنید نیز مطابقت دارد؛ بنابراین restart app-* شامل restart app-api به علاوه هر آرگومان دیگری است که فراخواننده اضافه کند. وجود یک الگو در داخل یک آرگومان، آرگومانهای اطراف آن را لو میدهد و قدرت یک دستور دقیقاً در آرگومانهای آن نهفته است. sudo-rs به جای تلاش برای ایمنسازی این ساختار، آن را رد میکند، زیرا هیچ شکل کلی ایمنی برای آن وجود ندارد.
جایگزینی wildcard با یک لیست دستور صریح
بیشتر قوانین wildcard به این دلیل وجود دارند که کسی نمیخواسته چهار خط را تایپ کند. آن چهار خط را تایپ کنید.
Cmnd_Alias APP_RESTART = /usr/bin/systemctl restart app-api, /usr/bin/systemctl restart app-worker
Cmnd_Alias APP_STATUS = /usr/bin/systemctl status app-api, /usr/bin/systemctl status app-worker
deploy ALL=(root) NOPASSWD: APP_RESTART, APP_STATUSمسیر را بهدرستی وارد کنید. قانونی که به /bin/systemctl اشاره دارد در سیستمی که فایل اجرایی آن در /usr/bin/systemctl قرار دارد، هرگز مطابقت پیدا نمیکند و خطای حاصل، مشابه مشکل مجوز (permissions) به نظر میرسد. با استفاده از command -v systemctl موضوع را تأیید کنید و خروجی آن را کپی کنید.
قانون را بهجای /etc/sudoers در یک فایل drop-in مجزا قرار دهید تا ارتقای پکیجها با ویرایش شما تداخلی ایجاد نکند:
sudo visudo -f /etc/sudoers.d/90-deploy
sudo visudo -c
sudo -l -U deployنام فایل را بدون نقطه و بدون tilde در انتها انتخاب کنید. نسخه اصلی sudo فایلهایی را که نامشان حاوی نقطه است در sudoers.d نادیده میگیرد، بنابراین 90-deploy.conf یک نمونه کلاسیک از عملیات بیاثر (no-op) است و رعایت این قرارداد هزینهای ندارد.
استفاده از یک wrapper با مالکیت root برای لیستهای طولانی
هنگامی که مجموعه دستورات مجاز برای لیست کردن بیش از حد طولانی است، تصمیمگیری را از فایل sudoers خارج کرده و به یک برنامه کوچک که مالکیت آن با root است، منتقل کنید.
sudo tee /usr/local/sbin/app-restart >/dev/null <<'EOF'
#!/bin/sh
set -eu
case "${1:-}" in
app-api|app-worker) ;;
*) echo "app-restart: not allowed: ${1:-}" >&2; exit 1 ;;
esac
exec /usr/bin/systemctl restart "$1"
EOF
sudo chown root:root /usr/local/sbin/app-restart
sudo chmod 0755 /usr/local/sbin/app-restart
ls -l /usr/local/sbin/app-restartسپس در فایل sudoers تنها یک دستور را مشخص کنید:
deploy ALL=(root) NOPASSWD: /usr/local/sbin/app-restart *استفاده از * در انتهای دستور در اینجا قابلقبول است، زیرا این اسکریپت است که تصمیم میگیرد چه چیزی مجاز باشد، نه sudo. این موضوع تنها زمانی صادق است که اسکریپت متعلق به root باشد و هیچ کاربر دیگری اجازه نوشتن در آن را نداشته باشد. اگر deploy بتواند در فایل بنویسد، deploy میتواند محتوای آن را جایگزین کرده و هر دستوری را با دسترسی root اجرا کند؛ که این وضعیت از قانون wildcard که حذف کردهاید، خطرناکتر است. وضعیت مجوزها را با ls -l بررسی کنید و اگر خروجی برای شما واضح نیست، خواندن رشته مجوز drwxr-xr-x تنها پنج دقیقه زمان برای یادگیری نیاز دارد. همین قانون در مورد دایرکتوری نیز صدق میکند: /usr/local/sbin نباید توسط آن حساب کاربری قابلنوشتن باشد، زیرا دایرکتوری قابلنوشتن به این معنی است که فایل میتواند بهطور کامل جایگزین شود.
به جای استفاده از قانون sudo، یک حساب کاربری اختصاصی برای وظیفه ایجاد کنید
پرسش بهتر اغلب این است که چرا دستور اصلاً به دسترسی root نیاز دارد. سرویسی که با حساب کاربری اختصاصی خود اجرا میشود، توسط همان کاربر قابل مدیریت است و نیازی به خط sudoers ندارد. برای unitهای سیستم، systemd این تصمیم را به polkit واگذار میکند، بنابراین یک قانون میتواند یک unit خاص و یک اپراتور مشخص را تعیین کند:
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "app-api.service" &&
subject.user == "deploy") {
return polkit.Result.YES;
}
});آن را با نام /etc/polkit-1/rules.d/50-app-api.rules ذخیره کنید تا deploy بتواند بدون نیاز به sudo، دستور systemctl restart app-api را اجرا کند. این مورد را دقیقاً در همان بستری که قرار است از آن استفاده شود تست کنید، زیرا قانونی که در نشست SSH شما کار میکند، پیش از آنکه به آن تکیه کنید، باید از طریق cron نیز تأیید شود. در هر صورت، حسابی که وظیفه را انجام میدهد باید صرفاً برای همان کار وجود داشته باشد؛ این همان استدلالی است که پشت حسابهای کاربری با حداقل دسترسی روی یک VPS نهفته است.
سایر مواردی که در sudo-rs حذف شدهاند
sudo -E پیادهسازی نشده است. متغیرهایی که نیاز دارید را با Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY" نامگذاری کنید و به یاد داشته باشید که env_reset همیشه فعال است، بنابراین هر چیزی که حفظ نشود، پاک خواهد شد.
ذخیرهسازی مرکزی sudoers در LDAP حذف شده است. sudoers.ldap و cvtsudoers پیادهسازی نشدهاند و بسته sudo-ldap در نسخه 26.04 حذف شده است. احراز هویت LDAP از طریق PAM یا SSSD همچنان کار میکند. بخش مربوط به سیاستهای مبتنی بر دایرکتوری (policy-in-a-directory) خارج از محدوده این پروژه است.
قابلیت INTERCEPT که تلاش میکرد از shell escape در دستورات مجاز جلوگیری کند، پیادهسازی نشده است. این قابلیت در برابر یک کاربر مصمم هرگز کارایی نداشت. اگر قانونی به کسی اجازه دهد یک ویرایشگر یا مفسر را با دسترسی root اجرا کند، او دسترسی root را در اختیار دارد و هیچ گزینه sudo نمیتواند این موضوع را تغییر دهد.
ضبط نشست (Session recording) پیادهسازی نشده است، بنابراین هیچ I/O log و sudoreplay وجود ندارد. ثبت وقایع (Logging) فقط به syslog ارسال میشود و هیچ گزینه logfile برای هدایت آن به جای دیگر وجود ندارد، بنابراین پیامهای sudo در هر جایی که سیستم شما در حال حاضر syslog را ارسال میکند، ذخیره خواهند شد.
آیا باید به sudo.ws برگردید؟
شما میتوانید این کار را انجام دهید و در طول چرخه 26.04، نسخه اصلی دقیقاً به همین دلیل در بستهها باقی میماند.
sudo apt install sudo
update-alternatives --config sudo
sudo update-alternatives --set sudo /usr/bin/sudo.wsمسیرهای دقیق را از خروجی --config کپی کنید و از این صفحه کپی نکنید، زیرا این همان فهرستی است که سیستم شما میپذیرد. بازگشت به sudo-rs در آینده به معنای تنظیم جایگزین (alternative) روی مسیر باینری sudo-rs از همان فهرست است.
پیش از آنکه تغییری در sudo ایجاد کنید، یک نشست SSH دوم را باز نگه دارید که در آن لاگین کردهاید و فعال است. یک فایل sudoers که در تجزیه (parse) آن خطا رخ دهد، یا یک جایگزین که به باینری نصبنشده اشاره کند، میتواند شما را بدون راهی برای دسترسی به root در یک سرور از راه دور رها کند. این عادت باید در کنار سایر کارهای شما در ده دقیقه اول در یک VPS جدید قرار بگیرد.
بازگشت به حالت قبل را به عنوان یک مهلت در نظر بگیرید، نه یک راه حل. این کار به شما یک هفته فرصت میدهد تا قوانین را به درستی بازنویسی کنید؛ و این بازنویسی به خودی خود ارزشمند است، زیرا هر قانون wildcard که حذف میکنید، دسترسیهای بیش از حدِ پیشبینیشده توسط نویسندهاش را محدود میکند.
FAQ
چرا قانون wildcard در sudoers من روی Ubuntu 26.04 از کار افتاد؟
زیرا Ubuntu 26.04 LTS از sudo-rs به عنوان sudo پیشفرض استفاده میکند و sudo-rs الگوهای wildcard را در آرگومانهای یک دستور تطبیق نمیدهد. این ابزار اجازه میدهد از wildcard در نام فایل دستور، "" برای عدم وجود آرگومان، و یک * تکی به عنوان آخرین آرگومان استفاده کنید. قانونی مانند /usr/bin/systemctl restart app-* یک الگو را در میان یک آرگومان قرار میدهد، بنابراین هیچ دسترسیای اعطا نمیکند و دستور رد میشود. برای مشاهده دسترسیهای واقعی حساب کاربری، دستور sudo -l -U deploy را با دسترسی root اجرا کنید، سپس قانون را با دستورات دقیق یا یک اسکریپت wrapper که مالکیت آن با root است، جایگزین کنید.
چگونه در Ubuntu 26.04 به sudo اصلی برگردم؟
نسخه اصلی در بسته sudo عرضه میشود که فایلهای اجرایی آن دارای پسوند .ws هستند. آن را با sudo apt install sudo نصب کنید، سپس با استفاده از sudo update-alternatives --set sudo /usr/bin/sudo.ws، جایگزین (alternative) را به سمت آن هدایت کنید. ابتدا update-alternatives --config sudo را اجرا کنید تا مسیرهای دقیق ارائهشده توسط سیستم خود را ببینید؛ همچنین هنگام تغییر، یک نشست SSH دوم باز نگه دارید. این کار sudo-ldap را بازنمیگرداند، چرا که صرفنظر از پیادهسازی انتخابی شما، این قابلیت از نسخه 26.04 حذف شده است.
آیا sudo-rs همان فایل /etc/sudoers را میخواند؟
بله. sudo-rs فایل /etc/sudoers و فایلهای موجود در /etc/sudoers.d/ را با همان سینتکس برای کاربران، گروهها، aliasها، مشخصات run-as و تگ NOPASSWD میخواند. این ابزار زیرمجموعهای از زبان sudoers را پیادهسازی میکند، بنابراین تفاوتها به صورت ساختارهای حذفشده نمایان میشوند، نه ساختارهایی که رفتار متفاوتی دارند. فایل را با sudo visudo ویرایش کنید و پیش از بستن نشست خود، آن را با sudo visudo -c تایید کنید.
چه چیزی جایگزین sudo -E در sudo-rs شده است؟
قابلیت sudo -E پیادهسازی نشده است و در sudo اصلی نیز استفاده از آن توصیه نمیشد، زیرا در اختیار قرار دادن محیطی که فراخواننده کنترل میکند به یک پردازش root، روشی شناختهشده برای تغییر رفتار آن پردازش است. در عوض، متغیرهایی که واقعاً نیاز دارید را در sudoers با خطی مانند Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY" نام ببرید. قابلیت env_reset در sudo-rs همیشه فعال است و نمیتوان آن را غیرفعال کرد، بنابراین هر متغیری که حفظ نکنید، پاکسازی میشود.