Skip to content

fix(agent): prevent shift overflow in clone_by_masklen for IPv6 - #11948

Open
YanLongDai wants to merge 1 commit into
deepflowio:mainfrom
YanLongDai:fix/shift-overflow-ipv6
Open

YanLongDai wants to merge 1 commit into
deepflowio:mainfrom
YanLongDai:fix/shift-overflow-ipv6

Conversation

@YanLongDai

Copy link
Copy Markdown

This PR is for:

  • Agent

Fixes shift overflow panic in clone_by_masklen for IPv6 addresses

Steps to reproduce the bug

  1. Deploy DeepFlow Agent v7.2.2 on KylinOS V10 (aarch64) with IPv6 addresses
  2. Create config file:
    controller-port: 30035
    log-file: /var/log/deepflow-agent/deepflow-agent.log
    log-level: info
    agent-mode: standalone
  3. Start agent: systemctl start deepflow-agent
  4. Agent crashes with signal 6 (SIGABRT) when processing IPv6 addresses

The issue occurs when the agent processes IPv6 addresses with masklen=0 in the policy labeler. The code attempts to shift u128::MAX by 128 bits, which causes a shift overflow panic in Rust debug builds.

Stack trace (native agent v7.2.2):

           PID: 109309 (deepflow-agent)
           UID: 0 (root)
           GID: 0 (root)
        Signal: 6 (ABRT)
     Timestamp: 2026-10-22 16:30:28 CST
  Command Line: /usr/bin/deepflow-agent -c /etc/deepflow-agent/deepflow-agent.yaml
    Executable: /usr/bin/deepflow-agent (native v7.2.2)

Stack trace of thread 109309:
#0  raise (libc.so.6)
#1  abort (libc.so.6)
#2-#9 Rust panic chain
#10 panic_const_shl_overflow (deepflow-agent)  ← PANIC HERE
#11 deepflow_agent::policy::labeler::EpcNetIpKey::clone_by_masklen (deepflow-agent)
#12 deepflow_agent::policy::labeler::Labeler::set_epc_by_cidr (deepflow-agent)
#13 deepflow_agent::policy::labeler::Labeler::get_l3_by_wan (deepflow-agent)
#14 deepflow_agent::policy::labeler::Labeler::get_endpoint_data (deepflow-agent)
#15 deepflow_agent::policy::policy::Policy::lookup_all_by_key (deepflow-agent)
#16 deepflow_agent::policy::policy::Policy::lookup (deepflow-agent)
#17 deepflow_agent::policy::policy::PolicyGetter::lookup (deepflow-agent)
#18 deepflow_agent::flow_generator::flow_map::FlowMap::init_flow (deepflow-agent)
#19 deepflow_agent::flow_generator::flow_map::FlowMap::new_tcp_node (deepflow-agent)
#20 deepflow_agent::flow_generator::flow_map::FlowMap::new_flow_node (deepflow-agent)
#21 deepflow_agent::flow_generator::flow_map::FlowMap::inject_meta_packet (deepflow-agent)
#22 deepflow_agent::dispatcher::local_mode_dispatcher::LocalModeDispatcher::process_packet (deepflow-agent)

Agent log error:

[2026-10-22 16:30:28.141941 +08:00] ERROR [src/main.rs:123] panicked at src/policy/labeler.rs:73:27:
attempt to shift left with overflow

Test environment:

OS: KylinOS V10 (aarch64)
Kernel: 4.19.90-89.37.v2401.ky10.aarch64
Architecture: ARM64 (aarch64)
DeepFlow Agent: v7.2.2 (native community version)
Network: Multiple IPv6 link-local addresses (fe80::/64)

Verification:

Program Version Config Result
Native (70M) With IPv6 addresses ❌ Crash (shift overflow)
Native (70M) Without IPv6 addresses ✅ Normal

Conclusion: This is a bug in the native DeepFlow code, verified on community version v7.2.2.

Root Cause

In agent/src/policy/labeler.rs:73, the clone_by_masklen function performs a left shift operation:

ip: self.ip & (u128::MAX << max_prefix.saturating_sub(masklen))

When processing IPv6 addresses (is_ipv4=false), max_prefix is set to IPV6_BITS (128). If masklen=0, the shift amount becomes 128 - 0 = 128. In Rust debug builds, shifting a u128 value by 128 bits causes a panic because the shift amount must be less than the bit width.

Changes to fix the bug

Location: EpcNetIpKey::clone_by_masklen() - Line 70-77

Before:

fn clone_by_masklen(&self, masklen: usize, is_ipv4: bool) -> Self {
    let max_prefix = if is_ipv4 { IPV4_BITS } else { IPV6_BITS };
    Self {
        ip: self.ip & (u128::MAX << max_prefix.saturating_sub(masklen)),
        epc_id: self.epc_id,
        masklen: masklen as u8,
    }
}

After:

fn clone_by_masklen(&self, masklen: usize, is_ipv4: bool) -> Self {
    let max_prefix = if is_ipv4 { IPV4_BITS } else { IPV6_BITS };
    let shift = max_prefix.saturating_sub(masklen);
    let mask = if shift >= max_prefix {
        0
    } else {
        u128::MAX << shift
    };
    Self {
        ip: self.ip & mask,
        epc_id: self.epc_id,
        masklen: masklen as u8,
    }
}

Explanation:

  • Calculate the shift amount first
  • Check if shift >= max_prefix (which would cause overflow)
  • If overflow would occur, use 0 as the mask (all bits zeroed)
  • Otherwise, perform the shift safely

Affected branches

  • main

Checklist

  • Verified the fix on KylinOS V10 (aarch64) with DeepFlow Agent v7.2.2
  • Tested with IPv6 addresses present
  • No breaking changes - maintains backward compatibility
  • Added unit test to verify the fix.
  • Verified eBPF program runs successfully on linux 4.14.x.
  • Verified eBPF program runs successfully on linux 4.19.x.
  • Verified eBPF program runs successfully on linux 5.2.x.

Note: The eBPF verification items are not applicable for this fix as it only modifies policy labeler logic, not eBPF programs.


Signed-off-by: Dai Yanlong daiyanlong@kylinos.cn

cc @lzf575 @rvql Please review this fix. Thanks!

- Add boundary check in clone_by_masklen() to prevent shift overflow
- When masklen=0 and is_ipv4=false, shift amount equals 128, causing panic
- Fix: check if shift >= max_prefix, return 0 mask instead of shifting

Fixes: Agent crash with signal 6 (SIGABRT) at policy/labeler.rs:73

Signed-off-by: Dai Yanlong <daiyanlong@kylinos.cn>

This branch has not been deployed

No deployments
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.

1 participant