Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Dump/restore syscall user dispatch via ptrace #2423

Open
wants to merge 8 commits into
base: criu-dev
Choose a base branch
from

Conversation

svetly-todorov
Copy link

Following up on issue #2037.

Use the PTRACE_GET/SET_SYSCALL_USER_DISPATCH flags upstreamed in kernel 6.4 to preserve SUD settings for a target process.

The majority of the implementation mirrors that of the seccomp dump/restore. The most significant difference is that, unlike seccomp, there's no flag for disabling SUD while a target is being ptraced. Therefore restoring it in the parasite blob is dangerous, because remote syscalls can generate a SIGSYS. Instead, restoration happens right before the final PTRACE_DETACH, and not in the parasite code.

@rst0git
Copy link
Member

rst0git commented Jun 27, 2024

@svetly-todorov Thank you for the pull request! Would you be able to add tests for this feature?


/* Setup SUD-disable struct */
memset(&disable, 0, sizeof(disable));
disable.mode = PR_SYS_DISPATCH_OFF;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#10 2.352 compel/src/lib/ptrace.c:54:17: error: ‘PR_SYS_DISPATCH_OFF’ undeclared (first use in this function)
#10 2.352    54 |  disable.mode = PR_SYS_DISPATCH_OFF;
#10 2.352       |                 ^~~~~~~~~~~~~~~~~~~

Copy link
Author

@svetly-todorov svetly-todorov Jun 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably a case of kernel headers not always being present. I'll go back and explicitly add the #ifdefs to sud.h.

While I'm at it, I'll probably also add some wrappers around the entire SUD architecture, since this only works with newer versions of the kernel, etc.

criu/sud.c Outdated
struct sys_dispatch_entry *entry;
sud_config_t config;

entry = sud_lookup(tid_real, true, false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation is also mixed here.

@svetly-todorov
Copy link
Author

svetly-todorov commented Jun 28, 2024

@rst0git

I'm working on a rebase that adds some bugfixes and addresses the whitespace issues.

We (@gmprice and I) did write a pair of tests for this. Where should they be included?

@rst0git
Copy link
Member

rst0git commented Jun 28, 2024

We (@gmprice and I) did write a pair of tests for this. Where should they be included?

Ideally, the tests should be in a separate commit and it would be great if it is possible to add them in ZDTM. For example, the following commits have been used to add ZDTM tests: 96a30f0, d490218, 516b369.

#undef LOG_PREFIX
#define LOG_PREFIX "sys-dispatch: "

static struct rb_root sud_tid_rb_root = RB_ROOT;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls add more info in the commit message to describe what is going on here.

@avagin
Copy link
Member

avagin commented Jul 2, 2024

The majority of the implementation mirrors that of the seccomp dump/restore. The most significant difference is that, unlike seccomp, there's no flag for disabling SUD while a target is being ptraced. Therefore restoring it in the parasite blob is dangerous, because remote syscalls can generate a SIGSYS. Instead, restoration happens right before the final PTRACE_DETACH, and not in the parasite code.

CRIU injects a parasite blob while a process is being dumped. How do you handle where to place a parasite blob?

@svetly-todorov
Copy link
Author

svetly-todorov commented Jul 2, 2024

The majority of the implementation mirrors that of the seccomp dump/restore. The most significant difference is that, unlike seccomp, there's no flag for disabling SUD while a target is being ptraced. Therefore restoring it in the parasite blob is dangerous, because remote syscalls can generate a SIGSYS. Instead, restoration happens right before the final PTRACE_DETACH, and not in the parasite code.

CRIU injects a parasite blob while a process is being dumped. How do you handle where to place a parasite blob?

@avagin

We don't worry about the parasite blob during dump because we collect and disable SUD during the compel_wait_task that precedes the infection. It's been a while since I wrote this code, but if I'm remembering correctly, collection of SUD entries happens in this callback.

This callback triggers here in compel_wait_task.

The callback is necessary for SUD, but not necessary for seccomp, because ptrace can disable seccomp without overwriting its settings. So for seccomp, you can SUSPEND_SECCOMP during compel_wait_task and then read its settings later. But for SUD, you can only read its settings while it is active; ptrace only lets you enable/disable it without a graceful suspend.

Use the PTRACE_GET/SET_SYSCALL_USER_DISPATCH_CONFIG flags to interface with a tracee's SUD settings.

This is scaffolding for infect and seize, which will use ptrace to collect and suspend the SUD status of a seized task.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
Use the new ptrace wrappers to get the SUD mode of the seized process. If activated, use ptrace_suspend_sud to disable it before proceeding with infection.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
Introduce function signatures for SUD image generation, dump, and restore. These mirror the functions in seccomp.h/.c.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
Add the necessary protobuf descriptions, image descriptions, and magic number for saving SUD data.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
Add hooks for saving SUD status upon infection.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
Add hooks for dumping SUD image to disk during cr-dump.c.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
Add hooks for restoring SUD settings throughout cr-restore.c.

The implementation is a little unorthodox. Unlike seccomp, SUD isn't suspended while a task is under ptrace. So the parasite code cannot restore the SUD settings because SIGSYS may be triggered when the restorer blob is unmapped.
Instead, we opt to reopen the per-core data right before PTRACE_DETACH, and restore the SUD settings then. This way we don't risk triggering SIGSYS via a remote syscall.

Signed-off-by: Svetly Todorov <[email protected]>
Signed-off-by: Gregory Price <[email protected]>
@svetly-todorov
Copy link
Author

svetly-todorov commented Jul 3, 2024

I have pushed up a kind of v2 for this RFC containing some fixes and the beginnings of a test case. CRIU itself should build with the new changes. But the test does not work quite yet. I have to drop development on this for now, because of other work obligations. I may circle back to this in the future. Forgive me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants