| Line 85: |
Line 85: |
| | === Executing outside critical section === | | === Executing outside critical section === |
| | | | |
| − | This is the simplest case. Process just have <code>struct rseq</code> registered in the kernel but currently instruction pointer (IP) not inside CS. | + | This is the simplest case. The process has a <code>struct rseq</code> registered with the kernel, but its instruction pointer (IP) is not currently executing within an RSEQ critical section. |
| | | | |
| | ==== Checkpoint ==== | | ==== Checkpoint ==== |
| − | We need only to determine where the <code>struct rseq</code> is and dump its address length and signature.
| + | CRIU only needs to locate the <code>struct rseq</code> instance and record its address, length, and signature. This information is obtained using the ptrace request <code>PTRACE_GET_RSEQ_CONFIGURATION</code> (see the <code>dump_thread_rseq</code> function). |
| − | To achieve that we use special ptrace handle <code>PTRACE_GET_RSEQ_CONFIGURATION</code> (refer to the <code>dump_thread_rseq</code> function).
| |
| | | | |
| | ==== Restore ==== | | ==== Restore ==== |
| − | We need to take data about the <code>struct rseq</code> from the image (see images/rseq.proto) and register it from the parasite context using the <code>rseq</code> syscall (take a look on <code>restore_rseq</code> in criu/pie/restorer.c)
| + | During restore, CRIU retrieves the <code>struct rseq</code> information from the checkpoint image (see images/rseq.proto) and re-register it from the parasite context using the <code>rseq</code> syscall (see <code>restore_rseq</code> in <code>criu/pie/restorer.c</code>). |
| | | | |
| | === Executing inside critical section === | | === Executing inside critical section === |
| Line 129: |
Line 128: |
| | | | |
| | ==== Checkpoint ==== | | ==== Checkpoint ==== |
| − | We need to determine where the <code>struct rseq</code> is and dump its address length and signature.
| + | CRIU locates the <code>struct rseq</code> instance and records its address, length, and signature using the <code>PTRACE_GET_RSEQ_CONFIGURATION</code> ptrace request (see <code>dump_thread_rseq</code>). |
| − | To achieve that we use special ptrace handle <code>PTRACE_GET_RSEQ_CONFIGURATION</code> (refer to the <code>dump_thread_rseq</code> function).
| + | In addition, the instruction pointer is explicitly adjusted to point to the RSEQ abort handler. |
| − | | |
| − | We have to fix up IP to the abort handler.
| |
| | | | |
| | ==== Restore ==== | | ==== Restore ==== |
| − | We need to take data about the <code>struct rseq</code> from the image (see images/rseq.proto) and register it from the parasite context using the <code>rseq</code> syscall (take a look on <code>restore_rseq</code> in criu/pie/restorer.c)
| + | During restore, CRIU reads data about the <code>struct rseq</code> state from the checkpoint image (<code>images/rseq.proto</code>) and re-register it from the restorer context using the <code>rseq</code> system call (see <code>restore_rseq</code> in <code>criu/pie/restorer.c</code>). No further action is required: the process resumes execution at the abort handler, outside of the RSEQ critical section. |
| | | | |
| − | No additional actions here. The process will be restored and will continue execution from the abort handler (not within the rseq CS!).
| + | === Executing inside non-abortable critical section === |
| | | | |
| − | === inside CS: <code>flags</code> is <code>RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL</code> ===
| + | This is a relatively rare case, but it is fully supported by CRIU. When an RSEQ critical section is marked with the <code>RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL</code> flag, it is effectively non-abortable. |
| | + | At first glance, this might suggest that no special handling is required as the RSEQ structure could simply be saved, and the instruction pointer left unchanged. However, this assumption is incorrect. |
| | | | |
| − | Rare case, but we support it too. If the rseq CS has <code>RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL</code> flag it means that its technically
| + | During checkpoint, when CRIU transfers execution to the parasite, the kernel clears the <code>(struct rseq).rseq_cs</code> pointer if it determines that execution is no longer within an rseq critical section: |
| − | non-abortable. So, from the first glance, it seems like we can just not do anything special: save rseq structure address, not fix up IP.
| |
| − | This is incorrect.
| |
| − | | |
| − | The kernel will clean up <code>(struct rseq).rseq_cs</code> pointer once we jump into the parasite on the dump:
| |
| | <pre> | | <pre> |
| | static int rseq_ip_fixup(struct pt_regs *regs) | | static int rseq_ip_fixup(struct pt_regs *regs) |
| Line 160: |
Line 154: |
| | </pre> | | </pre> |
| | | | |
| − | and after the restore process will continue the rseq CS execution from the same place (it's okay) but from the kernel point of view,
| + | As a result, after restore, the process resumes execution at the correct instruction pointer within the critical section, but from the kernel's perspective it is no longer executing inside an RSEQ critical section. This discrepancy is problematic, because the kernel relies on the <code>(struct rseq).rseq_cs</code> field to determine rseq execution context. |
| − | the process will continue this execution as not being within the rseq CS (that's bad!). Because the kernel determines execution context from the <code>(struct rseq).rseq_cs</code> field.
| |
| | | | |
| − | ==== Dump ==== | + | ==== Checkpoint ==== |
| − | We need to determine where the <code>struct rseq</code> is and dump its address length and signature.
| |
| − | To achieve that we use special ptrace handle <code>PTRACE_GET_RSEQ_CONFIGURATION</code> (refer to the <code>dump_thread_rseq</code> function).
| |
| | | | |
| − | We save IP as it was (not doing fixup), but we have to save <code>(struct rseq).rseq_cs</code> field into the CRIU image.
| + | CRIU locates the <code>struct rseq</code> instance and records its address, length, and signature using the <code>PTRACE_GET_RSEQ_CONFIGURATION</code> ptrace request. |
| | + | The instruction pointer is saved without modification, but the <code>(struct rseq).rseq_cs</code> field is also recorded in the CRIU image. |
| | | | |
| | ==== Restore ==== | | ==== Restore ==== |
| − | We need to take data about the <code>struct rseq</code> from the image (see images/rseq.proto) and register it from the parasite context using the <code>rseq</code> syscall (take a look on <code>restore_rseq</code> in criu/pie/restorer.c)
| |
| | | | |
| − | We need to restore <code>(struct rseq).rseq_cs</code> memory externaly using ptrace <code>POKEAREA</code> (see <code>restore_rseq_cs</code>).
| + | During restore, CRIU re-registers the <code>struct rseq</code> from the checkpoint image (<code>images/rseq.proto</code>) using the <code>rseq</code> system call from the restorer context (see <code>restore_rseq</code> in <code>criu/pie/restorer.c</code>). In addition, CRIU explicitly restores the <code>(struct rseq).rseq_cs</code> field using <code>PTRACE_POKEAREA</code> (see <code>restore_rseq_cs</code>) to reestablish the correct <code>rseq</code> execution context in the kernel. |
| | | | |
| | == TODO == | | == TODO == |