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

bcc: Use bpf_probe_read_user in tools and provide backward compatibility #2866

Conversation

sumanthkorikkar
Copy link
Contributor

@sumanthkorikkar sumanthkorikkar commented Apr 7, 2020

Hi @yonghong-song, @brendangregg, @4ast, all

[RFC 0/1] Support bpf_probe_read_user in bcc tools

bcc tracks the function arg pointers and then converts the pointer
deferences (both user and kernel pointer) into the bpf_probe_read().
However this is not valid for architecture which has overlapping address
space. To overcome this issue, the bpf_probe_read_{user/kernel} variant
was introduced.

Few Feasible solution for separation of user probe read and the kernel
probe read:

Approach 1 (temporary approach):

  1. Explicitly use bpf_probe_read_user() for copying the user-space var
    into the ebpf stack. Like kernel/bpf/samples/.
  • Make changes in the tools and examples.
  • For backward compatibility, when kernel version < 5.5, convert
    bpf_probe_read_user call to bpf_probe_read(). Atleast the tools are
    valid for architecture which supports it.

Approach 2
2. Mark certain pointer as user and then track it while visiting AST
nodes in cases like return, callexp, binop, assignment etc.. I am yet
to try this and see how this can be performed

Let me know, your suggestions for approach 1, approach 2 or any other good approaches. Thank you

The first approach rfc is added below.

Best Regards
Sumanth

@sumanthkorikkar sumanthkorikkar changed the title bcc: Use bpf_probe_read_user in tools and provide backward compability bcc: Use bpf_probe_read_user in tools and provide backward compatibility Apr 7, 2020
@yonghong-song
Copy link
Collaborator

Thanks! The patch looks good. I think approach 1 is practical for now. approach 2 is more involved. In kernel, __user is represented as address_space attribute and clang has pretty strict support for address_space attribute. I have a pending patch https://reviews.llvm.org/D69393 in clang to get better support for kernel with turning these __user marking etc. for compiler, no progress yet as it needs quite a lot of compiler work. Please comment if you have some thoughts.

@sumanthkorikkar
Copy link
Contributor Author

sumanthkorikkar commented Apr 13, 2020

Thanks! The patch looks good. I think approach 1 is practical for now. approach 2 is more involved. In kernel, __user is represented as address_space attribute and clang has pretty strict support for address_space attribute. I have a pending patch https://reviews.llvm.org/D69393 in clang to get better support for kernel with turning these __user marking etc. for compiler, no progress yet as it needs quite a lot of compiler work. Please comment if you have some thoughts.

Hi @yonghong-song ,

Thank you. For now, I will take the first approach and make necessary changes in the tools examples and send it.

Question - 2nd approach:

  1. Could we do something like the following ?:
  • Add the clang attribute __userptr, which is just a marker.
    • bcc program marks certain function arg pointer as __userptr.
      • bcc should then track this func arg ptr state in various assignments .
    • We dont really depend upon kernel __user attribute.
    • May be we dont need debug info in this case, which can be an advantage
    • However care should be taken by the bcc programmer in marking those appropriately, which is a disadvantage

@yonghong-song
Copy link
Collaborator

Thanks! The patch looks good. I think approach 1 is practical for now. approach 2 is more involved. In kernel, __user is represented as address_space attribute and clang has pretty strict support for address_space attribute. I have a pending patch https://reviews.llvm.org/D69393 in clang to get better support for kernel with turning these __user marking etc. for compiler, no progress yet as it needs quite a lot of compiler work. Please comment if you have some thoughts.

Hi @yonghong-song ,

Thank you. For now, I will take the first approach and make necessary changes in the tools examples and send it.

Question - 2nd approach:

1. Could we do something like the following ?:


* Add the clang attribute __userptr, which is just a marker.
  
  * bcc program marks certain function arg pointer as __userptr.
    
    * bcc should then track this func arg ptr state in various assignments .
  * We dont really depend upon kernel __user attribute.
  * May be we dont need debug info in this case, which can be an advantage
  * However care should be taken by the bcc programmer in marking those appropriately, which is a disadvantage

This should work. bcc could rewrite with proprer version of bpf_probe_read based on whether the attribute available or not. Not sure whether it is worthwhile or not since (1). we have a reasonable workaround (your apporach 1), (2). long term we still want clang can provide proper information with __user annotation, (3). we only limited cases (a few syscall's or a few calls close to syscalls). But thanks for suggestion, will continue to monitor situation.

@sumanthkorikkar
Copy link
Contributor Author

Ok. Thank you. I made changes to the tools using approach 1. Currently testing it and I will update it here.

@sumanthkorikkar sumanthkorikkar force-pushed the draft_bpf_probe_read_user_approach1 branch from f1ab2e5 to bd9bb44 Compare April 21, 2020 20:15
@yonghong-song
Copy link
Collaborator

Could you rebase on top of master? In the diff, there are a lot of libbpf submodule changes.

s390 has overlapping address space for user and kernel. Hence separation of
bpf_probe_read_user and bpf_probe_read_kernel is essential. Commit 6ae08ae3dea2
("bpf: Add probe_read_{user, kernel} and probe_read_{user, kernel}_str
helpers") introduced these changes into the kernel. However, bcc tools does not
respect it.

As a workaround, perform the following:
1. Use bpf_probe_read_user() explicitly in the bcc tools.
2. When kernel version < 5.5, perform the checks if the
   bpf_probe_read_user kernel helper is present in the backported kernel
   as well. If not found, then fallback from bpf_probe_read_user to
   bpf_probe_read.

Signed-off-by: Sumanth Korikkar <[email protected]>
1. Commit fa697140f9a2 ("syscalls/x86: Use 'struct pt_regs' based
   syscall calling convention for 64-bit syscalls") changed the raw
   parameter passed to the syscall entry function from a list of
   parameters supplied in user space to a single `pt_regs *` parameter
   (ARCH_HAS_SYSCALL_WRAPPER)

2. But ARCH_HAS_SYSCALL_WRAPPER in s390 is not used for that purpose.
   See commit a18f03cd89e9 ("s390: autogenerate compat syscall
   wrappers")

3. Use direct parameter assignment assumption for s390 syscall probe
   instead.

Signed-off-by: Sumanth Korikkar <[email protected]>
This is essential for architecture which do have overlapping address space.
- bpf_probe_read_kernel() shall be used for reading data from kernel space
to the bpf vm.
- bpf_probe_read_user() shall be used for reading data from user space
  to the bpf vm.

Signed-off-by: Sumanth Korikkar <[email protected]>
@sumanthkorikkar
Copy link
Contributor Author

sumanthkorikkar commented Apr 23, 2020

  1. Two more changes needed in trace.py and argdist.py. I will do it another commit.
  • tools/argdist.py -C 'p::do_sys_open(int dfd, const char __user filename, int flags, umode_t mode):char:filename'
    • This should be converted to bpf_probe_read_user() while reading the strings. Same applies for every uprobes
  • tools/argdist.py -C 'p::someinternalkernelfunc(char filename):char:filename'
    • This should be converted to bpf_probe_read() while reading the strings.
  1. @yonghong-song , Another thing, Do I also need to make bpf_probe_read_user changes in tools/old/ ?

@sumanthkorikkar
Copy link
Contributor Author

Could you rebase on top of master? In the diff, there are a lot of libbpf submodule changes.

Ok. Thank you

@yonghong-song
Copy link
Collaborator

1. Two more changes needed in trace.py and argdist.py. I will do it another commit.


* tools/argdist.py -C 'p::do_sys_open(int dfd, const char __user _filename, int flags, umode_t mode):char_:filename'
  
  * This should be converted to bpf_probe_read_user() while reading the strings. Same applies  for every uprobes

* tools/argdist.py -C 'p::someinternalkernelfunc(char _filename):char_:filename'
  
  * This should be converted to bpf_probe_read() while reading the strings.


1. @yonghong-song , Another thing, Do I also need to make bpf_probe_read_user changes in tools/old/ ?

for tools/old/ change, no. They are for old kernels which do not have bpf_probe_read_user() anyway. Thanks for the patch!

@yonghong-song
Copy link
Collaborator

[buildbot, test this please]

@yonghong-song
Copy link
Collaborator

[buildbot, ok to test]

@sumanthkorikkar
Copy link
Contributor Author

sumanthkorikkar commented Apr 25, 2020

I have also modified trace.py and argdist.py to support bpf_probe_read_user. I will create a separate pull request for trace.py/argdist.py soon after ample testing.

@yonghong-song yonghong-song merged commit f4302f3 into iovisor:master Apr 28, 2020
@yonghong-song
Copy link
Collaborator

I have also modified trace.py and argdist.py to support bpf_probe_read_user. I will create a separate pull request for trace.py/argdist.py soon after ample testing.

Thanks!

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