Skip to main content

Get the Reddit app

Scan this QR code to download the app now
Or check it out in the app stores
r/eBPF icon
r/eBPF icon

r/eBPF

members
online

Where to ask eBPF-related questions? Where to ask eBPF-related questions?

This subreddit rarely seems to have answers to asked questions (atleast in my experience), StackOverflow is being monitored only by the couple of people who physically don't answer all the questions, and Slack is banned in my country :D. Are there any other places where I can ask an eBPF related question?

Nobody seems to answer my SO question, in case somebody here knows :( https://stackoverflow.com/questions/78816045/can-i-share-ebpf-mmaped-memory-between-root-process-and-other-non-root-process


Inject raw packets Inject raw packets

Hello everyone. I have a question that no one has been able to answer so far.

I simplify the story to be super clear, I have a proxy that I can't edit. I'm on Linux and I want to create a proxy to intercept the packets at IP level, send them to the proxy, waiting for the new packets from the proxy and reinfecting them into the system.

What I have done so far is:

  1. Intercepting packets with ebpf ✅

  2. Sending them to user space with CPU array ✅

  3. Sending them to the proxy ✅

  4. Waiting for the new packets ✅

Now I'm stuck on the last point, I don't figure out how to reinject packets transparently into the system.

Is anyone have some ideas on how to do that?


How can I direct packets from UMEM to the network stack? How can I direct packets from UMEM to the network stack?

I've been following the xdp-tutorial on GitHub to learn about eBPF and AF_XDP. I am curious to notice that while following the tutorial: https://github.com/xdp-project/xdp-tutorial/tree/master/advanced03-AF_XDP, although data is being transferred to the UMEM in user space (af_xdp_user.c) and I am able to get the statistics, but packets are getting dropped after that. I had changed the process_packet function from the tutorial for a simple task, i.e, to count the number of TCP packets received. In addition, I modified the provided BPF program from the tutorial to redirect all packets to the AF_XDP socket instead of every alternate packet. Also, I had attached the BPF program to my network device interface rather than the virtual interface used in the tutorial.

I observe that only a few packets are displayed, and websites do not load during this time. It seems like only initial packets are being processed, with subsequent packets likely being dropped. Hence I am not able to develop a connection to websites while that process runs.

How do I ensure all packets are properly processed and not dropped after transferring to UMEM?


Trayce: "The network tab for your local Docker containers" Trayce: "The network tab for your local Docker containers"

Trayce is an open source desktop application which monitors HTTP(S) traffic to Docker containers on your machine. It uses EBPF to achieve automatic instrumentation and sniffing of TLS-encrypted traffic.

As a backend developer I wanted something which was similar to Wireshark or the Chrome network tab, but which intercepted requests & responses to my containers for debugging in a local dev environment. Wireshark is a great tool but it seems more geared towards lower level networking tasks. When I'm developing APIs or microservices I dont care about packets, I'm only concerned with HTTP requests and their responses. I also didn't want to have to configure a pre-shared master key to intercept TLS, I wanted it to work out-of-the-box.

Trayce is in beta phase so feedback is very welcome, bug reports too. The frontend GUI is written in Python with the QT framework. The TrayceAgent which is what does the intercepting of traffic is written in Go and EBPF. For more details about how it works see this page.



I think I've discovered a bug in ebpf. Can someone help verify? I think I've discovered a bug in ebpf. Can someone help verify?

replace this file xdp-tools/xdp-filter/xdpfilt_prog.h with this content below,
https://pastebin.com/rJiFpKQa
from
https://github.com/xdp-project/xdp-tools

which is supposed to only allow cloudflare ipv4 and ipv6 to pass through but when i run it i get the error:

./xdp-filter load ens3 -p deny
Couldn't attach XDP program on iface 'ens3': Permission denied(-13)

the problem is with the commented out section, if u uncomment it u'll get the error above.

  1. for (int i = 0; i < sizeof(clf_ipv6_ranges) / sizeof(clf_ipv6_ranges[0]); ++i) {

  2. //comment the if line below and it will work.

  3. if (ip_within_ipv6_range(&ipv6hdr->saddr, &clf_ipv6_ranges[i].start, clf_ipv6_ranges[i].cidr)) {

  4. action = XDP_PASS;

  5. goto out;

  6. }

  7. }


Can eBPF be used to determine the PID of the application that created a specific network packet? Can eBPF be used to determine the PID of the application that created a specific network packet?

I am trying to write an eBPF program to be inserted into the POSTROUTING hook of the Linux network stack. This program will identify packets originating from a specific process and block them if they match the criteria, I tried many methods but all fail, I'm a beginner, mainly I try to get the pid using bpf_get_current_pid_tgid, is this helper available for this program type? if not is there another method?

Thanks.



Project worth pursuing? Project worth pursuing?

I have very basic understanding of ebpf, and want to use it for a project. My motivation for learning ebpf is that I understand it can help safely implement kernel level applications without risking what just happened with CrowdStrike.

But personally... I want to write an extremely efficient network clock to sync a metronome for two users computers across a network to try to counteract latency. Whenever two users would use the app, it would spin up a node on a cloud somewhat equidistant in terms of latency between the two users, and shuffle around the clock pulses enough so that both users would receive corrected pulses at a similar time.

Never mind how this would be implemented or used in a greater application for now, I'm just trying to see if this is a decent application of the technology for the time being. The getting started guide for go has an implementation using XDF, is this the path that I should be diving down?




Why does the verifier detect an infinite loop in this code? Why does the verifier detect an infinite loop in this code?

This is my program:

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

struct
{
    __uint(type, BPF_MAP_TYPE_ARRAY);
    __type(key, __u32);
    __type(value, __u64);
    __uint(max_entries, 4);
} pkt_count SEC(".maps");

// count_packets atomically increases a packet counter on every invocation.
SEC("xdp")
int count_packets()
{
    int max = 100;
    for (int i = 0; i < max; i++)
    {
        __u64 *value = bpf_map_lookup_elem(&pkt_count, &i);
        if (!value)
        {
            return 0;
        }
        bpf_printk("%p", value);
    }

    return XDP_PASS;
}

char __license[] SEC("license") = "Dual MIT/GPL";

Why does the verifier detect an infinite loop in this code?

This is the output `bpftool prog load counter_bpfel.o /sys/fs/bpf/my_prog` command prints:

libbpf: prog 'count_packets': BPF program load failed: Invalid argument
libbpf: prog 'count_packets': -- BEGIN PROG LOAD LOG --
; int count_packets()
0: (b7) r6 = 0
; 
1: (63) *(u32 *)(r10 -4) = r6
last_idx 1 first_idx 0
regs=40 stack=0 before 0: (b7) r6 = 0
2: (b7) r7 = 28709
3: (b7) r8 = 99
4: (bf) r2 = r10
5: (07) r2 += -4
; __u64 *value = bpf_map_lookup_elem(&pkt_count, &i);
6: (18) r1 = 0xffff906dfb349e00
8: (85) call bpf_map_lookup_elem#1
; if (!value)
9: (15) if r0 == 0x0 goto pc+16
 R0_w=map_value(id=0,off=0,ks=4,vs=8,imm=0) R6_w=inv0 R7_w=inv28709 R8_w=inv99 R10=fp0 fp-8=mmmm????
; bpf_printk("%p", value);
10: (73) *(u8 *)(r10 -6) = r6
last_idx 10 first_idx 0
regs=40 stack=0 before 9: (15) if r0 == 0x0 goto pc+16
regs=40 stack=0 before 8: (85) call bpf_map_lookup_elem#1
regs=40 stack=0 before 6: (18) r1 = 0xffff906dfb349e00
regs=40 stack=0 before 5: (07) r2 += -4
regs=40 stack=0 before 4: (bf) r2 = r10
regs=40 stack=0 before 3: (b7) r8 = 99
regs=40 stack=0 before 2: (b7) r7 = 28709
regs=40 stack=0 before 1: (63) *(u32 *)(r10 -4) = r6
regs=40 stack=0 before 0: (b7) r6 = 0
11: (6b) *(u16 *)(r10 -8) = r7
12: (bf) r1 = r10
; 
13: (07) r1 += -8
; bpf_printk("%p", value);
14: (b7) r2 = 3
15: (bf) r3 = r0
16: (85) call bpf_trace_printk#6
last_idx 16 first_idx 0
regs=4 stack=0 before 15: (bf) r3 = r0
regs=4 stack=0 before 14: (b7) r2 = 3
; for (int i = 0; i < max; i++)
17: (61) r1 = *(u32 *)(r10 -4)
18: (bf) r2 = r1
19: (07) r2 += 1
; 
20: (63) *(u32 *)(r10 -4) = r2
; for (int i = 0; i < max; i++)
21: (67) r1 <<= 32
22: (c7) r1 s>>= 32
; for (int i = 0; i < max; i++)
23: (6d) if r8 s> r1 goto pc-20

from 23 to 4: R0=inv(id=0) R1_w=inv(id=0,smin_value=-2147483648,smax_value=98) R2_w=inv(id=0,umin_value=1,umax_value=4294967296,var_off=(0x0; 0x1ffffffff)) R6=inv0 R7=inv28709 R8=inv99 R10=fp0 fp-8=mmmm?mmm
; 
4: (bf) r2 = r10
5: (07) r2 += -4
; __u64 *value = bpf_map_lookup_elem(&pkt_count, &i);
6: (18) r1 = 0xffff906dfb349e00
8: (85) call bpf_map_lookup_elem#1
; if (!value)
9: (15) if r0 == 0x0 goto pc+16
 R0_w=map_value(id=0,off=0,ks=4,vs=8,imm=0) R6=inv0 R7=inv28709 R8=inv99 R10=fp0 fp-8=mmmm?mmm
; bpf_printk("%p", value);
10: (73) *(u8 *)(r10 -6) = r6
last_idx 10 first_idx 17
regs=40 stack=0 before 9: (15) if r0 == 0x0 goto pc+16
regs=40 stack=0 before 8: (85) call bpf_map_lookup_elem#1
regs=40 stack=0 before 6: (18) r1 = 0xffff906dfb349e00
regs=40 stack=0 before 5: (07) r2 += -4
regs=40 stack=0 before 4: (bf) r2 = r10
regs=40 stack=0 before 23: (6d) if r8 s> r1 goto pc-20
regs=40 stack=0 before 22: (c7) r1 s>>= 32
regs=40 stack=0 before 21: (67) r1 <<= 32
regs=40 stack=0 before 20: (63) *(u32 *)(r10 -4) = r2
regs=40 stack=0 before 19: (07) r2 += 1
regs=40 stack=0 before 18: (bf) r2 = r1
regs=40 stack=0 before 17: (61) r1 = *(u32 *)(r10 -4)
 R0_w=inv(id=0) R6_rw=invP0 R7_w=inv28709 R8_rw=inv99 R10=fp0 fp-8_r=mmmm?mmm
parent didn't have regs=40 stack=0 marks
last_idx 16 first_idx 0
regs=40 stack=0 before 16: (85) call bpf_trace_printk#6
regs=40 stack=0 before 15: (bf) r3 = r0
regs=40 stack=0 before 14: (b7) r2 = 3
regs=40 stack=0 before 13: (07) r1 += -8
regs=40 stack=0 before 12: (bf) r1 = r10
regs=40 stack=0 before 11: (6b) *(u16 *)(r10 -8) = r7
regs=40 stack=0 before 10: (73) *(u8 *)(r10 -6) = r6
regs=40 stack=0 before 9: (15) if r0 == 0x0 goto pc+16
regs=40 stack=0 before 8: (85) call bpf_map_lookup_elem#1
regs=40 stack=0 before 6: (18) r1 = 0xffff906dfb349e00
regs=40 stack=0 before 5: (07) r2 += -4
regs=40 stack=0 before 4: (bf) r2 = r10
regs=40 stack=0 before 3: (b7) r8 = 99
regs=40 stack=0 before 2: (b7) r7 = 28709
regs=40 stack=0 before 1: (63) *(u32 *)(r10 -4) = r6
regs=40 stack=0 before 0: (b7) r6 = 0
11: (6b) *(u16 *)(r10 -8) = r7
12: (bf) r1 = r10
; 
13: (07) r1 += -8
; bpf_printk("%p", value);
14: (b7) r2 = 3
15: (bf) r3 = r0
16: (85) call bpf_trace_printk#6
last_idx 16 first_idx 17
regs=4 stack=0 before 15: (bf) r3 = r0
regs=4 stack=0 before 14: (b7) r2 = 3
; for (int i = 0; i < max; i++)
infinite loop detected at insn 17
processed 39 insns (limit 1000000) max_states_per_insn 0 total_states 2 peak_states 2 mark_read 1
-- END PROG LOAD LOG --
libbpf: prog 'count_packets': failed to load: -22
libbpf: failed to load object 'counter_bpfel.o'
Error: failed to load object file

Please help me!


Help Needed with eBPF Conformance Test: Understanding Offset Calculations for ldxh and ldxw Operations Help Needed with eBPF Conformance Test: Understanding Offset Calculations for ldxh and ldxw Operations

I'm currently working on an eBPF specification and have encountered some issues due to the lack of documentation. I'm using the conformance tests available in the https://github.com/Alan-Jowett/bpf_conformance/tree/main/tests repository and I'm facing specific difficulties with the subnet test https://github.com/Alan-Jowett/bpf_conformance/tree/main/tests/subnet.data

My main question is about the offset calculation for ldxh and ldxw operations. How are these calculations done and how do they interact with the memory block passed to the program?

In the test, the values loaded into memory by the operations ldxh %r3, [%r1+12], ldxh %r3, [%r1+16], and ldxw %r3, [%r1+16] are 0x0008, 0x3c00, and 0x0201a8c0 respectively. However, the value loaded by the last operation should be 0x0201a8c0 or 0x0101a8c0, given the test result.

What is the justification for the offset in the operation ldxw %r1, [%r1+16] having values of 26 or 30, counting from the beginning of the memory, as per the expected output of the program?

Here is the relevant code from the test:

C

"

include <stdint.h>

define NETMASK 0xffffff00

define SUBNET 0xc0a80100

struct eth_hdr {

uint8_t eth_src[6];

uint8_t eth_dst[6];

uint16_t eth_type;

};

struct vlan_hdr {

uint16_t vlan;

uint16_t eth_type;

};

struct ipv4_hdr {

uint8_t ver_ihl;

uint8_t tos;

uint16_t total_length;

uint16_t id;

uint16_t frag;

uint8_t ttl;

uint8_t proto;

uint16_t csum;

uint32_t src;

uint32_t dst;

};

uint64_t entry(void *mem)

{

struct eth_hdr *eth_hdr = (void *)mem;

uint16_t eth_type;

void *next = eth_hdr;

if (eth_hdr->eth_type == __builtin_bswap16(0x8100)) {

struct vlan_hdr *vlan_hdr = (void *)(eth_hdr + 1);

eth_type = vlan_hdr->eth_type;

next = vlan_hdr + 1;

} else {

eth_type = eth_hdr->eth_type;

next = eth_hdr + 1;

}

if (eth_type == __builtin_bswap16(0x0800)) {

struct ipv4_hdr *ipv4_hdr = next;

if ((ipv4_hdr->dst & __builtin_bswap32(NETMASK)) == __builtin_bswap32(SUBNET)) {

return 1;

}

}

return 0;

}
"

Here is the relevant ASM section and the initial memory:

"

-- asm

mov %r2, 0xe

ldxh %r3, [%r1+12]

jne %r3, 0x81, L1

mov %r2, 0x12

ldxh %r3, [%r1+16]

and %r3, 0xffff

L1:

jne %r3, 0x8, L2

add %r1, %r2

mov %r0, 0x1

ldxw %r1, [%r1+16]

and %r1, 0xffffff

jeq %r1, 0x1a8c0, exit

L2:

mov %r0, 0x0

exit
"

Initial memory:

"

00 00 c0 9f a0 97 00 a0

cc 3b bf fa 08 00 45 10

00 3c 46 3c 40 00 40 06

73 1c c0 a8 01 02 c0 a8

01 01 06 0e 00 17 99 c5

a0 ec 00 00 00 00 a0 02

7d 78 e0 a3 00 00 02 04

05 b4 04 02 08 0a 00 9c

27 24 00 00 00 00 01 03

03 00
"

Expected result: 0x1

Could someone help me understand these calculations and how they affect the test result?




Fooling Port Scanners: Simulating Open Ports with eBPF and Rust Fooling Port Scanners: Simulating Open Ports with eBPF and Rust

🚀 New Blog Post Alert! 🚀

In my previous article, we explored the concept of the three-way handshake and the SYN and accept queues. In this article, we'll combine that knowledge with eBPF to fool port scanners.

Dive into the world of network security with this comprehensive guide on using eBPF and Rust to outsmart port scanners. This article explains the TCP three-way handshake, explores the popular Stealth SYN Scan technique, and demonstrates how to implement an eBPF program that simulates open ports.

Learn how to manipulate network packets at the kernel level, confuse potential attackers, and gain insights into advanced network programming. Perfect for developers looking to enhance their understanding of low-level network interactions and eBPF capabilities.

https://www.kungfudev.com/blog/2024/06/29/fooling-port-scanners-simulating-open-ports-rust-and-ebpf






encrypt/decrypt a packet using eBPF encrypt/decrypt a packet using eBPF

Hi all.

I have a legacy server that I'd rather not rewrite (I can rewrite clients). It communicates over TCP, but it doesn't encrypt its traffic. I would like to write an eBPF program (attach it to tc hooks) that would:

  • intercept outgoing packets, and encrypt them using AES GCM. Note that packet length increases due to addition of tag & IV

  • intercept incoming packets, decrypt and verify tag

Is this possible in eBPF? Can I write a kernel module with a eBPF kfunc that can be called from the tc hook to help do this?

Thanks for reading.


eBPF based NFS Telemetry Exporter for Kubernetes eBPF based NFS Telemetry Exporter for Kubernetes

Hello everyone ...
Lately, I have been working on my latest side project, kube-trace-nfs.

Many cloud providers offer NFS storage, attachable to Kubernetes clusters via CSI. However, storage providers often aggregate data across all NFS client connections, making it hard to isolate and monitor specific operations like reads, writes, and getattrs. This project addresses this by providing detailed telemetry of NFS requests, facilitating node-level and pod-level analysis. Leveraging Prometheus and Grafana, this enables comprehensive analysis of NFS traffic, empowering users with valuable insights into their cluster's NFS interactions.

This can be plugged into kubernetes cluster for monitoring services like AWS EFS, Azure Files, GCP Filestore or any on-premises NFS server setup.

Byte throughput for read/write operations
Latency metrics of read/write/open/getattr operations
Potential for IOPS and file level access metrics

GitHub Repo

Would love any feedback or suggestions, thanks :)

https://preview.redd.it/ebpf-based-nfs-telemetry-exporter-for-kubernetes-v0-vrdxbx266q6d1.png

TLS interception using eBPF TLS interception using eBPF

Hello,

I've been checking lately the posibility of intercepting TLS connections using eBPF.

I've found some good tools on Github and some people trying to do that, but none is working.

My questions are :

1- Is it possible to do so only with eBPF ( without a transparent proxy for example )

2- What tools have you tried or succeeded at using ?

Knowing that my goal is to be able to do it and make a Python script that allows it.

Thank you in advace.



bpf_probe_read_{kernel/user} backports not working with bcc bpf_probe_read_{kernel/user} backports not working with bcc

I'm trying to patch an android kernel 4.9 to support probe_read_{user, kernel} and probe_read_{user, kernel} helpers. For the backporting I took example from another patch that adds bpf_probe_read_str helper. While I've patched the kernel to add the helpers and running bpftrace --info, the str helper shows up but the newly added ones don't.

I'm posting this here since I wonder if it's an issue with my kernel patch.

bpftrace output

System
  OS: Linux 4.9.337-g4fcceb75c5cd #1 SMP PREEMPT Sat May 18 17:26:12 EEST 2024
  Arch: aarch64

Build
  version: v0.19.1
  LLVM: 14.0.6
  unsafe probe: yes
  bfd: no
  libdw (DWARF support): no

libbpf: failed to find valid kernel BTF
Kernel helpers
  probe_read: yes
  probe_read_str: yes
  probe_read_user: no
  probe_read_user_str: no
  probe_read_kernel: no
  probe_read_kernel_str: no
  get_current_cgroup_id: no
  send_signal: no
  override_return: no
  get_boot_ns: no
  dpath: no
  skboutput: no
  get_tai_ns: no
  get_func_ip: no

Kernel features
  Instruction limit: -1
  Loop support: no
  btf: no
  module btf: no
  map batch: no
  uprobe refcount (depends on Build:bcc bpf_attach_uprobe refcount): no

Map types
  hash: yes
  percpu hash: yes
  array: yes
  percpu array: yes
  stack_trace: yes
  perf_event_array: yes
  ringbuf: no

Probe types
  kprobe: yes
  tracepoint: yes
  perf_event: yes
  kfunc: no
  kprobe_multi: no
  raw_tp_special: no
  iter: no

This is the current diff I'm working on

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 744b4763b80e..de94c13b7193 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -559,6 +559,43 @@ enum bpf_func_id {
    */
    BPF_FUNC_probe_read_user,
 
+   /**
+   * int bpf_probe_read_kernel(void *dst, int size, void *src)
+   *     Read a kernel pointer safely.
+   *     Return: 0 on success or negative error
+   */
+   BPF_FUNC_probe_read_kernel,
+
+	/**
+	 * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+	 *     Copy a NUL terminated string from user unsafe address. In case the string
+	 *     length is smaller than size, the target is not padded with further NUL
+	 *     bytes. In case the string length is larger than size, just count-1
+	 *     bytes are copied and the last byte is set to NUL.
+	 *     @dst: destination address
+	 *     @size: maximum number of bytes to copy, including the trailing NUL
+	 *     @unsafe_ptr: unsafe address
+	 *     Return:
+	 *       > 0 length of the string including the trailing NUL on success
+	 *       < 0 error
+	 */
+	BPF_FUNC_probe_read_user_str,
+
+	/**
+	 * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+	 *     Copy a NUL terminated string from unsafe address. In case the string
+	 *     length is smaller than size, the target is not padded with further NUL
+	 *     bytes. In case the string length is larger than size, just count-1
+	 *     bytes are copied and the last byte is set to NUL.
+	 *     @dst: destination address
+	 *     @size: maximum number of bytes to copy, including the trailing NUL
+	 *     @unsafe_ptr: unsafe address
+	 *     Return:
+	 *       > 0 length of the string including the trailing NUL on success
+	 *       < 0 error
+	 */
+	BPF_FUNC_probe_read_kernel_str,
+
 	__BPF_FUNC_MAX_ID,
 };
 
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index a1e37a5d8c88..3478ca744a45 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -94,7 +94,7 @@ static const struct bpf_func_proto bpf_probe_read_proto = {
 	.arg3_type	= ARG_ANYTHING,
 };
 
-BPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size, const void *, unsafe_ptr)
+BPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size, const void  __user *, unsafe_ptr)
 {
 	int ret;
 
@@ -115,6 +115,27 @@ static const struct bpf_func_proto bpf_probe_read_user_proto = {
 };
 
 
+BPF_CALL_3(bpf_probe_read_kernel, void *, dst, u32, size, const void *, unsafe_ptr)
+{
+	int ret;
+
+	ret = probe_kernel_read(dst, unsafe_ptr, size);
+	if (unlikely(ret < 0))
+		memset(dst, 0, size);
+
+	return ret;
+}
+
+static const struct bpf_func_proto bpf_probe_read_kernel_proto = {
+	.func		= bpf_probe_read_kernel,
+	.gpl_only	= true,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_PTR_TO_RAW_STACK,
+	.arg2_type	= ARG_CONST_STACK_SIZE,
+	.arg3_type	= ARG_ANYTHING,
+};
+
+
 BPF_CALL_3(bpf_probe_write_user, void *, unsafe_ptr, const void *, src,
 	   u32, size)
 {
@@ -487,6 +508,69 @@ static const struct bpf_func_proto bpf_probe_read_str_proto = {
 	.arg3_type	= ARG_ANYTHING,
 };
 
+
+
+BPF_CALL_3(bpf_probe_read_user_str, void *, dst, u32, size,
+	   const void __user *, unsafe_ptr)
+{
+	int ret;
+
+	/*
+	 * The strncpy_from_unsafe() call will likely not fill the entire
+	 * buffer, but that's okay in this circumstance as we're probing
+	 * arbitrary memory anyway similar to bpf_probe_read() and might
+	 * as well probe the stack. Thus, memory is explicitly cleared
+	 * only in error case, so that improper users ignoring return
+	 * code altogether don't copy garbage; otherwise length of string
+	 * is returned that can be used for bpf_perf_event_output() et al.
+	 */
+	ret = strncpy_from_unsafe_user(dst, unsafe_ptr, size);
+	if (unlikely(ret < 0))
+		memset(dst, 0, size);
+
+	return ret;
+}
+
+static const struct bpf_func_proto bpf_probe_read_user_str_proto = {
+	.func		= bpf_probe_read_user_str,
+	.gpl_only	= true,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_PTR_TO_RAW_STACK,
+	.arg2_type	= ARG_CONST_STACK_SIZE,
+	.arg3_type	= ARG_ANYTHING,
+};
+
+
+BPF_CALL_3(bpf_probe_read_kernel_str, void *, dst, u32, size,
+	   const void *, unsafe_ptr)
+{
+	int ret;
+
+	/*
+	 * The strncpy_from_unsafe() call will likely not fill the entire
+	 * buffer, but that's okay in this circumstance as we're probing
+	 * arbitrary memory anyway similar to bpf_probe_read() and might
+	 * as well probe the stack. Thus, memory is explicitly cleared
+	 * only in error case, so that improper users ignoring return
+	 * code altogether don't copy garbage; otherwise length of string
+	 * is returned that can be used for bpf_perf_event_output() et al.
+	 */
+	ret = strncpy_from_unsafe(dst, unsafe_ptr, size);
+	if (unlikely(ret < 0))
+		memset(dst, 0, size);
+
+	return ret;
+}
+
+static const struct bpf_func_proto bpf_probe_read_kernel_str_proto = {
+	.func		= bpf_probe_read_kernel_str,
+	.gpl_only	= true,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_PTR_TO_RAW_STACK,
+	.arg2_type	= ARG_CONST_STACK_SIZE,
+	.arg3_type	= ARG_ANYTHING,
+};
+
 static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
 {
 	switch (func_id) {
@@ -500,8 +584,14 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
 		return &bpf_probe_read_proto;
 	case BPF_FUNC_probe_read_user:
 		return &bpf_probe_read_user_proto;
+	case BPF_FUNC_probe_read_kernel:
+		return &bpf_probe_read_kernel_proto;
 	case BPF_FUNC_probe_read_str:
 		return &bpf_probe_read_str_proto;
+	case BPF_FUNC_probe_read_user_str:
+		return &bpf_probe_read_user_str_proto;
+	case BPF_FUNC_probe_read_kernel_str:
+		return &bpf_probe_read_kernel_proto;
 	case BPF_FUNC_ktime_get_ns:
 		return &bpf_ktime_get_ns_proto;
 	case BPF_FUNC_tail_call:
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 155ce25c069d..91d5691288a7 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -522,7 +522,44 @@ enum bpf_func_id {
    *     Return: 0 on success or negative error
    */
    BPF_FUNC_probe_read_user,
+
+   /**
+   * int bpf_probe_read_kernel(void *dst, int size, void *src)
+   *     Read a kernel pointer safely.
+   *     Return: 0 on success or negative error
+   */
+   BPF_FUNC_probe_read_kernel,
 	
+	/**
+	 * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+	 *     Copy a NUL terminated string from user unsafe address. In case the string
+	 *     length is smaller than size, the target is not padded with further NUL
+	 *     bytes. In case the string length is larger than size, just count-1
+	 *     bytes are copied and the last byte is set to NUL.
+	 *     @dst: destination address
+	 *     @size: maximum number of bytes to copy, including the trailing NUL
+	 *     @unsafe_ptr: unsafe address
+	 *     Return:
+	 *       > 0 length of the string including the trailing NUL on success
+	 *       < 0 error
+	 */
+	BPF_FUNC_probe_read_user_str,
+
+	/**
+	 * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+	 *     Copy a NUL terminated string from unsafe address. In case the string
+	 *     length is smaller than size, the target is not padded with further NUL
+	 *     bytes. In case the string length is larger than size, just count-1
+	 *     bytes are copied and the last byte is set to NUL.
+	 *     @dst: destination address
+	 *     @size: maximum number of bytes to copy, including the trailing NUL
+	 *     @unsafe_ptr: unsafe address
+	 *     Return:
+	 *       > 0 length of the string including the trailing NUL on success
+	 *       < 0 error
+	 */
+	BPF_FUNC_probe_read_kernel_str,
+  
   __BPF_FUNC_MAX_ID,
 };

This is also a follow-up of the following patch that adds probe_read_user which now I see it didn't worked either

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 67d7d771a944..744b4763b80e 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -552,6 +552,13 @@ enum bpf_func_id {
 	 */
 	BPF_FUNC_get_socket_uid,
 
+   /**
+   * int bpf_probe_read_user(void *dst, int size, void *src)
+   *     Read a userspace pointer safely.
+   *     Return: 0 on success or negative error
+   */
+   BPF_FUNC_probe_read_user,
+
 	__BPF_FUNC_MAX_ID,
 };
 
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 59182e6d6f51..a1e37a5d8c88 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -94,35 +94,27 @@ static const struct bpf_func_proto bpf_probe_read_proto = {
 	.arg3_type	= ARG_ANYTHING,
 };
 
-BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size, const void *, unsafe_ptr)
+BPF_CALL_3(bpf_probe_read_user, void *, dst, u32, size, const void *, unsafe_ptr)
 {
 	int ret;
 
-	/*
-	 * The strncpy_from_unsafe() call will likely not fill the entire
-	 * buffer, but that's okay in this circumstance as we're probing
-	 * arbitrary memory anyway similar to bpf_probe_read() and might
-	 * as well probe the stack. Thus, memory is explicitly cleared
-	 * only in error case, so that improper users ignoring return
-	 * code altogether don't copy garbage; otherwise length of string
-	 * is returned that can be used for bpf_perf_event_output() et al.
-	 */
-	ret = strncpy_from_unsafe(dst, unsafe_ptr, size);
+	ret = probe_user_read(dst, unsafe_ptr, size);
 	if (unlikely(ret < 0))
 		memset(dst, 0, size);
 
 	return ret;
 }
 
-static const struct bpf_func_proto bpf_probe_read_str_proto = {
-	.func           = bpf_probe_read_str,
-	.gpl_only       = true,
-	.ret_type       = RET_INTEGER,
+static const struct bpf_func_proto bpf_probe_read_user_proto = {
+	.func		= bpf_probe_read_user,
+	.gpl_only	= true,
+	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_PTR_TO_RAW_STACK,
 	.arg2_type	= ARG_CONST_STACK_SIZE,
 	.arg3_type	= ARG_ANYTHING,
 };
 
+
 BPF_CALL_3(bpf_probe_write_user, void *, unsafe_ptr, const void *, src,
 	   u32, size)
 {
@@ -506,6 +498,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
 		return &bpf_map_delete_elem_proto;
 	case BPF_FUNC_probe_read:
 		return &bpf_probe_read_proto;
+	case BPF_FUNC_probe_read_user:
+		return &bpf_probe_read_user_proto;
 	case BPF_FUNC_probe_read_str:
 		return &bpf_probe_read_str_proto;
 	case BPF_FUNC_ktime_get_ns:
@@ -534,8 +528,6 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
 		return &bpf_current_task_under_cgroup_proto;
 	case BPF_FUNC_get_prandom_u32:
 		return &bpf_get_prandom_u32_proto;
-	case BPF_FUNC_probe_read_str:
-		return &bpf_probe_read_str_proto;
 	default:
 		return NULL;
 	}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index a339bea1f4c8..155ce25c069d 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -516,7 +516,14 @@ enum bpf_func_id {
 	 */
 	BPF_FUNC_get_socket_uid,
 
-	__BPF_FUNC_MAX_ID,
+   /**
+   * int bpf_probe_read_user(void *dst, int size, void *src)
+   *     Read a userspace pointer safely.
+   *     Return: 0 on success or negative error
+   */
+   BPF_FUNC_probe_read_user,
+	
+  __BPF_FUNC_MAX_ID,
 };
 
 /* All flags used by eBPF helper functions, placed here. */