قفل‌کردن هسته (به انگلیسی: Kernel Lockdown) یکی از ویژگی‌های جدید هسته سیستم‌عامل لینوکس است که در نسخه ۵.۴ به آن اضافه شده است.

هدف از ایجاد این ویژگی، قراردادن مرز مجکم‌تری بین بین فضای کاربر (به انگلیسی: User Space) و فضای هسته (به انگلیسی: Kernel Space) از طریق محدودسازی کاربر ریشه است. کاربر ریشه که با UID 0 مشخص می‌شود، به طور پیش‌فرض سطح دسترسی بالایی به تمام سیستم داشته و حتی امکان ویرایش هسته را هم دارد.

علت پیاده‌سازی
--------------

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

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

تاریخچه بحث و گفتگو برای پیاده‌سازی این ویژگی
---------------------------------------------

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

یکی از دلایل این حواشی مربوط به این می‌شود که در هسته لینوکس، مکانیزمی برای اعمال سیاست‌های امنیتی در قالب ماژول امنیتی لینوکس (به انگلیسی: Linux Security Module) قرار گرفته بود. این مکانیزم دست کاربر را برای اعمال محدودیت‌های امنیتی مختلف باز می‌گذارد. با این وجود مشکلی که وجود دارد، این بخش از فضای کاربر قابل اعمال است اما چنین سازوکاری که قرار است جلوی ویرایش نابه‌جای هسته را بگیرد، باید پیش از این که بتوان سیاست امنیتی خاصی را اعمال کرد، فعال بشود.

نحوه پیاده‌سازی
---------------

با توجه به مسائلی که در مورد لزوم پیاده‌سازی این قابلیت قبل از بالاآمدن سیستم وجود دارد، ی ماژول امنیتی مقدماتی در هنگام بالاآمدن سیستم ایجاد می‌شود تا قلاب‌های امنیتی (Security Hooks) اولیه لازم برای مکانیزم قفل کردن هسته ثبت بشوند. این قلاب امنیتی در پرونده lsm\_hooks.h تعریف شده و در پرونده security.c در تابع security\_locked\_down فراخوانی می‌شود.

```
//lsm\_hooks.h
int (\*locked\_down)(enum lockdown\_reason what);
 
//security.c 
int security\_locked\_down(enum lockdown\_reason what)
{
 return call\_int\_hook(locked\_down, 0, what);
}

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

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

به طور کلی سه حالت برای قفل‌سازی هسته وجود دارد. LOCKDOWN\_NONE که عملاً این مورد را فعال نمی‌کند. حالت LOCKDOWN\_INTEGRITY\_MAX

که جلوی عملیات‌هایی که منجر به تغییر غیرمجاز در هسته (عموماً از سمت کاربر ریشه) می‌شوند را گرفته و حالت LOCKDOWN\_CONFIDENTIALITY\_MAX که حتی امکان افشای داده‌های سطح هسته را هم می‌گیرد. با این وجود باید توجه کرد که در اصل حالت‌های خیلی بیش‌تری وجود دارند که همه آن‌ها در قالب  enum lockdown\_reason  در پرونده Security.h قرار گرفته‌اند. به دلیل ترتیبی بودن enumها، عملاً فعلاسازی LOCKDOWN\_INTEGRITY\_MAX باعث فعال شدن همه حالت‌های امنیتی پیشین آن نظیر LOCKDOWN\_KEXEC هم می‌شود.

```
enum lockdown\_reason {
 LOCKDOWN\_NONE,
 LOCKDOWN\_MODULE\_SIGNATURE,
 LOCKDOWN\_DEV\_MEM,
 LOCKDOWN\_EFI\_TEST,
 LOCKDOWN\_KEXEC,
 LOCKDOWN\_HIBERNATION,
 LOCKDOWN\_PCI\_ACCESS,
 LOCKDOWN\_IOPORT,
 LOCKDOWN\_MSR,
 LOCKDOWN\_ACPI\_TABLES,
 LOCKDOWN\_PCMCIA\_CIS,
 LOCKDOWN\_TIOCSSERIAL,
 LOCKDOWN\_MODULE\_PARAMETERS,
 LOCKDOWN\_MMIOTRACE,
 LOCKDOWN\_DEBUGFS,
 LOCKDOWN\_INTEGRITY\_MAX,
 LOCKDOWN\_KCORE,
 LOCKDOWN\_KPROBES,
 LOCKDOWN\_BPF\_READ,
 LOCKDOWN\_PERF,
 LOCKDOWN\_TRACEFS,
 LOCKDOWN\_CONFIDENTIALITY\_MAX,
};

```
به عنوان مثال یکی از تغییراتی که در این نسخه داده شده است، مربوط به پرونده kexec\_file.c است:

```
static int kimage\_validate\_signature(struct kimage \*image)
{
 ...
 if (!ima\_appraise\_signature(READING\_KEXEC\_IMAGE) &&
 security\_locked\_down(LOCKDOWN\_KEXEC))
 return -EPERM;
 ... 
 }

```

این تابع در صورتی که امضای پرونده توسط واحد Integrity Measurement Architecture تایید نشود و حالت LOCKDOWN\_KEXEC هم فعال باشد، خطای مجاز نبودن عملیات (EPERM) می‌دهد.

بخش عمده تغییرات مربوط به این قابلیت مربوط به پرونده lockdown.c می‌شود. مثلاً پیاده‌سازی اصلی تابع نظیر شده به قلاب امنیتی locked\_down با نام lockdown\_is\_locked\_down در این پرونده قرار دارد. در این پرونده توابعی برای خواندن و نوشتن هم پیاده‌سازی شده است که در اصل یکسری بررسی‌ها روی وضعیت و حالات قفل‌سازی هسته انجام داده و در صورت نیاز پیام‌ها یا خطاهایی را که در هنگام خروجی‌دادن این توابع باید تولید بشوند، مشخص کرده و در نهایت عملکرد اصلی خواندن و نوشتن را انجام می‌دهند.

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

```
static int lock\_kernel\_down(const char \*where, enum lockdown\_reason level)
{
 if (kernel\_locked\_down>= level)
 return -EPERM;

 kernel\_locked\_down = level;
 pr\_notice("Kernel is locked down from %s; see man kernel\_lockdown.7\n",
 where);
 return 0;
}

static int lockdown\_is\_locked\_down(enum lockdown\_reason what)
{
 if (WARN(what>= LOCKDOWN\_CONFIDENTIALITY\_MAX,
 "Invalid lockdown reason"))
 return -EPERM;

 if (kernel\_locked\_down>= what) {
 if (lockdown\_reasons[what])
 pr\_notice("Lockdown: %s: %s is restricted; see man kernel\_lockdown.7\n",
 current->comm, lockdown\_reasons[what]);
 return -EPERM;
 }

 return 0;
}

static struct security\_hook\_list lockdown\_hooks[] \_\_lsm\_ro\_after\_init = {
 LSM\_HOOK\_INIT(locked\_down, lockdown\_is\_locked\_down),
};

```
این قابلیت ریزه‌کاری‌های دیگری هم در قسمت‌های دیگر کد هسته دارد. تغییراتی جزئی در کدهای مربوط به ACPI که در هنگام بوت‌شدن سیستم برای مدیریت توان و شناسایی قطعات سخت‌افزاری کاربرد دارد داده شده است. به علاوه تغییراتی جزئی در file.c و inode.c داده شده تا وضعیت قفل‌بودن هسته در حالاتی خاص گزارش بشود.

منابع
-----

<references group="">

1. 1 2  Cimpanu, Catalin. "Linux to get kernel 'lockdown' feature". *ZDNet* (به انگلیسی). Retrieved 2021-05-13.
2. ↑  «Linux\_5.4 - Linux Kernel Newbies». *kernelnewbies.org*. دریافت‌شده در ۲۰۲۱-۰۵-۱۳.
3. 1 2  «Lockdown as a security module [LWN.net]». *lwn.net*. دریافت‌شده در ۲۰۲۱-۰۵-۱۳.
4. ↑  «Preparing the kernel for UEFI secure boot [LWN.net]». *lwn.net*. دریافت‌شده در ۲۰۲۱-۰۵-۱۳.
5. ↑  «kernel\_lockdown(7) - Linux manual page». *man7.org*. دریافت‌شده در ۲۰۲۱-۰۵-۱۳.
6. ↑  «kernel/git/torvalds/linux.git - Linux kernel source tree». *git.kernel.org*. دریافت‌شده در ۲۰۲۱-۰۵-۱۳.
7. 1 2  "torvalds/linux". *GitHub* (به انگلیسی). Retrieved 2021-05-13.