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
Use /proc/[pid]/root when looking at /proc/[pid]/maps paths #2324
Use /proc/[pid]/root when looking at /proc/[pid]/maps paths #2324
Conversation
[buildbot, ok to test] |
the test failed due to an infra error. Let us try again. |
[buildbot, test this please] |
@palmtenor any comment for this pull request? |
@vijunag could you take a look as well? |
@palmtenor what do you think about this approach? |
@davemarchevsky related to MATCH_FILENAME, could you have false positives? Or because this is shared library and we should just proceed with library-name-only comparision even with potentially incorrect user full binary path. I do not see any issues with MATCH_FILENAME if user only specifies library name like abbr. |
Agree with @vijunag, but changing path, with NSGuard, we do risk going into a different mount namespace then intended, so this change may require NSGuard becomes noop, right? I have not done any experiments to show this is possible or not. |
I did a little bit experiment. For USDT, suppose that we have If we supply the process ID 123456 and shared binary path displayed by /proc/123456/maps, So we do not need NSGuard at all in such cases? Did I miss anything? |
@yonghong-song I think you are correct in saying that if we have Speaking of "match against":
Definitely. I think the default should be
Is that we could add a match like Another thought I had while doing first pass was matching based on |
Regarding to MATCH_SUBPATH, I am still thinking we can either to full path comparison if user provides one, or bcc just derives the path if user does not supply one. This seems cleaner and less error prone. But I will see your patch first. Could you add some examples to show how it is tested so we can check usability as well? Thanks! |
@davemarchevsky @yonghong-song - Now is the time to eliminate ProcNsGuard() and any other fix is incomplete. What we need now is PrefixGuard() which will prefix the paths according to the process namespace that way we can keep this infra same across USDT/Symlookups. |
Just realized that |
@davemarchevsky Any update on this? |
3c3f4ba
to
5f6df61
Compare
@yonghong-song @vijunag @palmtenor I made some changes to incorporate feedback and added some tests. It might be best to consider this an entirely new PR, solving the same problems outlined in my first post. I will edit the first post to make this more clear. Here's a summary of the changes:
|
[buildbot, test this please] |
@davemarchevsky there are two test failures,
They are legitimate failures. could you take a look. @palmtenor if you get some time, could you take a look as well? |
5f6df61
to
4a8f452
Compare
(rebased, some small additional changes to address rebase conflict, integrating memfd addition) still need to unbreak tests |
[buildbot, test this please] |
1 similar comment
[buildbot, test this please] |
if (bcc_perf_map_path(map_path, sizeof(map_path), pid)) { | ||
mod.name = map_path; | ||
mod.end_addr = -1; | ||
if (callback(&mod, 1, payload) < 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, bcc_perf_map_path
may already deal with /proc/<pid>/root
? So callback function does not need enter_ns
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this was the case as well, but it's doing readlink on /proc/PID/root
and prepending the path of the symlink to the perf map path. Some processes on the hosts I'm working on have /proc/PID/root
symlink resolve to /
, but the inode is not the same as the actual root inode.
When I tried modifying this line to do callback(&mod, 0, payload)
, one of the symcache tests in test_c_api
broke. Think it's necessary to do enter_ns
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, the original code indeed entered mount ns.
int Context::_each_module(const char *modpath, uint64_t, uint64_t, uint64_t,
bool, void *p) {
Context *ctx = static_cast<Context *>(p);
// Modules may be reported multiple times if they contain more than one
// executable region. We are going to parse the ELF on disk anyway, so we
// don't need these duplicates.
if (ctx->modules_.insert(modpath).second /*inserted new?*/) {
ProcMountNSGuard g(ctx->mount_ns_instance_.get());
bcc_elf_foreach_usdt(modpath, _each_probe, p);
}
return 0;
}
If you got some time, could you dig a little more to find out why this is needed? It is puzzling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @palmtenor who may know the answer as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually tricky. You don't always want to go with proc root for reading perf map, since they are often only in root /tmp. I remember we try both (with either global PID or NS PID), but I need to take a better look at the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@palmtenor I think this code is what you are referring to. This PR preserves that functionality.
@@ -273,6 +279,10 @@ std::string Context::resolve_bin_path(const std::string &bin_path) { | |||
::free(which_so); | |||
} | |||
|
|||
if (!result.empty() && pid_) { | |||
result = tfm::format("/proc/%d/root%s", *pid_, result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this true all the time? Or it is just another try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Context
can be initialized without a pid
, and separately from that both bcc_procutils_which
and bcc_procutils_which_so
can fail due to diabolical input. Functions that call Context::resolve_bin_path
rely on its return string to be empty as a signal of "I couldn't find a bin path" so we must only prepend /proc/PID/root
when there's something to prepend to.
All ubuntu failures are same:
fc28 looks more complicated, so going to focus on this first. |
For
This is a test case bug. The probe name should be Could you fix and resubmit the pull request? |
@yonghong-song The |
[buildbot, test this please] |
Only Ubuntu tests were broken because the shared library (w/ USDT) that I added to tests was never actually used in |
[buildbot, test this please] |
@yonghong-song It's finally green. The remaining |
Cools. Thanks! Will do another round of review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Thanks @davemarchevsky for the patience!
BTW can you merge all the commits? Ideally do a rebase -i
and re-order them to fixup
the fixes together with the initial add commit. If it's too much trouble you can just merge them into one.
P.S.: Can you catch me what's with the -1? I got a bit lost there.
a87012c
to
f47fef5
Compare
@palmtenor I squashed down to one commit and pushed. Since the PR got big and messy it was hard to find logical multi-commit split. FYI there were two I'd like to validate that this still fixes the production issue that prompted the PR (since there were lots of minor test-related bugfixes), will update when that's done, day or two at most.
A few places in this PR I do a check: "If we have an actual PID, prepend |
[buildbot, test this please] |
@davemarchevsky sounds good to me for first verifying in production environment. Thanks! |
New CI system seems broken: Last log line in recent Travis CI build says: |
@davemarchevsky do not need to worry Travis CI run for now. There are a different commit trying to address all failures. For your commit, maybe you can rename |
Looks like builtbot has some issues. @drzaeus77 is in the middle of fixing them. |
[buildbot, test this please] |
[buildbot, retest this please] |
[buildbot, test this please] |
This removes the namespace code from libbpf, as they are no longer necessary since iovisor#2324 was merged, and have caused regressions on older Kernels that do not use the new API for creating probes. This also deletes the dead code for namespace handling in libbpf, as this was the last use of it. This also introduces regression tests to ensure that processes in containers can be USDT probed, by adding tests that unshare the mount and process namespaces.
This removes the namespace code from libbpf, as they are no longer necessary since #2324 was merged, and have caused regressions on older Kernels that do not use the new API for creating probes. This also deletes the dead code for namespace handling in libbpf, as this was the last use of it. This also introduces regression tests to ensure that processes in containers can be USDT probed, by adding tests that unshare the mount and process namespaces.
I recently ran into a problem when trying to attach to a USDT in a shared library. Specifically, the shared library was loaded into the address space of a chrooted process. If I just provide the
pid
of this process, initializingUSDT
object fails because all paths in/proc/[pid]/maps
for the target are relative to its chroot, while the process I'm trying to attach from is not in a chroot and therefore the paths don't make sense andUSDT
initialization can't look through shared lib ELFs to find the right probe.Similarly, if I try to initialize the
USDT
object withpid
andbin_path
to the shared lib, initialization succeeds but actually attaching fails: address lookup for the usdt's semaphore inpid
's address space fails because/proc/[pid]/maps
shared lib path is expected to match providedbin_path
exactly, but maps paths are chroot-relative so this doesn't work.Implementation evolved significantly since this PR was created, look at this comment for details about impl.