В чем разница между пространством ядра и пространством пользователя?
В чем разница между пространством ядра и пространством пользователя? Означает ли пространство ядра, потоки ядра, процессы ядра и стек ядра одно и то же? Кроме того, зачем нам эта дифференциация?
17 ответов
Действительно упрощенный ответ заключается в том, что ядро работает в пространстве ядра, а обычные программы - в пространстве пользователя. Пространство пользователя в основном является формой песочницы - оно ограничивает пользовательские программы, поэтому они не могут связываться с памятью (и другими ресурсами), принадлежащими другим программам или ядру ОС. Это ограничивает (но обычно не полностью исключает) их способность совершать плохие поступки, например, разбивать машину.
Ядро - это ядро операционной системы. Обычно он имеет полный доступ ко всей памяти и оборудованию машины (и всему остальному на машине). Чтобы машина была максимально стабильной, обычно требуется, чтобы в режиме ядра / пространстве ядра выполнялся только самый проверенный и проверенный код.
Стек - это просто другая часть памяти, поэтому, естественно, он отделен от остальной памяти.
Оперативное запоминающее устройство (ОЗУ) может быть логически разделено на две отдельные области, а именно - пространство ядра и пространство пользователя ( физические адреса ОЗУ фактически не делятся только на виртуальные адреса, все это реализуется MMU)
Ядро работает в той части памяти, которая имеет на это право. Эта часть памяти не может быть доступна напрямую процессам обычных пользователей, поскольку ядро может получить доступ ко всем частям памяти. Для доступа к какой-либо части ядра пользовательские процессы должны использовать предопределенные системные вызовы, т.е. open
, read
, write
и т. д. Также C
библиотечные функции, такие как printf
вызвать системный вызов write
в очереди.
Системные вызовы действуют как интерфейс между пользовательскими процессами и процессами ядра. Права доступа размещены в пространстве ядра, чтобы не дать пользователям по ошибке осознать ядро.
Таким образом, когда происходит системный вызов, программному прерыванию отправляется ядро. Процессор может временно передать управление соответствующей подпрограмме обработки прерывания. Процесс ядра, который был остановлен прерываниями, возобновляется после того, как процедура обработчика прерываний завершает свою работу.
Кольца процессора - самое четкое различие
В защищенном режиме x86 процессор всегда находится в одном из 4 звонков. Ядро Linux использует только 0 и 3:
- 0 для ядра
- 3 для пользователей
Это наиболее сложное и быстрое определение ядра и пользовательского пространства.
Почему Linux не использует кольца 1 и 2: Кольца привилегий ЦП: Почему кольца 1 и 2 не используются?
Как определяется текущее кольцо?
Текущее кольцо выбирается комбинацией:
таблица глобальных дескрипторов: таблица в памяти записей GDT, и у каждой записи есть поле
Privl
который кодирует кольцо.Инструкция LGDT устанавливает адрес для текущей таблицы дескрипторов.
Смотрите также: http://wiki.osdev.org/Global_Descriptor_Table
Сегмент регистрирует CS, DS и т. д., которые указывают на индекс записи в GDT.
Например,
CS = 0
означает, что первая запись GDT в данный момент активна для исполняемого кода.
Что может сделать каждое кольцо?
Чип процессора физически построен так, что:
кольцо 0 может сделать что угодно
кольцо 3 не может выполнить несколько инструкций и записать в несколько регистров, в частности:
не может изменить свое собственное кольцо! В противном случае он мог бы установить себе кольцо 0, и кольца были бы бесполезны.
Другими словами, нельзя изменить текущий дескриптор сегмента, который определяет текущее кольцо.
не может изменить таблицы страниц: как работает подкачка x86?
Другими словами, нельзя изменить регистр CR3, а само разбиение на страницы предотвращает изменение таблиц страниц.
Это препятствует тому, чтобы один процесс видел память других процессов из соображений безопасности / простоты программирования.
не может зарегистрировать обработчики прерываний. Они настраиваются путем записи в ячейки памяти, что также предотвращается подкачкой.
Обработчики работают в кольце 0 и нарушают модель безопасности.
Другими словами, нельзя использовать инструкции LGDT и LIDT.
не может сделать инструкции IO, такие как
in
а такжеout
и, таким образом, иметь произвольный доступ к оборудованию.В противном случае, например, права доступа к файлам будут бесполезны, если какая-либо программа сможет напрямую читать с диска.
Точнее, благодаря Майклу Петчу: операционная система может разрешить инструкции ввода-вывода на 3-м кольце, это фактически контролируется сегментом состояния задачи.
То, что не возможно, для кольца 3, чтобы дать себе разрешение сделать это, если у него не было его во-первых.
Linux всегда запрещает это. См. Также: Почему Linux не использует аппаратное переключение контекста через TSS?
Как программы и операционные системы переходят между кольцами?
когда процессор включен, он запускает исходную программу в кольце 0 (что-то вроде, но это хорошее приближение). Вы можете считать эту исходную программу ядром (но обычно это загрузчик, который затем вызывает ядро все еще в кольце 0).
когда пользовательский процесс хочет, чтобы ядро сделало что-то для него, например, запись в файл, он использует инструкцию, которая генерирует прерывание, такое как
int 0x80
сигнализировать ядро.Когда это происходит, процессор вызывает и обрабатывает обработчик обратного вызова, который ядро зарегистрировало во время загрузки.
Этот обработчик работает в кольце 0, который решает, разрешит ли ядро это действие, выполняет действие и перезапускает программу пользователя в кольце 3.
когда
exec
системный вызов используется (или когда ядро запустится/init
), ядро подготавливает регистры и память нового пользовательского процесса, затем оно переходит к точке входа и переключает ЦП на кольцо 3Если программа пытается сделать что-то непослушное, например, запись в запрещенный регистр или адрес памяти (из-за подкачки), ЦП также вызывает некоторый обработчик обратного вызова ядра в кольце 0.
Но поскольку пользовательская область была непослушной, ядро на этот раз может убить процесс или выдать ему предупреждение с сигналом.
Когда ядро загружается, оно устанавливает аппаратные часы с некоторой фиксированной частотой, которая периодически генерирует прерывания.
Эти аппаратные часы генерируют прерывания, которые запускают кольцо 0, и позволяют ему планировать, какие процессы пользователя активизируются.
Таким образом, планирование может происходить, даже если процессы не выполняют никаких системных вызовов.
Какой смысл иметь несколько колец?
Существует два основных преимущества разделения ядра и пользовательского пространства:
- проще создавать программы, так как вы уверены, что одно не будет мешать другому. Например, один пользовательский процесс не должен беспокоиться о перезаписи памяти другой программы из-за подкачки страниц или о переводе оборудования в недопустимое состояние для другого процесса.
- это более безопасно. Например, права доступа к файлам и разделение памяти могут помешать хакерскому приложению читать ваши банковские данные. Это предполагает, конечно, что вы доверяете ядру.
Как поиграть с этим?
Я создал "голую железную" установку, которая должна быть хорошим способом для непосредственного управления кольцами: https://github.com/cirosantilli/x86-bare-metal-examples
К сожалению, у меня не хватило терпения сделать пример пользовательского пространства, но я дошел до настройки пейджинга, поэтому пользовательское пространство должно быть выполнимым. Я хотел бы видеть запрос на получение.
Кроме того, модули ядра Linux работают в кольце 0, поэтому вы можете использовать их для проверки привилегированных операций, например, для чтения управляющих регистров: как получить доступ к управляющим регистрам cr0,cr2,cr3 из программы? Получение ошибки сегментации
Вот удобная настройка QEMU + Buildroot, чтобы попробовать ее, не убивая своего хоста.
Недостатком модулей ядра является то, что другие kthreads работают и могут мешать вашим экспериментам. Но в теории вы можете взять на себя все обработчики прерываний с вашим модулем ядра и владеть системой, это будет действительно интересный проект.
Отрицательные кольца
Хотя отрицательные кольца фактически не упоминаются в руководстве Intel, на самом деле существуют режимы ЦП, которые имеют более широкие возможности, чем само кольцо 0, и поэтому хорошо подходят для имени "отрицательного кольца".
Одним из примеров является режим гипервизора, используемый в виртуализации.
Для получения дополнительной информации см.: https://security.stackexchange.com/questions/129098/what-is-protection-ring-1
РУКА
В ARM кольца называются уровнями исключения, но основные идеи остаются прежними.
В ARMv8 существует 4 уровня исключений, которые обычно используются как:
EL0: пользовательская область
EL1: ядро
EL2: гипервизоры, например Xen.
Гипервизор для ОС, то же самое, что ОС для пользователя.
Например, Xen позволяет запускать несколько ОС, таких как Linux или Windows, в одной и той же системе одновременно, и он изолирует ОС друг от друга для обеспечения безопасности и простоты отладки, как это делает Linux для пользовательских программ.
Гипервизоры являются ключевой частью современной облачной инфраструктуры: они позволяют нескольким серверам работать на одном оборудовании, поддерживая использование оборудования всегда близким к 100% и экономя много денег.
Например, AWS использовала Xen до 2017 года, когда новость о переходе на KVM.
EL3: еще один уровень. Пример TODO.
Эталонная модель архитектуры ARMv8 DDI 0487C.a - Глава D1 - Модель программиста на уровне системы AArch64 - Рисунок D1-1 прекрасно иллюстрирует это:
Обратите внимание, что ARM, возможно, благодаря ретроспективному анализу, имеет лучшее соглашение об именах для уровней привилегий, чем x86, без необходимости отрицательных уровней: 0 является самым низким, а 3 самым высоким. Более высокие уровни, как правило, создаются чаще, чем более низкие.
Текущий EL может быть запрошен с MRS
инструкция: каков текущий режим выполнения / уровень исключения и т. д.?
ARM не требует наличия всех уровней исключений, чтобы обеспечить реализации, которым не требуется эта функция для сохранения площади микросхемы. ARMv8 "Уровни исключения" говорит:
Реализация может не включать все уровни исключений. Все реализации должны включать EL0 и EL1. EL2 и EL3 являются необязательными.
Например, QEMU по умолчанию имеет значение EL1, но EL2 и EL3 можно включить с помощью параметров командной строки: qemu-system-aarch64 вводит el1 при эмуляции включения питания a53
Пространство ядра и виртуальное пространство являются понятиями виртуальной памяти.... это не означает, что Ram(ваша фактическая память) разделен на ядро и пространство пользователя. Каждому процессу предоставляется виртуальная память, которая делится на ядро и пространство пользователя.
Таким образом, говоря: "Оперативная память (RAM) может быть разделена на две отдельные области, а именно - пространство ядра и пространство пользователя". неправильно.
& относительно вещи "пространство ядра против пространства пользователя"
Когда процесс создан и его виртуальная память разделена на пользовательское пространство и пространство ядра, где область пользовательского пространства содержит данные, код, стек, кучу процесса и пространство ядра содержит такие вещи, как таблица страниц для процесса., структуры данных ядра, код ядра и т. д. Для запуска кода пространства ядра управление должно перейти в режим ядра (с использованием программного прерывания 0x80 для системных вызовов), а стек ядра в основном распределяется между всеми процессами, выполняющимися в настоящее время в пространстве ядра.
Пространство ядра и пространство пользователя - это разделение функций привилегированной операционной системы и ограниченных пользовательских приложений. Разделение необходимо для того, чтобы пользовательские приложения не могли обыскать ваш компьютер. Было бы плохо, если бы любая старая пользовательская программа могла начать запись случайных данных на ваш жесткий диск или считывать память из пространства памяти другой пользовательской программы.
Программы пространства пользователя не могут получить доступ к системным ресурсам напрямую, поэтому доступ осуществляется от имени программы ядром операционной системы. Программы пользовательского пространства обычно делают такие запросы операционной системы через системные вызовы.
Потоки ядра, процессы, стек не означают одно и то же. Они являются аналогичными конструкциями для пространства ядра как их аналоги в пространстве пользователя.
Каждый процесс имеет 4 ГБ виртуальной памяти, которая отображается на физическую память через таблицы страниц. Виртуальная память в основном разделена на две части: 3 ГБ для использования процесса и 1 ГБ для использования ядра. Большинство переменных, которые вы создаете, находятся в первой части адресного пространства. Эта часть называется пользовательским пространством. В последней части находится ядро, которое является общим для всех процессов. Это называется пространством ядра, и большая часть этого пространства отображается на начальные места физической памяти, где образ ядра загружается во время загрузки.
Максимальный размер адресного пространства зависит от длины адресного регистра на процессоре.
В системах с 32-разрядными адресными регистрами максимальный размер адресного пространства составляет 232 байта или 4 ГиБ. Аналогично, в 64-битных системах можно адресовать 264 байта.
Такое адресное пространство называется виртуальной памятью или виртуальным адресным пространством. На самом деле это не связано с физическим объемом оперативной памяти.
На платформах Linux виртуальное адресное пространство делится на пространство ядра и пространство пользователя.
Специфичная для архитектуры константа, называемая пределом размера задачи, или TASK_SIZE
, отмечает позицию, где происходит разделение:
диапазон адресов от 0 до
TASK_SIZE
-1 выделено для пользовательского пространства;остаток от
TASK_SIZE
до 232-1 (или 264-1) выделяется для пространства ядра.
Например, в конкретной 32-битной системе 3 ГиБ могут быть заняты для пространства пользователя и 1 ГиБ для пространства ядра.
Каждое приложение / программа в Unix-подобной операционной системе - это процесс; у каждого из них есть уникальный идентификатор, называемый Идентификатор процесса (или просто Идентификатор процесса, то есть PID). Linux предоставляет два механизма для создания процесса: fork()
системный вызов или 2. exec()
вызов.
Поток ядра - это легкий процесс, а также исполняемая программа. Один процесс может состоять из нескольких потоков, совместно использующих одни и те же данные и ресурсы, но проходящих разные пути через программный код. Linux предоставляет clone()
системный вызов для генерации потоков.
Примеры использования потоков ядра: синхронизация данных ОЗУ, помощь планировщику в распределении процессов между процессорами и т. Д.
Вкратце: ядро работает в пространстве ядра, пространство ядра имеет полный доступ ко всей памяти и ресурсам, можно сказать, что память делится на две части, часть для ядра и часть для собственного процесса пользователя (пространство пользователя), запускает обычные программы, пользователь space не может получить прямой доступ к пространству ядра, поэтому он запрашивает у ядра использование ресурсов. по syscall (предопределенный системный вызов в glibc)
есть утверждение, которое упрощает различное "пространство пользователя - просто тестовая загрузка для ядра " ...
Чтобы быть очень ясным: архитектура процессора позволяет процессору работать в двух режимах, режиме ядра и пользовательском режиме, инструкция аппаратного обеспечения позволяет переключаться из одного режима в другой.
память может быть помечена как часть пространства пользователя или пространства ядра.
When CPU running in User Mode, the CPU can access only memory that is being in user space, while cpu attempts to access memory in Kernel space the result is a "hardware exception", when CPU running in Kernel mode, the CPU can access directly to both kernel space and user space ...
В коротком пространстве ядра - это часть памяти, где работает ядро linux (верхние 1 ГБ виртуального пространства в случае linux), а пространство пользователя - это часть памяти, в которой запускается пользовательское приложение (нижние 3 ГБ виртуальной памяти в случае Linux. Хотите узнать больше, см. ссылку, приведенную ниже:)
http://learnlinuxconcepts.blogspot.in/2014/02/kernel-space-and-user-space.html
Пространство ядра и пространство пользователя являются логическими пространствами.
Большинство современных процессоров предназначены для работы в разных привилегированных режимах. Машины x86 могут работать в 4 различных привилегированных режимах.
И конкретная машинная инструкция может быть выполнена, когда в / выше конкретного привилегированного режима.
Из-за этого дизайна вы предоставляете защиту системы или песочницу среды выполнения.
Ядро - это кусок кода, который управляет вашим оборудованием и обеспечивает системную абстракцию. Таким образом, он должен иметь доступ ко всем инструкциям машины. И это самая надежная часть программного обеспечения. Так что я должен быть казнен с высшей привилегией. И уровень Кольца 0 - самый привилегированный режим. Поэтому Ring Level 0 также называется Kernel Mode.
Пользовательское приложение - это часть программного обеспечения от сторонних поставщиков, и вы не можете им полностью доверять. Кто-то со злым умыслом может написать код для сбоя вашей системы, если у него был полный доступ ко всем инструкциям машины. Поэтому приложение должно иметь доступ к ограниченному набору инструкций. А Ring Level 3 - наименее привилегированный режим. Таким образом, все ваше приложение работает в этом режиме. Следовательно, уровень 3 звонка также называется режимом пользователя.
Примечание: я не получаю Уровни Кольца 1 и 2. В основном это режимы с промежуточными привилегиями. Так может быть код драйвера устройства выполняется с этой привилегией. AFAIK, linux использует только Ring Level 0 и 3 для выполнения кода ядра и пользовательского приложения соответственно.
Таким образом, любая операция, происходящая в режиме ядра, может рассматриваться как пространство ядра. И любая операция, происходящая в пользовательском режиме, может рассматриваться как пространство пользователя.
Пространство ядра означает, что пространство памяти может быть затронуто только ядром. В 32-битном Linux это 1G(от 0xC0000000 до 0xffffffff в качестве адреса виртуальной памяти). Каждый процесс, создаваемый ядром, также является потоком ядра, поэтому для одного процесса существует два стека: один стек в пользовательском пространстве для этого процесса и другой в ядре место для потока ядра.
стек ядра занимал 2 страницы (8 КБ в 32-битной Linux), включая task_struct(около 1 КБ) и реальный стек (около 7 КБ). Последний используется для хранения некоторых автоматических переменных или параметров вызова функции или адреса функции в функциях ядра. Вот код (Processor.h (linux \ include \ asm-i386)):
#define THREAD_SIZE (2*PAGE_SIZE)
#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
#define free_task_struct(p) free_pages((unsigned long) (p), 1)
__get_free_pages (GFP_KERNEL, 1)) означает выделение памяти как 2^1=2 страницы.
Но стек процессов - это другое дело, его адрес ниже 0xC0000000(32-битный Linux), его размер может быть значительно больше, что используется для вызовов функций из пространства пользователя.
Итак, возникает вопрос: системный вызов работает в пространстве ядра, но вызывается процессом в пользовательском пространстве. Как это работает? Положит ли linux свои параметры и адрес функции в стек ядра или в стек процессов? Решение Linux: все системные вызовы запускаются программным прерыванием INT 0x80. Определено в entry.S (linux\arch\i386\kernel), вот несколько строк, например:
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork)
.long SYMBOL_NAME(sys_read)
.long SYMBOL_NAME(sys_write)
.long SYMBOL_NAME(sys_open) /* 5 */
.long SYMBOL_NAME(sys_close)
Ядро Linux относится ко всему, что работает в режиме ядра и состоит из нескольких отдельных уровней. На нижнем уровне Ядро взаимодействует с оборудованием через HAL. На среднем уровне ядро UNIX разделено на 4 отдельные области. Первая из четырех областей обрабатывает символьные устройства, сырой и приготовленный TTY и обработку терминала. Вторая область управляет драйверами сетевых устройств, протоколами маршрутизации и сокетами. Третья область предназначена для драйверов дисковых устройств, кэшей страниц и буферов, файловой системы, виртуальной памяти, именования и сопоставления файлов. Четвертая и последняя область отвечает за диспетчеризацию, планирование, создание и завершение процессов, а также обработку сигналов. Помимо всего этого у нас есть верхний уровень ядра, который включает системные вызовы, прерывания и прерывания. Этот уровень служит интерфейсом для каждой из функций нижнего уровня. Программист использует различные системные вызовы и прерывания для взаимодействия с функциями операционной системы.
Попытка дать очень упрощенное объяснение
Виртуальная память делится на пространство ядра и пространство пользователя. Пространство ядра - это та область виртуальной памяти, где будут выполняться процессы ядра, а пространство пользователя - это та область виртуальной памяти, где будут выполняться пользовательские процессы.
Это разделение требуется для защиты доступа к памяти.
Всякий раз, когда загрузчик запускает ядро после загрузки его в какое-либо место в ОЗУ (как правило, на контроллере на основе ARM), он должен убедиться, что контроллер находится в режиме супервизора с отключенными FIQ и IRQ.
Эта демаркация нуждается в архитектурной поддержке, есть некоторые инструкции, доступ к которым осуществляется в привилегированном режиме.
В таблицах страниц у нас есть сведения о доступе, если пользовательский процесс попытается получить доступ к адресу, который находится в диапазоне адресов ядра, тогда он выдаст ошибку нарушения привилегий.
Таким образом, для входа в привилегированный режим необходимо запустить инструкцию типа trap, которая меняет режим ЦП на привилегированный и дает доступ к инструкциям, а также к областям памяти.
Правильный ответ: нет такой вещи, как пространство ядра и пространство пользователя. Набор инструкций процессора имеет специальные разрешения для установки таких деструктивных элементов, как корень карты таблицы страниц, доступ к памяти аппаратного устройства и т. Д.
Код ядра имеет привилегии самого высокого уровня, а код пользователя - самый низкий. Это предотвращает сбой системы в коде пользователя, изменение других программ и т. Д.
Обычно код ядра хранится в карте памяти, отличной от кода пользователя (точно так же, как пользовательские пространства хранятся в картах памяти, отличных друг от друга). Отсюда и термины "пространство ядра" и "пространство пользователя". Но это не жесткое и быстрое правило. Например, поскольку x86 косвенно требует, чтобы его обработчики прерываний / прерываний постоянно отображались, часть (или все некоторые ОС) ядра должна отображаться в пространство пользователя. Опять же, это не означает, что такой код имеет пользовательские привилегии.
Зачем нужно ядро / пользовательское разделение? Некоторые дизайнеры не согласны с тем, что это действительно необходимо. Архитектура микроядра основана на идее о том, что секции с наивысшими привилегиями должны быть как можно меньше, при этом все значимые операции выполняются в коде с привилегиями пользователей. Вам нужно изучить, почему это может быть хорошей идеей, это не простая концепция (и она известна как своими преимуществами, так и недостатками).
Получение памяти разделено на две отдельные области:
- Пространство пользователя, которое представляет собой набор мест, в которых выполняются обычные пользовательские процессы (т. Е. Все, кроме ядра). Роль ядра состоит в том, чтобы управлять приложениями, работающими в этом пространстве, не связываясь друг с другом и с машиной.
- Пространство ядра, в котором хранится код ядра и выполняется в нем.
Процессы, выполняющиеся в пространстве пользователя, имеют доступ только к ограниченной части памяти, тогда как ядро имеет доступ ко всей памяти. Процессы, выполняющиеся в пространстве пользователя, также не имеют доступа к пространству ядра. Процессы пользовательского пространства могут получить доступ только к небольшой части ядра через интерфейс, предоставляемый ядром - системные вызовы. Если процесс выполняет системный вызов, в ядро отправляется программное прерывание, которое затем отправляет соответствующий обработчик прерываний и продолжает его работа после того, как обработчик закончил.
В Linux есть два пробела, 1-й - это пространство пользователя, а другой - пространство ядра. Пользовательское пространство состоит только из пользовательского приложения, которое вы хотите запустить. в качестве ядра службы присутствуют управление процессами, управление файлами, обработка сигналов, управление памятью, управление потоками и так много других служб. Если вы запускаете приложение из пользовательского пространства, это приложение взаимодействует только с сервисом Kernal. и эта служба взаимодействует с драйвером устройства, который присутствует между оборудованием и ядром. Основное преимущество пространства ядра и разделения пространства пользователя заключается в том, что мы можем обеспечить защиту с помощью virus.bcaz всех пользовательских приложений, находящихся в пространстве пользователя, а служба присутствует в пространстве ядра. Вот почему Linux не влияет на вирус.