Linux Security Modules (LSM) is a framework that adds support for various security models to Linux. LSM has been part of the kernel since Linux version 2.6. Currently, SELinux, AppArmor, Tomoyo and Smack security modules inhabit the official kernel.
The modules work in parallel with the native Linux security model - Discretionary Access Control (DAC). LSM checks are invoked for actions allowed by the DAC.
The LSM mechanism can be applied in different ways. In most cases, this is the addition of mandatory access control (as in the case of SELinux, for example). In addition, you can create your own security model, implement it as a module and easily implement it using the framework. Consider for example the implementation of a module that will give rights to actions in the system in the presence of a special USB device.
')
Let's look at the scheme and try to figure out how the LSM hook works (using the open system call example).

Nothing complicated. The main task of LSM is to provide security modules with a mechanism for controlling access to kernel objects (hooks are inserted into the kernel code right before object calls). Before the kernel accesses an internal object, the verification function provided by the LSM will necessarily be called.
In other words, LSM gives modules the opportunity to answer the question: “Can subject S perform an OP action on an internal OBJ core object?”
It's great. This is not a sys_call_table hooked by the most pointers.
It is reasonable to start by writing a blank security module. He will be very modest and will agree with the DAC in everything. The sources we need are in the security directory among the kernel sources.
Digging the source
Go to include / linux / security.h (I have the source code for version 2.6.39.4 of the kernel). The most important thing here is the powerful structure of security_ops.
Here is a fragment of it:
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); … };
This is a list of predefined and documented callback functions that are available to a security module for performing checks. By default, these functions mostly return 0, thereby allowing any actions. But some use the POSIX security module. These are Common Capabilities functions, they can be found in the file security / commoncap.c.
In this case, the following function from include / linux / security.c is important to us:
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; }
We write preparation
I have the BackTrack 5 R1 distribution kit at hand (kernel version 2.6.39.4). Take a look at a ready-made security module, for example, SELinux (directory / security / selinux /). Its main mechanism is described in the hooks.c file. Based on this file, I created the skeleton of a new security module (we will later make something interesting out of it).
The monstrous security_ops structure is filled with pointers to its functions. For this, it is enough for all functions to replace selinux with the name of their module (PtLSM in my example). Editing the bodies of all functions: returning void is empty, int should return 0. As a result, nothing is done that does LSM, allowing everything that the “native” defense mechanism allows. (Module source code:
pastebin.com/Cst0VVQh ).
A small sad retreat. Starting from version 2.6.24, for security reasons, the kernel has stopped exporting the symbols necessary for writing security modules as loadable kernel modules (Linux Kernel Module, LKM). For example, the register_security function, which allows you to register a module and its hooks, has disappeared from export. Therefore, we will build the kernel with our module.
Create a directory with the name of the PtLSM module: /usr/src/linux-2.6.39.4/security/ptlsm/.
To build the module perform the following steps.
1. Create a Makefile:
obj-m: = ptlsm.o
2. Create a Kconfig file:
config SECURITY_PTLSM
bool "Positive Protection"
default n
help
This is a module.
If you are unsure.
3. Edit / security / Makefile and / security / Kconfig - so that the whole world will know about the new module. Add lines - like other modules.
My files with PtLSM added:
1) Makefile -
pastebin.com/k7amsnQK2) Kconfig -
pastebin.com/YDsPBGAzNext, in the directory with the kernel sources, we make make menuconfig, select PtLSM in the “Security Options” item.

Now make, make modules_install, make install. The module is placed in the kernel, and with the help of the dmesg utility you can see what it is writing to the log.
Writing a super cool module
It's time to make our module super cool! Let the module prohibit doing anything on the computer if a USB device with the specified Vendor ID and Product ID is not connected to it (in my example it will be the Galaxy S II phone ID).

I changed the body of the ptlsm_inode_create function, which checks whether a process has the ability to create files. If the function has found a “device of higher authority”, it will give permission for execution. Similar checks can be performed with any other actions.
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; }
Now it would be nice to write the find_usb_device function. It will analyze all USB devices in the system and find the one that has the desired ID. Data on USB devices is stored in the form of trees whose roots are called root hub device. The list of all roots is in the usb_bus_list tire list.
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; }
And finally, the match_device function that checks the Vendor ID and Product ID.
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; }
To work with USB connect a couple of headers.
#include <linux/usb.h> #include <linux/usb/hcd.h>
Repeat the steps to insert the module - and buy a cool phone to use the computer.
