Skip to content

Commit 4e1ec56

Browse files
borkmannAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: add skb_load_bytes_relative helper
This adds a small BPF helper similar to bpf_skb_load_bytes() that is able to load relative to mac/net header offset from the skb's linear data. Compared to bpf_skb_load_bytes(), it takes a fifth argument namely start_header, which is either BPF_HDR_START_MAC or BPF_HDR_START_NET. This allows for a more flexible alternative compared to LD_ABS/LD_IND with negative offset. It's enabled for tc BPF programs as well as sock filter program types where it's mainly useful in reuseport programs to ease access to lower header data. Reference: https://lists.iovisor.org/pipermail/iovisor-dev/2017-March/000698.html Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent e0cea7c commit 4e1ec56

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

include/uapi/linux/bpf.h

+32-1
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,30 @@ union bpf_attr {
18021802
* Return
18031803
* a non-negative value equal to or less than size on success, or
18041804
* a negative error in case of failure.
1805+
*
1806+
* int skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header)
1807+
* Description
1808+
* This helper is similar to **bpf_skb_load_bytes**\ () in that
1809+
* it provides an easy way to load *len* bytes from *offset*
1810+
* from the packet associated to *skb*, into the buffer pointed
1811+
* by *to*. The difference to **bpf_skb_load_bytes**\ () is that
1812+
* a fifth argument *start_header* exists in order to select a
1813+
* base offset to start from. *start_header* can be one of:
1814+
*
1815+
* **BPF_HDR_START_MAC**
1816+
* Base offset to load data from is *skb*'s mac header.
1817+
* **BPF_HDR_START_NET**
1818+
* Base offset to load data from is *skb*'s network header.
1819+
*
1820+
* In general, "direct packet access" is the preferred method to
1821+
* access packet data, however, this helper is in particular useful
1822+
* in socket filters where *skb*\ **->data** does not always point
1823+
* to the start of the mac header and where "direct packet access"
1824+
* is not available.
1825+
*
1826+
* Return
1827+
* 0 on success, or a negative error in case of failure.
1828+
*
18051829
*/
18061830
#define __BPF_FUNC_MAPPER(FN) \
18071831
FN(unspec), \
@@ -1871,7 +1895,8 @@ union bpf_attr {
18711895
FN(bind), \
18721896
FN(xdp_adjust_tail), \
18731897
FN(skb_get_xfrm_state), \
1874-
FN(get_stack),
1898+
FN(get_stack), \
1899+
FN(skb_load_bytes_relative),
18751900

18761901
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
18771902
* function eBPF program intends to call
@@ -1932,6 +1957,12 @@ enum bpf_adj_room_mode {
19321957
BPF_ADJ_ROOM_NET,
19331958
};
19341959

1960+
/* Mode for BPF_FUNC_skb_load_bytes_relative helper. */
1961+
enum bpf_hdr_start_off {
1962+
BPF_HDR_START_MAC,
1963+
BPF_HDR_START_NET,
1964+
};
1965+
19351966
/* user accessible mirror of in-kernel sk_buff.
19361967
* new fields can only be added to the end of this structure
19371968
*/

net/core/filter.c

+45
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,47 @@ static const struct bpf_func_proto bpf_skb_load_bytes_proto = {
16841684
.arg4_type = ARG_CONST_SIZE,
16851685
};
16861686

1687+
BPF_CALL_5(bpf_skb_load_bytes_relative, const struct sk_buff *, skb,
1688+
u32, offset, void *, to, u32, len, u32, start_header)
1689+
{
1690+
u8 *ptr;
1691+
1692+
if (unlikely(offset > 0xffff || len > skb_headlen(skb)))
1693+
goto err_clear;
1694+
1695+
switch (start_header) {
1696+
case BPF_HDR_START_MAC:
1697+
ptr = skb_mac_header(skb) + offset;
1698+
break;
1699+
case BPF_HDR_START_NET:
1700+
ptr = skb_network_header(skb) + offset;
1701+
break;
1702+
default:
1703+
goto err_clear;
1704+
}
1705+
1706+
if (likely(ptr >= skb_mac_header(skb) &&
1707+
ptr + len <= skb_tail_pointer(skb))) {
1708+
memcpy(to, ptr, len);
1709+
return 0;
1710+
}
1711+
1712+
err_clear:
1713+
memset(to, 0, len);
1714+
return -EFAULT;
1715+
}
1716+
1717+
static const struct bpf_func_proto bpf_skb_load_bytes_relative_proto = {
1718+
.func = bpf_skb_load_bytes_relative,
1719+
.gpl_only = false,
1720+
.ret_type = RET_INTEGER,
1721+
.arg1_type = ARG_PTR_TO_CTX,
1722+
.arg2_type = ARG_ANYTHING,
1723+
.arg3_type = ARG_PTR_TO_UNINIT_MEM,
1724+
.arg4_type = ARG_CONST_SIZE,
1725+
.arg5_type = ARG_ANYTHING,
1726+
};
1727+
16871728
BPF_CALL_2(bpf_skb_pull_data, struct sk_buff *, skb, u32, len)
16881729
{
16891730
/* Idea is the following: should the needed direct read/write
@@ -4061,6 +4102,8 @@ sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
40614102
switch (func_id) {
40624103
case BPF_FUNC_skb_load_bytes:
40634104
return &bpf_skb_load_bytes_proto;
4105+
case BPF_FUNC_skb_load_bytes_relative:
4106+
return &bpf_skb_load_bytes_relative_proto;
40644107
case BPF_FUNC_get_socket_cookie:
40654108
return &bpf_get_socket_cookie_proto;
40664109
case BPF_FUNC_get_socket_uid:
@@ -4078,6 +4121,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
40784121
return &bpf_skb_store_bytes_proto;
40794122
case BPF_FUNC_skb_load_bytes:
40804123
return &bpf_skb_load_bytes_proto;
4124+
case BPF_FUNC_skb_load_bytes_relative:
4125+
return &bpf_skb_load_bytes_relative_proto;
40814126
case BPF_FUNC_skb_pull_data:
40824127
return &bpf_skb_pull_data_proto;
40834128
case BPF_FUNC_csum_diff:

0 commit comments

Comments
 (0)