diff --git a/control/control_plane.go b/control/control_plane.go index 3967489..daba4f6 100644 --- a/control/control_plane.go +++ b/control/control_plane.go @@ -198,15 +198,31 @@ retryLoadBpf: _ = core.Close() } }() - // Bind to links. Binding should be advance of dialerGroups to avoid un-routable old connection. - for _, ifname := range lanInterface { - if err = core.bindLan(ifname); err != nil { - return nil, fmt.Errorf("bindLan: %v: %w", ifname, err) + /// Bind to links. Binding should be advance of dialerGroups to avoid un-routable old connection. + // Add clsact qdisc + for _, ifname := range common.Deduplicate(append(append([]string{}, lanInterface...), wanInterface...)) { + _ = core.addQdisc(ifname) + } + // Bind to LAN + if len(lanInterface) > 0 { + if err = core.setupRoutingPolicy(); err != nil { + return nil, err + } + for _, ifname := range lanInterface { + if err = core.bindLan(ifname); err != nil { + return nil, fmt.Errorf("bindLan: %v: %w", ifname, err) + } } } - for _, ifname := range wanInterface { - if err = core.bindWan(ifname); err != nil { - return nil, fmt.Errorf("bindWan: %v: %w", ifname, err) + // Bind to WAN + if len(wanInterface) > 0 { + if err = core.setupSkPidMonitor(); err != nil { + return nil, err + } + for _, ifname := range wanInterface { + if err = core.bindWan(ifname); err != nil { + return nil, fmt.Errorf("bindWan: %v: %w", ifname, err) + } } } diff --git a/control/control_plane_core.go b/control/control_plane_core.go index df6b312..bc6db97 100644 --- a/control/control_plane_core.go +++ b/control/control_plane_core.go @@ -12,15 +12,14 @@ import ( ciliumLink "github.com/cilium/ebpf/link" "github.com/safchain/ethtool" "github.com/sirupsen/logrus" - "github.com/v2rayA/dae/common" "github.com/v2rayA/dae/common/consts" internal "github.com/v2rayA/dae/pkg/ebpf_internal" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" - "net/netip" "os" "os/exec" "regexp" + "strings" ) type ControlPlaneCore struct { @@ -47,39 +46,6 @@ func (c *ControlPlaneCore) Close() (err error) { } func getIfParamsFromLink(link netlink.Link) (ifParams bpfIfParams, err error) { - // TODO: We should monitor IP change of the link. - ipnets, err := netlink.AddrList(link, netlink.FAMILY_ALL) - if err != nil { - return bpfIfParams{}, err - } - if len(ipnets) == 0 { - return bpfIfParams{}, fmt.Errorf("interface %v has no ip", link.Attrs().Name) - } - // Get first Ip4 and Ip6. - for _, ipnet := range ipnets { - ip, ok := netip.AddrFromSlice(ipnet.IP) - if !ok { - continue - } - if ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() { - continue - } - if (ip.Is6() && ifParams.HasIp6) || - (ip.Is4() && ifParams.HasIp4) { - continue - } - ip6format := ip.As16() - if ip.Is4() { - ifParams.HasIp4 = true - ifParams.Ip4 = common.Ipv6ByteSliceToUint32Array(ip6format[:]) - } else { - ifParams.HasIp6 = true - ifParams.Ip6 = common.Ipv6ByteSliceToUint32Array(ip6format[:]) - } - if ifParams.HasIp4 && ifParams.HasIp6 { - break - } - } // Get link offload features. et, err := ethtool.NewEthtool() if err != nil { @@ -111,60 +77,11 @@ func getIfParamsFromLink(link netlink.Link) (ifParams bpfIfParams, err error) { return ifParams, nil } -func (c *ControlPlaneCore) bindLan(ifname string) error { - c.log.Infof("Bind to LAN: %v", ifname) +func (c *ControlPlaneCore) addQdisc(ifname string) error { link, err := netlink.LinkByName(ifname) if err != nil { return err } - /// Insert ip rule / ip route. - var output []byte - if output, err = exec.Command("sh", "-c", ` - ip rule add fwmark 0x80000000/0x80000000 table 2023 - ip route add local default dev lo table 2023 - ip -6 rule add fwmark 0x80000000/0x80000000 table 2023 - ip -6 route add local default dev lo table 2023 -`).CombinedOutput(); err != nil { - return fmt.Errorf("%w: %v", err, string(bytes.TrimSpace(output))) - } - c.deferFuncs = append(c.deferFuncs, func() error { - return exec.Command("sh", "-c", ` - ip rule del fwmark 0x80000000/0x80000000 table 2023 - ip route del local default dev lo table 2023 - ip -6 rule del fwmark 0x80000000/0x80000000 table 2023 - ip -6 route del local default dev lo table 2023 -`).Run() - }) - /// Insert an elem into IfindexParamsMap. - ifParams, err := getIfParamsFromLink(link) - if err != nil { - return err - } - if err = ifParams.CheckVersionRequirement(c.kernelVersion); err != nil { - return err - } - if err := c.bpf.IfindexParamsMap.Update(uint32(link.Attrs().Index), ifParams, ebpf.UpdateAny); err != nil { - return fmt.Errorf("update IfindexIpsMap: %w", err) - } - // FIXME: not only this link ip. - if ifParams.HasIp4 { - if err := c.bpf.HostIpLpm.Update(_bpfLpmKey{ - PrefixLen: 128, - Data: ifParams.Ip4, - }, uint32(1), ebpf.UpdateAny); err != nil { - return fmt.Errorf("update IfindexIpsMap: %w", err) - } - } - if ifParams.HasIp6 { - if err := c.bpf.HostIpLpm.Update(_bpfLpmKey{ - PrefixLen: 128, - Data: ifParams.Ip6, - }, uint32(1), ebpf.UpdateAny); err != nil { - return fmt.Errorf("update IfindexIpsMap: %w", err) - } - } - - // Insert qdisc and filters. qdisc := &netlink.GenericQdisc{ QdiscAttrs: netlink.QdiscAttrs{ LinkIndex: link.Attrs().Index, @@ -174,48 +91,66 @@ func (c *ControlPlaneCore) bindLan(ifname string) error { QdiscType: "clsact", } if err := netlink.QdiscAdd(qdisc); err != nil { - if os.IsExist(err) { - _ = netlink.QdiscDel(qdisc) - err = netlink.QdiscAdd(qdisc) - } - - if err != nil { - return fmt.Errorf("cannot add clsact qdisc: %w", err) - } - } - c.deferFuncs = append(c.deferFuncs, func() error { - if err := netlink.QdiscDel(qdisc); err != nil { - return fmt.Errorf("QdiscDel: %w", err) - } - return nil - }) - - filterIngress := &netlink.BpfFilter{ - FilterAttrs: netlink.FilterAttrs{ - LinkIndex: link.Attrs().Index, - Parent: netlink.HANDLE_MIN_INGRESS, - Handle: netlink.MakeHandle(0, 1), - Protocol: unix.ETH_P_ALL, - Priority: 0, - }, - Fd: c.bpf.bpfPrograms.TproxyLanIngress.FD(), - Name: consts.AppName + "_ingress", - DirectAction: true, - } - if err := netlink.FilterAdd(filterIngress); err != nil { - return fmt.Errorf("cannot attach ebpf object to filter ingress: %w", err) + return fmt.Errorf("cannot add clsact qdisc: %w", err) } return nil } -func (c *ControlPlaneCore) bindWan(ifname string) error { - c.log.Infof("Bind to WAN: %v", ifname) +func (c *ControlPlaneCore) delQdisc(ifname string) error { link, err := netlink.LinkByName(ifname) if err != nil { return err } - if link.Attrs().Index == consts.LoopbackIfIndex { - return fmt.Errorf("cannot bind to loopback interface") + qdisc := &netlink.GenericQdisc{ + QdiscAttrs: netlink.QdiscAttrs{ + LinkIndex: link.Attrs().Index, + Handle: netlink.MakeHandle(0xffff, 0), + Parent: netlink.HANDLE_CLSACT, + }, + QdiscType: "clsact", + } + if err := netlink.QdiscDel(qdisc); err != nil { + if !os.IsExist(err) { + return fmt.Errorf("cannot add clsact qdisc: %w", err) + } + } + return nil +} + +func (c *ControlPlaneCore) setupRoutingPolicy() (err error) { + /// Insert ip rule / ip route. + // TODO: Refactor me with netlink. + var output []byte + cleanFunc := func() error { + return exec.Command("sh", "-c", ` + ip rule del fwmark 0x80000000/0x80000000 table 2023 + ip route del local default dev lo table 2023 + ip -6 rule del fwmark 0x80000000/0x80000000 table 2023 + ip -6 route del local default dev lo table 2023 +`).Run() + } +tryAgain: + if output, err = exec.Command("sh", "-c", ` + ip rule add fwmark 0x80000000/0x80000000 table 2023 + ip route add local default dev lo table 2023 + ip -6 rule add fwmark 0x80000000/0x80000000 table 2023 + ip -6 route add local default dev lo table 2023 +`).CombinedOutput(); err != nil { + if strings.Contains(string(output), "File exists") { + _ = cleanFunc() + goto tryAgain + } + return fmt.Errorf("%w: %v", err, string(bytes.TrimSpace(output))) + } + c.deferFuncs = append(c.deferFuncs, cleanFunc) + return nil +} + +func (c *ControlPlaneCore) bindLan(ifname string) error { + c.log.Infof("Bind to LAN: %v", ifname) + link, err := netlink.LinkByName(ifname) + if err != nil { + return err } /// Insert an elem into IfindexParamsMap. ifParams, err := getIfParamsFromLink(link) @@ -229,6 +164,35 @@ func (c *ControlPlaneCore) bindWan(ifname string) error { return fmt.Errorf("update IfindexIpsMap: %w", err) } + // Insert filters. + filterIngress := &netlink.BpfFilter{ + FilterAttrs: netlink.FilterAttrs{ + LinkIndex: link.Attrs().Index, + Parent: netlink.HANDLE_MIN_INGRESS, + Handle: netlink.MakeHandle(0x2023, 2), + Protocol: unix.ETH_P_ALL, + // Priority should be behind of WAN's + Priority: 2, + }, + Fd: c.bpf.bpfPrograms.TproxyLanIngress.FD(), + Name: consts.AppName + "_lan_ingress", + DirectAction: true, + } + // Remove and add. + _ = netlink.FilterDel(filterIngress) + if err := netlink.FilterAdd(filterIngress); err != nil { + return fmt.Errorf("cannot attach ebpf object to filter ingress: %w", err) + } + c.deferFuncs = append(c.deferFuncs, func() error { + if err := netlink.FilterDel(filterIngress); err != nil { + return fmt.Errorf("FilterDel(%v:%v): %w", ifname, filterIngress.Name, err) + } + return nil + }) + return nil +} + +func (c *ControlPlaneCore) setupSkPidMonitor() error { /// Set-up SrcPidMapper. /// Attach programs to support pname routing. // Get the first-mounted cgroupv2 path. @@ -266,65 +230,77 @@ func (c *ControlPlaneCore) bindWan(ifname string) error { return nil }) } + return nil +} +func (c *ControlPlaneCore) bindWan(ifname string) error { + c.log.Infof("Bind to WAN: %v", ifname) + link, err := netlink.LinkByName(ifname) + if err != nil { + return err + } + if link.Attrs().Index == consts.LoopbackIfIndex { + return fmt.Errorf("cannot bind to loopback interface") + } + /// Insert an elem into IfindexParamsMap. + ifParams, err := getIfParamsFromLink(link) + if err != nil { + return err + } + if err = ifParams.CheckVersionRequirement(c.kernelVersion); err != nil { + return err + } + if err := c.bpf.IfindexParamsMap.Update(uint32(link.Attrs().Index), ifParams, ebpf.UpdateAny); err != nil { + return fmt.Errorf("update IfindexIpsMap: %w", err) + } /// Set-up WAN ingress/egress TC programs. - // Insert qdisc. - qdisc := &netlink.GenericQdisc{ - QdiscAttrs: netlink.QdiscAttrs{ - LinkIndex: link.Attrs().Index, - Handle: netlink.MakeHandle(0xffff, 0), - Parent: netlink.HANDLE_CLSACT, - }, - QdiscType: "clsact", - } - if err := netlink.QdiscAdd(qdisc); err != nil { - if os.IsExist(err) { - _ = netlink.QdiscDel(qdisc) - err = netlink.QdiscAdd(qdisc) - } - - if err != nil { - return fmt.Errorf("cannot add clsact qdisc: %w", err) - } - } - c.deferFuncs = append(c.deferFuncs, func() error { - if err := netlink.QdiscDel(qdisc); err != nil { - return fmt.Errorf("QdiscDel: %w", err) - } - return nil - }) - // Insert TC filters filterEgress := &netlink.BpfFilter{ FilterAttrs: netlink.FilterAttrs{ LinkIndex: link.Attrs().Index, Parent: netlink.HANDLE_MIN_EGRESS, - Handle: netlink.MakeHandle(0, 1), + Handle: netlink.MakeHandle(0x2023, 1), Protocol: unix.ETH_P_ALL, - Priority: 0, + Priority: 1, }, Fd: c.bpf.bpfPrograms.TproxyWanEgress.FD(), - Name: consts.AppName + "_egress", + Name: consts.AppName + "_wan_egress", DirectAction: true, } + // Remove and add. + _ = netlink.FilterDel(filterEgress) if err := netlink.FilterAdd(filterEgress); err != nil { return fmt.Errorf("cannot attach ebpf object to filter egress: %w", err) } + c.deferFuncs = append(c.deferFuncs, func() error { + if err := netlink.FilterDel(filterEgress); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("FilterDel(%v:%v): %w", ifname, filterEgress.Name, err) + } + return nil + }) filterIngress := &netlink.BpfFilter{ FilterAttrs: netlink.FilterAttrs{ LinkIndex: link.Attrs().Index, Parent: netlink.HANDLE_MIN_INGRESS, - Handle: netlink.MakeHandle(0, 1), + Handle: netlink.MakeHandle(0x2023, 1), Protocol: unix.ETH_P_ALL, - Priority: 0, + Priority: 1, }, Fd: c.bpf.bpfPrograms.TproxyWanIngress.FD(), - Name: consts.AppName + "_ingress", + Name: consts.AppName + "_wan_ingress", DirectAction: true, } + // Remove and add. + _ = netlink.FilterDel(filterIngress) if err := netlink.FilterAdd(filterIngress); err != nil { return fmt.Errorf("cannot attach ebpf object to filter ingress: %w", err) } + c.deferFuncs = append(c.deferFuncs, func() error { + if err := netlink.FilterDel(filterIngress); err != nil { + return fmt.Errorf("FilterDel(%v:%v): %w", ifname, filterIngress.Name, err) + } + return nil + }) return nil } diff --git a/control/kern/tproxy.c b/control/kern/tproxy.c index df2f0ef..173bb49 100644 --- a/control/kern/tproxy.c +++ b/control/kern/tproxy.c @@ -11,10 +11,9 @@ #include "headers/socket_defs.h" #include "headers/vmlinux.h" -// #include +#include "headers/bpf_core_read.h" #include "headers/bpf_endian.h" #include "headers/bpf_helpers.h" -#include "headers/bpf_core_read.h" // #define __DEBUG_ROUTING // #define __PRINT_ROUTING_RESULT @@ -190,11 +189,6 @@ struct { // Interface Ips: struct if_params { - __be32 ip4[4]; - __be32 ip6[4]; - - bool has_ip4; - bool has_ip6; bool rx_cksm_offload; bool tx_l4_cksm_ip4_offload; bool tx_l4_cksm_ip6_offload; @@ -220,7 +214,7 @@ struct map_lpm_type { __uint(max_entries, MAX_LPM_SIZE); __uint(key_size, sizeof(struct lpm_key)); __uint(value_size, sizeof(__u32)); -} unused_lpm_type SEC(".maps"), host_ip_lpm SEC(".maps"); +} unused_lpm_type SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); __uint(key_size, sizeof(__u32)); @@ -1193,12 +1187,12 @@ int tproxy_lan_ingress(struct __sk_buff *skb) { ip rule add fwmark 0x80000000/0x80000000 table 2023 ip route add local default dev lo table 2023 ip -6 rule add fwmark 0x80000000/0x80000000 table 2023 - ip -6 route add local ::/0 dev lo table 2023 + ip -6 route add local default dev lo table 2023 ip rule del fwmark 0x80000000/0x80000000 table 2023 ip route del local default dev lo table 2023 ip -6 rule del fwmark 0x80000000/0x80000000 table 2023 - ip -6 route del local ::/0 dev lo table 2023 + ip -6 route del local default dev lo table 2023 */ // Socket lookup and assign skb to existing socket connection. struct bpf_sock_tuple tuple = {0}; @@ -1446,13 +1440,28 @@ int tproxy_wan_egress(struct __sk_buff *skb) { return TC_ACT_OK; } - __be16 sport; - if (l4proto == IPPROTO_TCP) { - sport = tcph.source; - } else if (l4proto == IPPROTO_UDP) { - sport = udph.source; + // Backup for further use. + __be16 ipv4_tot_len = 0; + struct tuples tuples = {0}; + tuples.l4proto = l4proto; + if (ipversion == 4) { + tuples.src.ip[2] = bpf_htonl(0x0000ffff); + tuples.src.ip[3] = iph.saddr; + + tuples.dst.ip[2] = bpf_htonl(0x0000ffff); + tuples.dst.ip[3] = iph.daddr; + + ipv4_tot_len = iph.tot_len; } else { - return TC_ACT_OK; + __builtin_memcpy(tuples.dst.ip, &ipv6h.daddr, IPV6_BYTE_LENGTH); + __builtin_memcpy(tuples.src.ip, &ipv6h.saddr, IPV6_BYTE_LENGTH); + } + if (l4proto == IPPROTO_TCP) { + tuples.src.port = tcph.source; + tuples.dst.port = tcph.dest; + } else { + tuples.src.port = udph.source; + tuples.dst.port = udph.dest; } // We should know if this packet is from tproxy. @@ -1462,29 +1471,41 @@ int tproxy_wan_egress(struct __sk_buff *skb) { if (!tproxy_port) { return TC_ACT_OK; } - bool tproxy_response = *tproxy_port == sport; - - // Backup for further use. - __be16 ipv4_tot_len = 0; - - // Parse saddr and daddr as ipv6 format. - __be32 saddr[4]; - __be32 daddr[4]; - if (ipversion == 4) { - saddr[0] = 0; - saddr[1] = 0; - saddr[2] = bpf_htonl(0x0000ffff); - saddr[3] = iph.saddr; - - daddr[0] = 0; - daddr[1] = 0; - daddr[2] = bpf_htonl(0x0000ffff); - daddr[3] = iph.daddr; - - ipv4_tot_len = iph.tot_len; - } else { - __builtin_memcpy(daddr, &ipv6h.daddr, IPV6_BYTE_LENGTH); - __builtin_memcpy(saddr, &ipv6h.saddr, IPV6_BYTE_LENGTH); + bool tproxy_response = *tproxy_port == tuples.src.port; + // Double check to avoid bind wan and lan to one interface. + if (tproxy_response && l4proto == IPPROTO_TCP) { + // If it is a TCP first handshake, it is not a tproxy response. + if (tcph.syn && !tcph.syn) { + tproxy_response = false; + // Abnormal. + return TC_ACT_SHOT; + } else { + // If there is an existing socket on localhost, it is not a tproxy + // response. + struct bpf_sock_tuple tuple = {0}; + __u32 tuple_size; + if (ipversion == 4) { + tuple.ipv4.daddr = tuples.dst.ip[3]; + tuple.ipv4.saddr = tuples.src.ip[3]; + tuple.ipv4.dport = tuples.dst.port; + tuple.ipv4.sport = tuples.src.port; + tuple_size = sizeof(tuple.ipv4); + } else { + __builtin_memcpy(tuple.ipv6.daddr, tuples.dst.ip, IPV6_BYTE_LENGTH); + __builtin_memcpy(tuple.ipv6.saddr, tuples.src.ip, IPV6_BYTE_LENGTH); + tuple.ipv6.dport = tuples.dst.port; + tuple.ipv6.sport = tuples.src.port; + tuple_size = sizeof(tuple.ipv6); + } + struct bpf_sock *sk = + bpf_skc_lookup_tcp(skb, &tuple, tuple_size, BPF_F_CURRENT_NETNS, 0); + if (sk) { + // Not a tproxy response. + tproxy_response = false; + bpf_sk_release(sk); + return TC_ACT_OK; + } + } } if (tproxy_response) { @@ -1511,7 +1532,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { __builtin_memset(&key_src, 0, sizeof(key_src)); // Use daddr as key in WAN because tproxy (control plane) also lookups the // map element using income client ip (that is daddr). - __builtin_memcpy(key_src.ip, daddr, IPV6_BYTE_LENGTH); + __builtin_memcpy(key_src.ip, tuples.dst.ip, IPV6_BYTE_LENGTH); key_src.port = tcph.source; __u8 outbound; if (unlikely(tcp_state_syn)) { @@ -1538,7 +1559,8 @@ int tproxy_wan_egress(struct __sk_buff *skb) { bpf_htonl((ethh.h_source[2] << 24) + (ethh.h_source[3] << 16) + (ethh.h_source[4] << 8) + (ethh.h_source[5])), }; - if ((ret = routing(flag, &tcph, saddr, daddr, mac)) < 0) { + if ((ret = routing(flag, &tcph, tuples.src.ip, tuples.dst.ip, mac)) < + 0) { bpf_printk("shot routing: %d", ret); return TC_ACT_SHOT; } @@ -1572,7 +1594,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { if (unlikely(tcp_state_syn)) { struct ip_port_outbound value_dst; __builtin_memset(&value_dst, 0, sizeof(value_dst)); - __builtin_memcpy(value_dst.ip, daddr, IPV6_BYTE_LENGTH); + __builtin_memcpy(value_dst.ip, tuples.dst.ip, IPV6_BYTE_LENGTH); value_dst.port = tcph.dest; value_dst.outbound = outbound; // bpf_printk("UPDATE: %pI6:%u", key_src.ip, bpf_ntohs(key_src.port)); @@ -1595,7 +1617,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { // Backup for further use. struct ip_port_outbound new_hdr; __builtin_memset(&new_hdr, 0, sizeof(new_hdr)); - __builtin_memcpy(new_hdr.ip, daddr, IPV6_BYTE_LENGTH); + __builtin_memcpy(new_hdr.ip, tuples.dst.ip, IPV6_BYTE_LENGTH); new_hdr.port = udph.dest; // Routing. It decides if we redirect traffic to control plane. @@ -1620,7 +1642,7 @@ int tproxy_wan_egress(struct __sk_buff *skb) { bpf_htonl((ethh.h_source[2] << 24) + (ethh.h_source[3] << 16) + (ethh.h_source[4] << 8) + (ethh.h_source[5])), }; - if ((ret = routing(flag, &udph, saddr, daddr, mac)) < 0) { + if ((ret = routing(flag, &udph, tuples.src.ip, tuples.dst.ip, mac)) < 0) { bpf_printk("shot routing: %d", ret); return TC_ACT_SHOT; } @@ -1700,7 +1722,7 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { // Tproxy related. __u16 tproxy_typ = bpf_ntohs(*(__u16 *)ðh.h_source[4]); if (*(__u32 *)ðh.h_source[0] != bpf_htonl(0x02000203) || tproxy_typ > 1) { - return TC_ACT_OK; + return TC_ACT_PIPE; } bool tproxy_response = tproxy_typ == 1; @@ -1773,7 +1795,6 @@ int tproxy_wan_ingress(struct __sk_buff *skb) { if (!original_dst) { bpf_printk("[%X]Bad Connection: to: %pI6:%u", bpf_ntohl(tcph.seq), key_dst.ip, bpf_ntohs(key_dst.port)); - // Do not impact previous connections. return TC_ACT_SHOT; } @@ -1933,7 +1954,7 @@ static int __always_inline update_map_elem_by_cookie(const __u64 cookie) { buf[to_read] = 0; } if ((ret = bpf_core_read_user(&buf, to_read, - (const void *)(arg_start + j)))) { + (const void *)(arg_start + j)))) { bpf_printk("failed to read process name: %d", ret); return ret; } @@ -1950,7 +1971,7 @@ static int __always_inline update_map_elem_by_cookie(const __u64 cookie) { length_cpy = TASK_COMM_LEN; } if ((ret = bpf_core_read_user(&val.pname, length_cpy, - (const void *)(arg_start + last_slash)))) { + (const void *)(arg_start + last_slash)))) { bpf_printk("failed to read process name: %d", ret); return ret; }