
Работают модули параллельно с «родной» моделью безопасности Linux — избирательным управлением доступом (Discretionary Access Control, DAC). Проверки LSM вызываются на действия, разрешенные DAC.
Применять механизм LSM можно по-разному. В большинстве случаев это добавление мандатного управления доступом (как, например, в случае с SELinux). Кроме того, можно придумать собственную модель безопасности, реализовать ее в виде модуля и легко внедрить, используя фреймворк. Рассмотрим для примера реализацию модуля, который будет давать права на действия в системе при наличии особого USB-устройства.
Поглядим на схему и попытаемся разобраться, как работает хук LSM (на примере системного вызова open).
Другим словами, LSM дает модулям возможность ответить на вопрос: «Может ли субъект S произвести действие OP над внутренним объектом ядра OBJ?»
Это — очень здорово. Это не sys_call_table хукать по самые указатели.
Разумно для начала написать заготовку модуля безопасности. Он будет очень скромный и будет во всем соглашаться с DAC. Необходимые нам исходники лежат в каталоге security среди исходников ядра.
Копаем исходники
Идем в include/linux/security.h (у меня исходники ядра версии 2.6.39.4). Самое важное здесь – могучая структура security_ops.
Вот её фрагмент:
struct security_operations
{
char name[SECURITY_NAME_MAX + 1];
int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
int (*ptrace_traceme) (struct task_struct *parent);
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
…
};
/**
* register_security – регистрирует модуль безопасности в ядре.
* @ops: указатель на структуру security_options, которая будет
* использоваться.
*
* This function allows a security module to register itself with the
* kernel security subsystem. Some rudimentary checking is done on the @ops
* value passed to this function. You'll need to check first if your LSM
* is allowed to register its @ops by calling security_module_enable(@ops).
*
* Если в ядре уже зарегистрирован модуль безопасности, то вернёт ошибку. При
* успехе вернёт 0.
*/
int __init register_security(struct security_operations *ops)
{
if (verify(ops))
{
printk(KERN_DEBUG "%s could not verify "
"security_operations structure.\n", __func__);
return -EINVAL;
}
if (security_ops != &default_security_ops)
return -EAGAIN;
security_ops = ops;
return 0;
}
obj-m := ptlsm.o
config SECURITY_PTLSM
bool «Positive Protection»
default n
help
This module does nothing in a positive kind of way.
If you are unsure how to answer this question, answer N.
static int ptlsm_inode_create(struct inode *dir, struct dentry *dentry, int mask)
{
if (find_usb_device() != 0)
{
printk(KERN_ALERT "You shall not pass!\n");
return -EACCES;
}
else {
printk(KERN_ALERT "Found supreme USB device\n");
}
return 0;
}
static int find_usb_device(void)
{
struct list_head* buslist;
struct usb_bus* bus;
int retval = -ENODEV;
mutex_lock(&usb_bus_list_lock);
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next)
{
bus = container_of(buslist, struct usb_bus, bus_list);
retval = match_device(bus->root_hub);
if (retval == 0)
{
break;
}
}
mutex_unlock(&usb_bus_list_lock);
return retval;
}
static int match_device(struct usb_device* dev)
{
int retval = -ENODEV;
int child;
if ((dev->descriptor.idVendor == vendor_id) &&
(dev->descriptor.idProduct == product_id))
{
return 0;
}
for (child = 0; child < dev->maxchild; ++child)
{
if (dev->children[child])
{
retval = match_device(dev->children[child]);
if (retval == 0)
{
return retval;
}
}
}
return retval;
}
#include <linux/usb.h>
#include <linux/usb/hcd.h>