Product SiteDocumentation Site

14.5. مقدمه‌ای بر SELinux

14.5.1. اصول

SELinux که مخفف عبارت Security Enhanced Linux است، یک سیستم Mandatory Access Control مبتنی بر رابط LSM یا Linux Security Modules در لینوکس است. در عمل، کرنل قبل از هر فراخوانی سیستمی از SELinux پرس و جو می‌کند آیا فرآیند جاری مجاز به اجرای عملیات فوق‌الذکر می‌باشد یا خیر.
SELinux از مجموعه قوانین - که بنام policy شناخته می‌شوند - استفاده کرده تا عملیات را مجاز یا ممنوع کند. این قوانین به سختی ایجاد می‌شوند. خوشبختانه، دو خط مشی استاندارد targeted و strict فراهم شده‌اند که طیف گسترده‌ای از کار را بر عهده می‌گیرند.
با استفاده از SELinux، مدیریت دسترسی به شیوه‌ای کاملا متفاوت با سیستم‌های سنتی یونیکس انجام می‌شود. دسترسی یک فرآیند کاملا مبتنی بر زمینه امنیتی آن خواهد بود. این زمینه توسط شناسه کاربری که فرآیند را آغاز کرده است تعریف می‌شود، همراه با نقش و دامنه که کاربر در آن زمان داشته است. این حقوق کاملا مبتنی بر دامنه کار هستند، اما انتقال بین دامنه‌ها توسط نقش‌های کاربری کنترل می‌شود. در نهایت، انتقال‌های احتمالی بین چند نقش مبتنی بر شناسه کاربری خواهد بود.
زمینه‌های امنیتی و کاربران یونیکس

شكل 14.1. زمینه‌های امنیتی و کاربران یونیکس

In practice, during login, the user gets assigned a default security context (depending on the roles that they should be able to endorse). This defines the current domain, and thus the domain that all new child processes will carry. If you want to change the current role and its associated domain, you must call newrole -r role_r -t domain_t (there is usually only a single domain allowed for a given role, the -t parameter can thus often be left out). This command authenticates you by asking you to type your password. This feature forbids programs to automatically switch roles. Such changes can only happen if they are explicitly allowed in the SELinux policy.
به طور مشخص این دسترسی‌ها به تمام اشیا متعلق نیستند (فایل‌ها، دایرکتوری‌ها، سوکت‌ها، دستگاه‌ها و از این قبیل). می‌توانند از هر شی به دیگری متفاوت باشند. برای دستیابی به این منظور، هر شی به یک نوع اختصاص می‌یابد (اینکار بنام برچسب‌گذاری شناخته می‌شود). دسترسی‌های یک دامنه توسط مجموعه‌ای از عمیات (غیر)مجاز روی این انواع بیان می‌شوند (و به طور غیرمستقیم، روی تمام اشیایی که با این نوع برچسب‌گذاری شده‌اند).
به صورت پیشفرض، یک برنامه دامنه خود را از کاربری که فرآیند را آغاز کرده است به ارث می‌برد، اما خطی مشی استاندارد SELinux انتظار دارد که برنامه‌های مهم در دامنه‌های اختصاصی اجرا شوند. برای دستیابی به این منظور، آن برنامه‌های اجرایی همراه با یک نوع اختصاصی برچسب‌گذاری می‌شوند (برای نمونه ssh توسط ssh_exec_t برچسب‌گذاری شده و زمانی که برنامه آغاز شود به صورت خودکار به دامنه ssh_t تغییر می‌یابد). این مکانیزم خودکار انتقال دامنه امکان اختصاص دسترسی‌های لازم برای هر بر نامه را فراهم می‌کند. این یک اصل پایه در SELinux به حساب می‌آید.
انتقال خودکار بین دامنه‌ها

شكل 14.2. انتقال خودکار بین دامنه‌ها

14.5.2. راه‌اندازی SELinux

پشتیبانی از SELinux درون کرنل‌های استاندارد دبیان قرار دارد. ابزار اصلی یونیکس از SELinux بدون کوچک‌ترین تغییری پشتیبانی می‌کنند. بنابراین فعال‌سازی SELinux کار به نسبت ساده‌ای است.
The apt install selinux-basics selinux-policy-defaulti auditd command will automatically install the packages required to configure an SELinux system.
بسته selinux-policy-default شامل مجموعه قوانین استاندارد است. به صورت پیشفرض، این خط مشی تنها دسترسی به برخی سرویس‌های مشخص را محدود می‌کند. نشست‌های سمت کاربر محدود نیستند و از این رو بعید بنظر می‌رسد که SELinux عملیات مرتبط با کاربران مجاز را مسدود سازد. با این حال، اینکار منجر به بهبود امنیت سرویس‌های سیستمی می‌شود. برای راه‌انداری خط مشی که برابر با قوانین “strict” قدیمی باشد، تنها باید ماژول unconfined را غیرفعال کنید (مدیریت ماژول‌ها در ادامه آورده می‌شود).
زمانی که خط مشی مشخص گردد، باید تمام فایل‌های موجود را برچسب‌گذاری کنید (به این معنی که یک نوع به آن‌ها اختصاص دهید). این عملیات باید به صورت دستی توسط fixfiles relabel صورت پذیرد.
اکنون سیستم SELinux آماده است. برای فعال‌سازی آن، باید پارامتر selinux=1 security=selinux را به کرنل لینوکس اضافه کنید. پارامتر enforcing=1 امکان ثبت گزارش در SELinux که تمام عملیات غیرمجاز را ثبت می‌کند. در نهایت، پارامتر audit=1 قوانین را برای برنامه‌ها اجرایی می‌کند: بدون این پارامتر SELinux در حالت پیشفرض permissive خود فعالیت کرده به صورتی که عملیات غیرمجاز ثبت شده ولی هنوز اجرا می‌شوند. برای افزودن پارامترهای مورد نیاز باید فایل پیکربندی راه‌انداز GRUB را تغییر دهید. یک روش ساده برای اینکار تغییر متغیر GRUB_CMDLINE_LINUX در /etc/default/grub و اجرای update-grub است. SELinux پس از راه‌اندازی مجدد سیستم فعال‌سازی می‌شود.
شایان ذکر است که اسکریپت selinux-activate این عملیات را خودکارسازی کرده و در راه‌اندازی بعدی عملیات برچسب‌گذاری را انجام می‌دهد (که این عمل از ایجاد فایل‌های برچسب‌گذاری نشده در زمان غیرفعال بودن SELinux و زمانی که عملیات برچسب‌گذاری انجام می‌شود، پیشگیری می‌کند).

14.5.3. مدیریت یک سیستم SELinux

خط مشی SELinux مجموعه‌ای از قوانین ماژولار است که نصب آن با شناسایی و فعال‌سازی خودکار تمام ماژول‌های مبتنی بر سرویس‌های نصب شده فعالیت می‌کند. از این رو سیستم بلافاصله قابل استفاده است. با این حال، زمانی که یک سرویس پس از خط مشی SELinux نصب می‌شود، باید قادر باشید تا ماژول مرتبط با آن را فعال‌سازی کنید. هدف دستور semodule نیز همین است. علاوه بر این، باید بتوانید نقش‌های مورد نیاز هر کاربر را تعریف کنید که اینکار با استفاده از دستور semanage انجام می‌شود.
این دو دستور می‌توانند به منظور تغییر پیکربندی SELinux، که در /etc/selinux/default/ ذخیره‌سازی شده است، بکار روند. برخلاف تمام فایل‌های پیکربندی که می‌توانید در /etc/ پیدا کنید، این فایل‌ها نباید به صورت دستی تغییر یابند. باید از برنامه‌های مخصوص برای تغییر آن‌ها استفاده کنید.

14.5.3.1. مدیریت ماژول‌های SELinux

ماژول‌های موجود SELinux درون دایرکتوری /usr/share/selinux/default/ قرار دارند. برای فعال‌سازی یکی از این ماژول‌ها در پیکربندی فعلی، باید از semodule -i module.pp.bz2 استفاده کنید. پسوند pp.bz2 مخفف عبارت policy package است (که توسط bzip2 فشرده‌سازی شده است).
حذف یک ماژول از پیکربندی موجود با استفاده از semodule -r module صورت می‌پذیرد. در نهایت، دستور semodule -l فهرستی از تمام ماژول‌های نصب شده را نشان می‌دهد. همچنین شماره نسخه را نیز نمایش می‌دهد. ماژول‌ها می‌توانند توسط semodule -e فعال یا semodule -d غیرفعال شوند.
# semodule -i /usr/share/selinux/default/abrt.pp.bz2
libsemanage.semanage_direct_install_info: abrt module will be disabled after install as there is a disabled instance of this module present in the system.
# semodule -l
accountsd
acct
[...]
# semodule -e abrt
# semodule -d accountsd
# semodule -l
abrt
acct
[...]
# semodule -r abrt
libsemanage.semanage_direct_remove_key: abrt module at priority 100 is now active.
semodule بلافاصله پیکربندی جدید را بارگیری می‌کند مگر اینکه از گزینه -n استفاده کنید. شایان ذکر است که برنامه به صورت پیشفرض با پیکربندی فعلی کار می‌کند (که توسط متغیر SELINUXTYPE در /etc/selinux/config مشخص شده است)، اما می‌توانید آن را با استفاده از گزینه -s تغییر دهید.

14.5.3.2. مدیریت شناسه‌ها

هر مرتبه که کاربر وارد سیستم می‌شود، یک شناسه SELinux به وی اختصاص می‌یابد. این شناسه مشخص می‌کند کاربر از چه نقش‌هایی می‌تواند استفاده کند. این دو نگاشت (از کاربر به شناسه و از شناسه به نقش‌ها) توسط دستور semanage قابل پیکربندی هستند.
You should definitely read the semanage(8) manual page. All the managed concepts have their own manual page; for instance, semanage-login(8). Even if the command's syntax tends to be similar for all the concepts which are managed, it is recommended to read its manual page. You will find common options to most subcommands: -a to add, -d to delete, -m to modify, -l to list, and -t to indicate a type (or domain).
semanage login -l نگاشت فعلی بین شناسه‌های کاربر و هویت‌های SELinux را فهرست می‌کند. کاربرانی که هیچ مدخل واضحی ندارند از شناسه موجود در مدخل __default__ استفاده می‌کنند. دستور semanage login -a -s user_u user شناسه user_u را به کاربر مورد نظر اختصاص می‌دهد. در نهایت، semanage login -d user نگاشت موجود برای کاربر را از بین می‌برد.
# semanage login -a -s user_u rhertzog
# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
rhertzog             user_u               s0                   *
root                 unconfined_u         s0-s0:c0.c1023       *
# semanage login -d rhertzog
semanage user -l نگاشت فعلی بین شناسه‌های کاربری SELinux و نقش‌های مجاز را فهرست می‌کند. افزودن یک شناسه جدید مستلزم تعریف نقش‌های مرتبط با آن همراه با پیشوند برچسب‌گذاری برای اختصاص نوع به فایل‌های شخصی کاربر می‌باشد (/home/user/*). پیشوند باید از میان user، staff یا sysadm انتخاب شود. پیشوند “staff” روی فایل‌هایی از نوع “staff_home_dir_t” تاثیر می‌گذارد. ایجاد یک شناسه کاربری جدید SELinux توسط semanage user -a -R roles -P prefix identity انجام می‌شود. در نهایت، با استفاده از semanage user -d identity می‌توانید یک شناسه کاربری SELinux را حذف کنید.
# semanage user -a -R 'staff_r user_r' -P staff test_u
# semanage user -l

                Labeling   MLS/       MLS/                          
SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles

root            sysadm     s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r
staff_u         staff      s0         s0-s0:c0.c1023                 staff_r sysadm_r
sysadm_u        sysadm     s0         s0-s0:c0.c1023                 sysadm_r
system_u        user       s0         s0-s0:c0.c1023                 system_r
test_u          staff      s0         s0                             staff_r user_r
unconfined_u    unconfined s0         s0-s0:c0.c1023                 system_r unconfined_r
user_u          user       s0         s0                             user_r
# semanage user -d test_u

14.5.3.3. مدیریت زمینه‌های فایل، درگاه‌ها و شرایط منطقی

هر ماژول SELinux مجموعه‌ای از قوانین برچسب‌گذاری را تعریف می‌کند، اما امکان تعریف قوانین سفارشی برای برچسب‌گذاری نیز وجود دارد. برای نمونه، اگر می‌خواهید که سرور وب قادر باشد فایل‌های درون دایرکتوری /srv/www/ را بخواند، می‌توانید دستور semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?" را همراه با restorecon -R /srv/www/ اجرا کنید. دستور اول قوانین جدید برچسب‌گذاری را ثبت و دستور دوم انواع فایل را متناسب با قوانین جدید برچسب‌گذاری می‌کند.
به طور مشابه، درگاه‌های TCP/UDP به شیوه‌ای برچسب‌گذاری می‌شوند که تنها فرآیندهای پس‌زمینه متناسب بتوانند به آن‌ها گوش دهند. برای نمونه، اگر می‌خواهید سرور وب به درگاه ۸۰۸۰ گوش دهد، باید semanage port -m -t http_port_t -p tcp 8080 را اجرا کنید.
Some SELinux modules export Boolean options that you can tweak to alter the behavior of the default rules. The getsebool utility can be used to inspect those options (getsebool boolean displays one option, and getsebool -a them all). The setsebool boolean value command changes the current value of a Boolean option. The -P option makes the change permanent, it means that the new value becomes the default and will be kept across reboots. The example below grants web servers an access to home directories (this is useful when users have personal websites in ~/public_html/).
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
# setsebool -P httpd_enable_homedirs on
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on

14.5.4. انطباق قوانین

از آنجا که خط مشی SELinux ماژولار بوده، توسعه ماژول‌های جدید برای برنامه‌هایی که به آن نیاز دارند (به صورت سفارشی) کار جالبی است. این ماژول‌های جدید خط مشی مرجع را کامل می‌کنند.
برای ایجاد ماژول‌های جدید، بسته‌های selinux-policy-dev و selinux-policy-doc مورد نیاز هستند. بسته دوم شامل مستندات قوانین استاندارد (/usr/share/doc/selinux-policy-doc/html/) و فایل‌های نمونه است که می‌توانند به عنوان قالب برای ایجاد ماژول‌های جدید بکار روند. این فایل‌ها را نصب کرده و به دقت مطالعه نمایید:
$ cp /usr/share/doc/selinux-policy-doc/Makefile.example Makefile
$ cp /usr/share/doc/selinux-policy-doc/example.fc ./
$ cp /usr/share/doc/selinux-policy-doc/example.if ./
$ cp /usr/share/doc/selinux-policy-doc/example.te ./
فایل .te مهم‌ترین آن‌ها است که قوانین را تعریف می‌کند. فایل .fc “زمینه‌های فایل” را تعریف می‌کند، که همان نوع اختصاص یافته به فایل‌های مرتبط با این ماژول است. از داده موجود درون فایل .fc در گام برچسب‌گذاری استفاده می‌شود. در نهایت، فایل .if رابط مرتبط با ماژول را تعریف می‌کند: یک مجموعه از “توابع عمومی” است که سایر ماژول‌ها می‌توانند به منظور تعامل بهتر با این ماژول از آن‌ها استفاده کنند.

14.5.4.1. نوشتن یک فایل .fc

خواندن مثال زیر برای درک اولیه از محتوای فایل مذکور کافی است. می‌توانید با استفاده از عبارت‌های منظم یک زمینه امنیتی یکسان را برای چندین فایل یا حتی یک دایرکتوری کامل در نظر بگیرید.

مثال 14.2. فایل example.fc

# myapp executable will have:
# label: system_u:object_r:myapp_exec_t
# MLS sensitivity: s0
# MCS categories: <none>

/usr/sbin/myapp         --      gen_context(system_u:object_r:myapp_exec_t,s0)

14.5.4.2. نوشتن یک فایل .if

در مثال زیر، اولین رابط (“myapp_domtrans”) کنترل می‌کند چه کسی می‌تواند برنامه را اجرا کند. رابط دوم (“myapp_read_log”) اجازه خواندن و نوشتن روی فایل‌های گزارش برنامه را می‌دهد.
هر رابط باید مجموعه‌ای معتبر از قوانین را که درون فایل .te قرار می‌گیرند تعریف کند. بنابراین باید تمام انواع مورد استفاده خود را تعریف کنید (با استفاده از ماکرو gen_require) و از عبارت‌های استاندارد به منظور تخصیص دسترسی بهره ببرید. با این حال، به یاد داشته باشید که می‌توانید از رابط‌های سایر ماژول‌ها نیز استفاده کنید. قسمت بعد توضیحات بیشتری در مورد چگونگی تخصیص این دسترسی‌ها ارائه می‌دهد.

مثال 14.3. فایل example.if

## <summary>Myapp example policy</summary>
## <desc>
##      <p>
##              More descriptive text about myapp.  The desc
##              tag can also use p, ul, and ol
##              html tags for formatting.
##      </p>
##      <p>
##              This policy supports the following myapp features:
##              <ul>
##              <li>Feature A</li>
##              <li>Feature B</li>
##              <li>Feature C</li>
##              </ul>
##      </p>
## </desc>
#

########################################
## <summary>
##      Execute a domain transition to run myapp.
## </summary>
## <param name="domain">
##      <summary>
##      Domain allowed to transition.
##      </summary>
## </param>
#
interface(`myapp_domtrans',`
        gen_require(`
                type myapp_t, myapp_exec_t;
        ')

        domtrans_pattern($1,myapp_exec_t,myapp_t)
')

########################################
## <summary>
##      Read myapp log files.
## </summary>
## <param name="domain">
##      <summary>
##      Domain allowed to read the log files.
##      </summary>
## </param>
#
interface(`myapp_read_log',`
        gen_require(`
                type myapp_log_t;
        ')

        logging_search_logs($1)
        allow $1 myapp_log_t:file read_file_perms;
')

14.5.4.3. نوشتن یک فایل .te

نگاهی به فایل example.te بیندازید:
policy_module(example,1.0.0) 1 # a non-base module name must match the file name

########################################
#
# Declarations
#

type myapp_t; 2
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t) 3

type myapp_log_t;
logging_log_file(myapp_log_t) 4

type myapp_tmp_t;
files_tmp_file(myapp_tmp_t)

########################################
#
# Myapp local policy
#

allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; 5

allow myapp_t myapp_tmp_t:file manage_file_perms;
files_tmp_filetrans(myapp_t,myapp_tmp_t,file)

1

ماژول باید توسط نام و شماره نسخه‌اش معرفی شود. این عبارت مورد نیاز است.

2

اگر ماژول انواع جدیدی را معرفی کند، باید به شکل عبارت مشابه بالا باشد. از ایجاد انواع مورد نیاز خود دریغ نکنید بجای اینکه تعداد زیادی دسترسی بی‌معنا صادر کنید.

3

این رابط‌ها نوع myapp_t را به عنوان یک دامنه فرآیند تعریف می‌کنند که باید برای هر برنامه اجرایی برچسب‌گذاری شده با myapp_exec_t بکار روند. به طور ضمنی، اینکار یک صفت exec_type روی آن اشیا اضافه می‌کند، که در عوض به سایر ماژول‌ها اجازه می‌دهد برای اجرای برنامه‌ها دسترسی‌های لازم را صادر کنند: برای نمونه، ماژول userdomain به فرآیندهای موجود در دامنه‌های user_t، staff_t و sysadm_t اجازه اجرا می‌دهد. دامنه‌های سایر برنامه‌های محدود شده اجازه دسترسی برای اجرا را ندارند، مگر اینکه قوانین همان دسترسی‌ها را برایشان تعریف کنند (برای نمونه، در مورد dpkg همراه با دامنه dpkg_t آن).

4

logging_log_file is an interface provided by the reference policy. It indicates that files labeled with the given type are log files which ought to benefit from the associated rules (for example, granting rights to logrotate so that it can manipulate them).

5

allow عبارت پایه‌ای است که برای احرازهویت یک عملیات استفاده می‌شود. پارامتر اول آن دامنه فرآیندی است که امکان اجرای عملیات را دارد. پارامتر دوم به تعریف یک شی می‌پردازد که فرآیند دامنه قبلی می‌تواند آن را تغییر دهد. این پارامتر به شکل “type:class“ است که در آن type نوع SELinux است و class طبیعت آن شی را تعریف می‌کند (فایل، دایرکتوری، سوکت و از این قبیل). در نهایت، پارامتر آخر به تعریف مجوزها می‌پردازد (همان عملیات مجاز).
مجوزها مجموعه‌ای از عملیات مجاز هستند که از قالب رو‌به‌رو تبعیت می‌کنند: { operation1 operation2 }. اگرچه، می‌توانید از ماکروها برای نمایش کاربردی‌ترین مجوزها نیز استفاده کنید. فایل /usr/share/selinux/devel/include/support/obj_perm_sets.spt فهرستی از آن‌ها را شامل می‌شود.
The following web page provides a relatively exhaustive list of object classes, and permissions that can be granted.
اکنون باید حداقل مجموعه قوانین مورد نیاز برای اجرای صحیح برنامه یا سرویس هدف را پیدا کنید. برای دستیابی به این منظور، باید دانش خوبی از چگونگی کارکرد برنامه و انواع داده‌های مدیریتی/تولیدی آن را داشته باشید.
اگرچه، رویکرد تجربی نیز ممکن است. زمانی که اشیای مربوطه برچسب‌گذاری شده‌اند، می‌توانید از برنامه در حالت permissive استفاده کنید: عملیاتی که ممنوع باشند ثبت گزارش شده ولی هنوز اجرا می‌شوند. با بررسی و تحلیل این گزارش‌ها می‌توانید عملیات مجاز را تشخیص دهید. در اینجا نمونه‌ای از چنین فایل گزارشی آورده شده است:
avc:  denied  { read write } for  pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1
برای درک بهتر این پیام بیایید آن را قطعه به قطعه مطالعه کنیم.

جدول 14.1. بررسی و تحلیل گزارش SELinux

پیامتوضیحات
avc: deniedعملیات غیرمجاز است.
{ read write }این عملیات نیازمند مجوزهای read و write است.
pid=1876فرآیندی با شناسه ۱۸۷۶ اقدام به اجرای عملیات کرده است.
comm="syslogd"فرآیند یک نمونه از برنامه syslogd بوده است.
name="xconsole"شی هدف xconsole نام دارد. بعضی وقت‌ها می‌توانید یک متغیر “path” داشته باشید - همراه با مسیر کامل-.
dev=tmpfsThe device hosting the target object is a tmpfs (an in-memory filesystem). For a real disk, you could see the partition hosting the object (for example, “sda3”).
ino=5510شی با inode ۵۵۱۰ شناسایی شده است.
scontext=system_u:system_r:syslogd_t:s0این همان زمینه امنیتی فرآیندی است که عملیات را اجرا کرده است.
tcontext=system_u:object_r:device_t:s0این همان زمینه امنیتی شی هدف می‌باشد.
tclass=fifo_fileشی هدف یک فایل FIFO است.
By observing this log entry, it is possible to build a rule that would allow this operation. For example, allow syslogd_t device_t:fifo_file { read write }. This process can be automated, and it is exactly what the audit2allow command (of the policycoreutils package) offers. This approach is only useful if the various objects are already correctly labeled according to what must be confined. In any case, you will have to carefully review the generated rules and validate them according to your knowledge of the application. Effectively, this approach tends to grant more rights than are really required. The proper solution is often to create new types and to grant rights on those types only. It also happens that a denied operation isn't fatal to the application, in which case it might be better to just add a “dontaudit” rule to avoid the log entry despite the effective denial.

14.5.4.4. کامپایل‌کردن فایل‌ها

Once the 3 files (example.if, example.fc, and example.te) match your expectations for the new rules, rename them to myapp.extension and run make NAME=devel to generate a module in the myapp.pp file (you can immediately load it with semodule -i myapp.pp). If several modules are defined, make will create all the corresponding .pp files.