How to make Linux kernel from Windows?

    Practical experience in developing overhead protection

    We are starting to publish a series of practical articles devoted to particular issues of implementing imposed security features, namely, embedding in software systems. Using the Linux kernel as an example , we will consider the methods and tools used to modify, expand and complement its functionality.

    The first article will be an introduction with a brief overview of key embedding methods. Further, we will take a closer look at the individual embedding methods, paying attention to the technical details.

    Security Approaches

    In accordance with generally accepted practice, a model including categories of confidentiality, integrity and accessibility is used as a standard information security model. At the same time, protected systems are understood to mean systems on which the functions of implementing this model are assigned. Being the basic element of such a system, the core of the operating system (OS) plays a crucial role in the process of ensuring information security, therefore, issues of increasing its security are given a primary role.

    There are two approaches to building security features: built-in tools and cash on hand. Embedded tools are characterized by the initial presence in the protected system, while the imposed funds are introduced into the protected system during its operation, before its operation.

    Each approach has its own strengths and weaknesses that determine the limits of applicability. Often the strength of one approach is the vulnerability of another. So, the advantages of the built-in security features include the lack of the need to verify the authenticity of the protected system; this is also a disadvantage of the overlay - how to determine that the protected is authentic? On the other hand, the integration of an embedded security tool into a protected system carries with it a limitation on the choice of a supplier of operating system components and the security tool itself. This problem is especially acute in the Russian market, where the certification of systems plays an important role, and the built-in protective equipment does not always meet the requirements defined by the regulators (see the requirements of the FSTEC of Russia).

    The goals and objectives of embedding in software systems

    Like any software system, the core of the operating system is a set of interconnected software modules (components) that form a common computing system. The implementation of the imposed protection tool for the OS kernel, and in particular the Linux kernel, implies the need to integrate it into the operating mechanisms of its subsystems. At the same time, embedding is understood as the process of introducing additional (third-party) program elements, carried out in such a way that, on the one hand, the functioning of the system itself is preserved, and on the other, its functionality is expanded or changed.

    Speaking of embedding, we will consider the following practical problem. Let there be some target component of a software system that functions in accordance with a given (basic) algorithm. It is necessary to modify the operation of this component in such a way as to be able to make specific changes to this basic algorithm.

    Thus, the main purpose of embedding is to obtain the ability to control, modify and expand the functions of the components of the software system, while the main objective of embedding is to ensure implementation in the existing software system while maintaining its operability. Successfully completed embedding is characterized by maintaining the functioning of the software system in the presence of a new component in its composition.
    Being the central part of modern software systems, the OS kernel acts as an intermediary between applications and devices that process data at the hardware level. At the same time, its main task is effective resource management.

    About embedding Linux in the kernel

    By its architecture, the Linux kernel is a monolithic kernel with support for expanding functionality through modules, which are loaded as needed during operation. Given this feature, it is possible for the Linux kernel to develop extensions that, in fact being part of the kernel, can override / complement its various functions, i.e. actually change the order of its subsystems.

    Considering the components of software systems as various kinds of application and system programs running on the corresponding equipment, it is possible to establish a connection between embedding and gaining the ability to intercept control during the execution of sections of these programs. In this case, the program code that handles such situations is called an interceptor code or, more simply, a hook (English, hooking). The terms interception (control) and embedding themselves are considered to be similar and, if this is not specified separately, are used to mean the same thing. However, one should keep in mind the existing difference between them: embedding is a process of implementation in a general sense, while interception rather indicates a specific methodological technique.

    A distinctive feature of dynamic embedding methods is that there is no need to reboot the target system in order for the expected changes to take effect. As a rule, the objects of interception are functions - elements of the kernel code that implement one or another algorithm. Less often, embedding occurs in such system mechanisms as exception handlers and, in particular, the system call manager.

    Interception of kernel functions is a basic method that allows you to redefine / complement its various mechanisms. Based on the fact that the Linux kernel is almost completely written in C, with the exception of small architecture-dependent parts, it can be argued that for embedding into most of the kernel components it is enough to be able to intercept the corresponding functions.

    Exception handling underlies the functioning of many system mechanisms. As a result, intercepting the Linux kernel exception handlers allows you to increase the degree of control over the system, and intercepting the system call manager makes it possible to regulate application software requests to Linux kernel services.

    Traditional embedding methods are based on patching (engl., Patching) - a technique for making changes to code or data that allows you to modify the behavior of the target algorithm in the desired way. Technically, the result of patching is to change the contents of cells in RAM. However, code modification, in contrast to data modification, has its own peculiarities associated primarily with the fundamental difference between code and data.
    The implementation of interception using the patch technique requires qualifications, as well as an understanding of the operating principles of not only the core itself, but also the features of the used hardware platform. When modifying the code, it is worth paying special attention to the correctness of embedding in the case of multiprocessor systems, because as a result of changes, coherence should not be violated. In addition, it is necessary to take into account the need to bypass the mechanisms for protecting the kernel code from modification, as well as the features of the search and use of hidden and not exported characters. One way or another, in most cases, patching solves the embedding problem.

    The disadvantage of patch can be considered a necessary violation of the integrity of the components of the target system. Changes to the code can be easily detected, which in some contexts is a fundamental limitation. An example of this kind of restriction is, in particular, the kernel protection mechanism of the Windows OS - Kernel Patch Protection , better known as PatchGuard. One of its features is the implementation of integrity control of key components of the OS kernel, which negates most standard embedding methods based on code modifications. At the same time, disabling this tool for installing the overlay is an extreme option, because in the absence of duplicate functionality in the embedded security feature, the overall security of the system is obviously reduced.

    To implement embedding while maintaining the integrity of the target components, you should use methods devoid of this kind of restrictions. As a rule, some of these methods use the hardware capabilities of the platform (for example, hardware breakpoints), which in principle cannot be universal, given at least the restrictions on the number of set intercepts. On the other hand, there always remains the possibility of using various kinds of virtual functions and other dynamically replaced pointers, which allow redefining the behavior of the system within certain limits. The latter, in particular, is common for intercepting operations carried out within the framework of a virtual file system ( VFS), when tables of virtual methods are used for operations with objects, the replacement of which can be performed without modifying the code. However, this approach also has a number of limitations, the main of which is that there is no way to control what is not provided for.


    Thus, for embedding into the kernel of the OS, there are methods whose use in relation to a specific task is more or less appropriate. Patching is a basic embedding method and may be applicable if there are no restrictions on maintaining integrity (code). Otherwise, depending on the situation, architecture-specific solutions (such as using hardware breakpoints), overloading virtual functions, and other methods may be applied.

    One way or another, the implementation of embedding into the kernel allows you to modify the logic of the operation of its components, and at the same time increase the degree of its security by embedding mesanisms intended for this purpose.

    In the next article, we will examine in detail one of the most common embedding methods - the method of intercepting kernel functions.

    Also popular now: