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

gadgets: Add trace_ssl #2745

Merged
merged 1 commit into from
May 29, 2024
Merged

gadgets: Add trace_ssl #2745

merged 1 commit into from
May 29, 2024

Conversation

i-Pear
Copy link
Contributor

@i-Pear i-Pear commented Apr 22, 2024

gadgets: Add trace_ssl

Usage: capture SSL data/latency from OpenSSL, GnuTLS, NSS and libcrypto.

@@ -0,0 +1,247 @@
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) TODO: Apache2?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This gadget and the sslsnoop gadget is modified from the BCC project, which is using Apache2 license. I'm not sure whether using the Apache2 license will cause any problems?

@i-Pear i-Pear force-pushed the sslsniff branch 2 times, most recently from 1f51dbd to cba126c Compare April 22, 2024 16:11
@i-Pear
Copy link
Contributor Author

i-Pear commented Apr 22, 2024

This pull request is updated according to the comments from the sslsnoop PR.

@i-Pear i-Pear force-pushed the sslsniff branch 3 times, most recently from 56e2a4a to a1a281c Compare April 26, 2024 16:09
@alban
Copy link
Member

alban commented Apr 29, 2024

trace_sslsniff and trace_sslsnoop (#2746) are similar. To avoid user confusion, I think there should be only one. There could be a gadget parameter to enable or disable buf.

@i-Pear i-Pear changed the title gadgets: Add trace_sslsniff gadgets: Add trace_ssl Apr 30, 2024
@i-Pear i-Pear force-pushed the sslsniff branch 2 times, most recently from 247b626 to dfeae5e Compare April 30, 2024 17:51
@i-Pear
Copy link
Contributor Author

i-Pear commented Apr 30, 2024

This PR has been merged with sslsnoop. To avoid sending raw buffer to userspace, use ig run trace_ssl:latest --record_data=false.

Copy link
Member

@alban alban left a comment

Choose a reason for hiding this comment

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

Thanks!

gadgets/trace_ssl/artifacthub-pkg.yml Outdated Show resolved Hide resolved
gadgets/trace_ssl/gadget.yaml Outdated Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
Copy link
Member

@alban alban left a comment

Choose a reason for hiding this comment

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

Thanks!

gadgets/trace_ssl/artifacthub-pkg.yml Outdated Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to provide a README.md so the artifacthub page can display it.

It could be done in a following PR.

Comment on lines 145 to 147
mntns_id = gadget_get_mntns_id();
if (gadget_should_discard_mntns_id(mntns_id))
return 0;
Copy link
Member

Choose a reason for hiding this comment

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

I suggest to use gadget_should_discard_mntns_id only in the "enter" probe and not in the "exit" probe.

In most cases, the mntns will not change between "enter" and "exit". And it will be functionally equivalent because one of the bpf_map_lookup_elem below will return 0, so the "exit" probe will not do anything.

However, a container could change mntns between the 2 probes by patching libssl in the container image. The container could even do that without privileges by making use of unprivileged user namespaces. This could cause the maps to get full and the gadget would stop working properly for other containers.

And event->mntns_id could be filled with the mntns_id from the "enter" probe kept in the context map keyed by tid.

This kind of issues exist with uprobes, but in general not with kprobes (unless the kprobe is attached to sys_setns, sys_unshare or sys_clone, equivalent) because userspace code does not have control on the mntns while kernel code is running (multithreaded processes cannot change namespaces of type mount).

Alternatively, you could replace return 0; by goto out; and add the following cleanup code at the end of the function:

out:
    bpf_map_delete_elem(&ssl_bufs, &tid);
    bpf_map_delete_elem(&ssl_starttime, &tid);

Ditto for trace_uretprobe_libssl_SSL_do_handshake and probe_crypto_exit.

cc @mauriciovasquezbernal I think this tip should be in a documentation somewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can understand your concern about security. I'll remove all gadget_should_discard_mntns_id in exit probes, and replace return 0; by goto out;.

Some other ideas:

  • Is this used for writing the correct mntns in events?

And event->mntns_id could be filled with the mntns_id from the "enter" probe kept in the context map keyed by tid.

  • If a process changed its mntns, then all its events will not be traced? Maybe not strict enough in some security-related situations. If we attach to some kprobes which can change processes' mntns, can we still trace those processes with new mntns?

  • What will happen if a process calls clone and changed its tid? For most use cases it doesn't matter, but developers may also think about it.

  • Maybe I can manage to skip the ret-probes? For example, I can write (or patch) some assembly and bypass the "return" symbol. More easily, I think c++'s exception can unwind the stack directly, and bypass the ret-probe. If I do this, I can easily make the ebpf map full.

  • If I patch libssl (it's indeed possible, maybe just mprotect+rw?), will the inode be the same? And will the trace point still be called? In other words, uprobe is "patching" the binary, and if the user is also patching the binary, who will win?

Comment on lines 150 to 151
if (len <= 0) // no data
return 0;
Copy link
Member

Choose a reason for hiding this comment

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

In various error cases, you should still clean up the maps with goto out;:

out:
    bpf_map_delete_elem(&ssl_bufs, &tid);
    bpf_map_delete_elem(&ssl_starttime, &tid);

Ditto for trace_uretprobe_libssl_SSL_do_handshake and probe_crypto_exit.

gadgets/trace_ssl/gadget.yaml Outdated Show resolved Hide resolved
Copy link
Member

@alban alban left a comment

Choose a reason for hiding this comment

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

Thanks!

gadgets/trace_ssl/gadget.yaml Outdated Show resolved Hide resolved
gadgets/trace_ssl/gadget.yaml Outdated Show resolved Hide resolved
Comment on lines 114 to 117
bpf_map_delete_elem(&mntns_context, &tid);
bpf_map_delete_elem(&ssl_starttime, &tid);
bpf_map_delete_elem(&ssl_bufs, &tid);
bpf_map_delete_elem(&crypto_starttime, &tid);
Copy link
Member

Choose a reason for hiding this comment

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

Optional suggestion: we now have several maps indexed by the tid. I think it would be cleaner to have a single map with a struct type as value.

gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
gadgets/trace_ssl/program.bpf.c Outdated Show resolved Hide resolved
bpf_get_current_comm(&event->comm, sizeof(event->comm));

if (!record_data ||
bpf_probe_read_user(&event->buf, buf_copy_size, (char *)*bufp))
Copy link
Member

Choose a reason for hiding this comment

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

I get the following:

Error: starting operator "oci": starting operator "ebpf": creating eBPF collection: program trace_uretprobe_libssl_SSL_write: load program: permission denied: 102: (85) call bpf_probe_read_user#112: R2 unbounded memory access, use 'var &= const' or 'if (var < const)' (133 line(s) omitted)

Copy link
Member

Choose a reason for hiding this comment

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

I got it working with the following:

--- a/gadgets/trace_ssl/program.bpf.c
+++ b/gadgets/trace_ssl/program.bpf.c
@@ -175,9 +175,11 @@ static __always_inline int probe_ssl_rw_exit(struct pt_regs *ctx,
        if (mntns_ptr == 0)
                goto clean;
 
-       buf_copy_size = (size_t)MAX_BUF_SIZE < (size_t)len ?
-                               (size_t)MAX_BUF_SIZE :
-                               (size_t)len;
+       buf_copy_size = len;
+       // MAX_BUF_SIZE is a power of two, so &=MAX_BUF_SIZE-1 makes sure
+       // buf_copy_size does not go above the upper limit
+       buf_copy_size &= MAX_BUF_SIZE-1;
+
        event = gadget_reserve_buf(&events, sizeof(struct event));
        if (!event)
                goto clean;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks strange, it could work on my linux 6.9. Trying to rollback to 6.6

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got the same err message in 6.6, seems it's because the low version of verifier.

Copy link
Contributor Author

@i-Pear i-Pear May 29, 2024

Choose a reason for hiding this comment

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

Although buf_copy_size can be up to MAX_BUF_SIZE, and using MAX_BUF_SIZE - 1 will waste 1 byte, I haven't found a better way to make the 6.6 verifier happy. Let's go with this.

Co-authored-by: Alban Crequy <albancrequy@linux.microsoft.com>
Signed-off-by: Tianyi Liu <i.pear@outlook.com>
Copy link
Member

@alban alban left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@alban alban merged commit d273b1a into inspektor-gadget:main May 29, 2024
57 checks passed
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

2 participants