1. Field of the Invention
The present invention relates to a method of patching executable code, and more particularly, to a method of hot-swapping, or on-the-fly, patching of executable code during execution.
2. Related Art
The present invention is directed to patching, or changing, of code that is being executed by a processor or processors of a computer. For a number of reasons, it may not be possible or desirable to stop the computer or some running programs in order to reload the updated, or changed, or “patched” code. This may be due to the fact that an application running on the computer is of a critical nature, or due to any number of other factors that make it undesirable to stop the computer in order to change the behavior of the code.
One example of a need for a patch may be a function call by the operating system (OS) that calculates disk quota allocation. If a proprietary OS file system does not support disk quotas and an OS vendor cannot provide that option, a way needs to be found to implement disk quotas as a modification of current OS programs/drivers.
Another example is a change in the code of the operating system itself. The operating system may be one that is running on a server that supports multiple users and multiple applications, such that stopping the applications and the user access to the server in order to reload the OS may be undesirable or unacceptable. Thus, it may be necessary to change the code of the operating system, or some aspect of the operating system, on-the-fly, without stopping the user processes.
Another example of such a patch may be enhancement of security of the operating system that needs to be loaded on the fly. Another example is an upgrade of the operating system to a new version. Yet another example is an upgrade to a driver for a peripheral device, addition of a driver for a new peripheral that was previously not supported by the operating system. Other examples include modifications of critical applications.
The conventional way of patching code is relatively risky. A “direct” method of patching the code involves simply substituting new instructions for the original instructions, without regard to whether or not this particular piece of code is being executed. The outcome can be unpredictable, since, in the case of that instruction being executed, the processor may receive unexpected input or incomplete instructions, potentially resulting in an application crash or a system crash. In a multi-tasking environment, such a crash can occur because a particular process only has CPU resources for a certain time slice, and hands the CPU resources over to another process during the next time slice.
In the context of multi-tasking, in a single processor system, one process runs for a time slice, then that process is suspended, until another process (or several other processes) finish running. At some time slice in the future, the original process resumes execution. Normally, the operating system manages the multi-tasking aspect. Each process, at the time of its suspension, has a set of parameters that include, for example, the address of the code being executed to which the process needs to return upon resumption, the state of certain parameters, registers, stack contents, etc. This is sometimes referred to as the “execution context.” The execution context needs to be stored somewhere to enable the process to resume, after suspension.
The address of the instruction to which the process needs to return upon resumption is one of the execution context parameters. If that instruction is in the process of being replaced at the moment that the process returns to that instruction for resumption, the outcome is unpredictable, and may result in program crash. Furthermore, the length of the old instruction (in bytes) and the length of the new (patched) instruction may not be the same. Thus, where the processor, for example, expected a return point to a beginning of an instruction, it is now executing in the middle of patched instruction, further increasing the possibility of a program crash.
The above situation is compounded for a multi-processor system. There, it is even more likely that one processor can make changes to the code while another processor is at the same time executing the same code. Thus, the processor that executes the code suddenly finds itself executing something it did not expect, or something that the writer creator did not intend.
In other words, in a conventional method, there is no guarantee that the substitution (or the patching) of the code will actually be performed correctly, with failure rates as high as 20% or 25%, depending on the operating system and the processor configuration.
A number of conventional methods exist for “safe” installation of patched code:
1. An “external patch” refers to changing the binary code in the executable file. The advantage of this method is that there is no need to implement patching of the code on the fly. The disadvantage is that it may take some time, may require reloading of the code into memory while stopping the processes being run, and may be forbidden by the software licensing agreement.
2. Another method is to simply replace the first byte of any function that is being modified by an interrupt instruction, e.g., a 1-byte instruction INT3 (0xCC) in Intel processors with 32-bit architecture. The advantage of this is that it is the simplest method of patch installation. The disadvantage is that every time the function is called, there is an interrupt. This causes substantial additional overhead.
3. A third method is a “synchronization” method. In this method, all the threads (except the patching thread) are suspended. Upon verification that all of the threads are out of the “danger zone,” the first five bytes of the function are modified with a jump to the patching instructions. The advantage of this method is that it avoids the complications of having to install a patch on the fly. The disadvantage of this approach is that it is difficult to ensure the necessary conditions—in other words, that all the threads are actually suspended, rather than merely waiting for user input. Also, suspending all the threads except the patching thread effectively results in a suspension of all useful processor activity, which may be unacceptable for critical applications.
Accordingly, there exists a need for a method of on-the-fly patching of executable code that has predictable results and avoids application program failures or system crashes.