Limitations¶
Debugging another user’s process¶
Sometimes it is necessary to debug a process belonging to another user. Usually, debuggers running with sufficient privileges can attach to another user’s processes. Under UDB this is not the case by default. With default settings, UDB may attach only to processes belonging to the same user as the debugger. It will refuse to attach to processes belonging to another user, even when the debugger is running with sufficient privileges.
Note
Usually, a user with the CAP_PTRACE
capability can attach to any other
process in the system (so long as it is not already being debugged). In most
configurations, this equates with the root
user. These privileges are
still required to attach UDB to another user’s process but are not, by
themselves, adequate.
This behaviour can be overridden by activating permissive communications mode. This mode is disabled by default but can be enabled by setting an environment variable.
Warning
Permissive Communications Mode makes cross-user debugging possible but comes with security implications: it opens communications channels that any process on the system may connect to. It therefore carries a risk of local cross-user exploits.
It is therefore recommended that users avoid Permissive Communications Mode where possible. It is particularly desirable to avoid its use on shared systems. If permissive communications are specifically required (for instance, to fit within an existing debugging workflow on a dedicated system) they can be enabled via a environment variable:
UNDO_permissive_comms=true udb <args>
When starting with permissive comms mode, UDB will display a warning to remind the user of the setting currently in effect:
CAUTION: attaching with permissive comms mode
Record and replay of external device state¶
The Undo Engine works fine with programs that access external device state, and during replay the developer can see a copy of any external device state as far as it impacts the program being recorded. For example, when the program reads from a memory-mapped device, the values that are read are stored in our event log.
In general, a detailed view of the external device state is not necessary in order to be able to debug problems in the software that controls that external device. What matters is the inputs and outputs to the device, for which the Undo Engine gives full visibility.
It’s important to note that the Undo Engine don’t just make a recording of the system events (in the manner of a tool such as strace), but it records the program in a manner that allows the reconstruction of all of the state and events produced by the program at any time in its history, whether or not they interact with the underlying system.
Synchronized debugging¶
The Undo Engine does not allow synchronized debugging between multiple processes at present.
Kernel-space memory¶
The Undo Engine only records user-space memory.
Streamed recording¶
The Undo Engine records to an in-memory event log. Streaming the event log to an external location is not currently implemented, but we hope to address this in the future.
Performance analysis¶
The Undo Engine can tell you about what system calls were executed, and when they were executed. And of course you can set breakpoints on code that handles particular cases. However the Undo Engine only supports user-mode execution, and recording the kernel is not supported.
Finding memory leaks¶
The Undo Engine cannot perform memory leak detection automatically, but it can assist in the process of searching for memory leaks.
For example, you could set a watchpoint in the malloc_chunk
structure
describing an allocated block, and run backwards to find the point where that
data structure was modified, and so discover which code allocated the block.
The Undo Engine also supports debugging code compiled with Clang’s sanitizers such as AddressSanitizer or LeakSanitizer.
Other limitations¶
- CPU features
The x86-64 CPU features 3dnow, 3dnowext, 3dnowprefetch, clwb, hle, mpx, rdseed, and rtm are not supported.
- Exec system call
The
execve
system call is not supported. This is used to implement the standard C library functionsexecl()
,execlp()
,execle()
,execv()
,execvp()
andexecve()
. The program will be stopped if it attempts to issue such a system call.- Forked programs
When a recorded program executes the
clone
syscall to create a new process (for instance, via thefork()
orvfork()
C library functions), the Undo Engine keeps recording the parent process and the child process runs unimpeded without being recorded.This means that, when using the LiveRecorder API, the child (forked) process must call
undolr_start()
to be recorded. live-record and UDB cannot record the child process automatically.SIGKILL
The Undo Engine cannot continue if the program is terminated by
SIGKILL
. The debugging session is terminated immediately in this case.- User-defined command hooks
udb uses “user-defined command hooks” to hook many of GDB’s commands, so these hooks are not available to the user.
- Obscure system calls
Certain rarely used system calls are not supported. The following system calls are either esoteric, or obsolete, and only maintained in the kernel to maintain backwards compatibility with binaries written for early 2.x series kernels:
modify_ldt
,pivot_root
,ssetmask
,unshare
,vm86
.- setrlimit
If the program uses
setrlimit()
to reduce the amount of memory, processes, or other resources that it may consume, then the Undo Engine may not be able to operate properly due to lack of resources.- x86 inter-segment (“far”) jumps/calls
The Undo Engine does not support the use of “far” jumps and calls.
- Cross-memory attach
The Undo Engine does not support programs whose address spaces are written to others using the cross-memory attach facility.
- Self-modifying code
The Undo Engine supports self-modifying code, with two exceptions. First, the Undo Engine caches its translation of the currently executing BB and does not update it until the end of the BB. This means that it does not suport code that modifies instructions and then executes them without an intervening branch or system call. Second, execution of code in shared memory is not supported.
- Shared memory accesses straddling valid and invalid pages
When run natively, an instruction with an operand that straddles a page boundary, such that the first part of the operand is in accessible shared memory, but the second part is in mapped shared memory which is not backed by a valid shared object (for example, because the file which is mapped has been truncated) will get a
SIGBUS
. Under the Undo Engine, such an instruction does not get aSIGBUS
: instead, it reads zeros for the part of the operand in unbacked memory.- Breakpoints when reverse-stepping
The reverse-finish reverse-next, reverse-step and reverse-until commands in udb do not stop at breakpoints, unlike their forward-execution equivalents.
- System call output buffers
When run natively, a system call with an operand that straddles a page boundary, such that the first part of the operand is in accessible memory, but the second part is in inaccessible memory, succeeds if the system call only needs to access the first part of the operand. For example, if a
read()
system call is passed an 8K buffer of which the first 4K is in writable memory, and the second 4K is in non-writable memory, then the system call succeeds if less than 4K is read. Under the Undo Engine, such a system call fails withEFAULT
. The whole buffer must be accessible in order for the system call to succeed.- Adjust Flag
According to the Intel manuals, the state of the Adjust Flag (AF) after some instructions is “undefined”. On some processor models, different executions of the same code can produce different states of AF. If the behavior of a program depends on the state of AF when it is supposed to be undefined, the program may not replay correctly under udb.
SIGCHLD
while attachingIf a
SIGCHLD
arrives for a process while the Undo Engine is in the middle of attaching to the process, theSIGCHLD
may be silently lost. Once the process has been attached,SIGCHLD
is handled normally.