forked from Minki/linux
bpf-for-netdev
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQTFp0I1jqZrAX+hPRXbK58LschIgwUCY2RS7QAKCRDbK58LschI g6RVAQC1FdSXMrhn369NGCG1Vox1QYn2/5P32LSIV1BKqiQsywEAsxgYNrdCPTua ie91Q5IJGT9pFl1UR50UrgL11DI5BgI= =sdhO -----END PGP SIGNATURE----- Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf Daniel Borkmann says: ==================== bpf 2022-11-04 We've added 8 non-merge commits during the last 3 day(s) which contain a total of 10 files changed, 113 insertions(+), 16 deletions(-). The main changes are: 1) Fix memory leak upon allocation failure in BPF verifier's stack state tracking, from Kees Cook. 2) Fix address leakage when BPF progs release reference to an object, from Youlin Li. 3) Fix BPF CI breakage from buggy in.h uapi header dependency, from Andrii Nakryiko. 4) Fix bpftool pin sub-command's argument parsing, from Pu Lehui. 5) Fix BPF sockmap lockdep warning by cancelling psock work outside of socket lock, from Cong Wang. 6) Follow-up for BPF sockmap to fix sk_forward_alloc accounting, from Wang Yufen. bpf-for-netdev * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: Add verifier test for release_reference() bpf: Fix wrong reg type conversion in release_reference() bpf, sock_map: Move cancel_work_sync() out of sock lock tools/headers: Pull in stddef.h to uapi to fix BPF selftests build in CI net/ipv4: Fix linux/in.h header dependencies bpftool: Fix NULL pointer dereference when pin {PROG, MAP, LINK} without FILE bpf, sockmap: Fix the sk->sk_forward_alloc warning of sk_stream_kill_queues bpf, verifier: Fix memory leak in array reallocation for stack state ==================== Link: https://lore.kernel.org/r/20221104000445.30761-1-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
f2c24be55b
@ -376,7 +376,7 @@ static inline void sk_psock_report_error(struct sk_psock *psock, int err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct sk_psock *sk_psock_init(struct sock *sk, int node);
|
struct sk_psock *sk_psock_init(struct sock *sk, int node);
|
||||||
void sk_psock_stop(struct sk_psock *psock, bool wait);
|
void sk_psock_stop(struct sk_psock *psock);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
|
#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
|
||||||
int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock);
|
int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define _UAPI_LINUX_IN_H
|
#define _UAPI_LINUX_IN_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/stddef.h>
|
||||||
#include <linux/libc-compat.h>
|
#include <linux/libc-compat.h>
|
||||||
#include <linux/socket.h>
|
#include <linux/socket.h>
|
||||||
|
|
||||||
|
@ -1027,12 +1027,17 @@ out:
|
|||||||
*/
|
*/
|
||||||
static void *realloc_array(void *arr, size_t old_n, size_t new_n, size_t size)
|
static void *realloc_array(void *arr, size_t old_n, size_t new_n, size_t size)
|
||||||
{
|
{
|
||||||
|
void *new_arr;
|
||||||
|
|
||||||
if (!new_n || old_n == new_n)
|
if (!new_n || old_n == new_n)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
arr = krealloc_array(arr, new_n, size, GFP_KERNEL);
|
new_arr = krealloc_array(arr, new_n, size, GFP_KERNEL);
|
||||||
if (!arr)
|
if (!new_arr) {
|
||||||
|
kfree(arr);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
arr = new_arr;
|
||||||
|
|
||||||
if (new_n > old_n)
|
if (new_n > old_n)
|
||||||
memset(arr + old_n * size, 0, (new_n - old_n) * size);
|
memset(arr + old_n * size, 0, (new_n - old_n) * size);
|
||||||
@ -6618,8 +6623,12 @@ static int release_reference(struct bpf_verifier_env *env,
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
|
bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
|
||||||
if (reg->ref_obj_id == ref_obj_id)
|
if (reg->ref_obj_id == ref_obj_id) {
|
||||||
__mark_reg_unknown(env, reg);
|
if (!env->allow_ptr_leaks)
|
||||||
|
__mark_reg_not_init(env, reg);
|
||||||
|
else
|
||||||
|
__mark_reg_unknown(env, reg);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -803,16 +803,13 @@ static void sk_psock_link_destroy(struct sk_psock *psock)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sk_psock_stop(struct sk_psock *psock, bool wait)
|
void sk_psock_stop(struct sk_psock *psock)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&psock->ingress_lock);
|
spin_lock_bh(&psock->ingress_lock);
|
||||||
sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
|
sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED);
|
||||||
sk_psock_cork_free(psock);
|
sk_psock_cork_free(psock);
|
||||||
__sk_psock_zap_ingress(psock);
|
__sk_psock_zap_ingress(psock);
|
||||||
spin_unlock_bh(&psock->ingress_lock);
|
spin_unlock_bh(&psock->ingress_lock);
|
||||||
|
|
||||||
if (wait)
|
|
||||||
cancel_work_sync(&psock->work);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sk_psock_done_strp(struct sk_psock *psock);
|
static void sk_psock_done_strp(struct sk_psock *psock);
|
||||||
@ -850,7 +847,7 @@ void sk_psock_drop(struct sock *sk, struct sk_psock *psock)
|
|||||||
sk_psock_stop_verdict(sk, psock);
|
sk_psock_stop_verdict(sk, psock);
|
||||||
write_unlock_bh(&sk->sk_callback_lock);
|
write_unlock_bh(&sk->sk_callback_lock);
|
||||||
|
|
||||||
sk_psock_stop(psock, false);
|
sk_psock_stop(psock);
|
||||||
|
|
||||||
INIT_RCU_WORK(&psock->rwork, sk_psock_destroy);
|
INIT_RCU_WORK(&psock->rwork, sk_psock_destroy);
|
||||||
queue_rcu_work(system_wq, &psock->rwork);
|
queue_rcu_work(system_wq, &psock->rwork);
|
||||||
|
@ -1596,7 +1596,7 @@ void sock_map_destroy(struct sock *sk)
|
|||||||
saved_destroy = psock->saved_destroy;
|
saved_destroy = psock->saved_destroy;
|
||||||
sock_map_remove_links(sk, psock);
|
sock_map_remove_links(sk, psock);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
sk_psock_stop(psock, false);
|
sk_psock_stop(psock);
|
||||||
sk_psock_put(sk, psock);
|
sk_psock_put(sk, psock);
|
||||||
saved_destroy(sk);
|
saved_destroy(sk);
|
||||||
}
|
}
|
||||||
@ -1619,9 +1619,10 @@ void sock_map_close(struct sock *sk, long timeout)
|
|||||||
saved_close = psock->saved_close;
|
saved_close = psock->saved_close;
|
||||||
sock_map_remove_links(sk, psock);
|
sock_map_remove_links(sk, psock);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
sk_psock_stop(psock, true);
|
sk_psock_stop(psock);
|
||||||
sk_psock_put(sk, psock);
|
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
cancel_work_sync(&psock->work);
|
||||||
|
sk_psock_put(sk, psock);
|
||||||
saved_close(sk, timeout);
|
saved_close(sk, timeout);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sock_map_close);
|
EXPORT_SYMBOL_GPL(sock_map_close);
|
||||||
|
@ -278,7 +278,7 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
|
|||||||
{
|
{
|
||||||
bool cork = false, enospc = sk_msg_full(msg);
|
bool cork = false, enospc = sk_msg_full(msg);
|
||||||
struct sock *sk_redir;
|
struct sock *sk_redir;
|
||||||
u32 tosend, delta = 0;
|
u32 tosend, origsize, sent, delta = 0;
|
||||||
u32 eval = __SK_NONE;
|
u32 eval = __SK_NONE;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -333,10 +333,12 @@ more_data:
|
|||||||
cork = true;
|
cork = true;
|
||||||
psock->cork = NULL;
|
psock->cork = NULL;
|
||||||
}
|
}
|
||||||
sk_msg_return(sk, msg, msg->sg.size);
|
sk_msg_return(sk, msg, tosend);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
|
|
||||||
|
origsize = msg->sg.size;
|
||||||
ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags);
|
ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags);
|
||||||
|
sent = origsize - msg->sg.size;
|
||||||
|
|
||||||
if (eval == __SK_REDIRECT)
|
if (eval == __SK_REDIRECT)
|
||||||
sock_put(sk_redir);
|
sock_put(sk_redir);
|
||||||
@ -375,7 +377,7 @@ more_data:
|
|||||||
msg->sg.data[msg->sg.start].page_link &&
|
msg->sg.data[msg->sg.start].page_link &&
|
||||||
msg->sg.data[msg->sg.start].length) {
|
msg->sg.data[msg->sg.start].length) {
|
||||||
if (eval == __SK_REDIRECT)
|
if (eval == __SK_REDIRECT)
|
||||||
sk_mem_charge(sk, msg->sg.size);
|
sk_mem_charge(sk, tosend - sent);
|
||||||
goto more_data;
|
goto more_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,6 +300,9 @@ int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
|
|||||||
int err;
|
int err;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
|
if (!REQ_ARGS(3))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
fd = get_fd(&argc, &argv);
|
fd = get_fd(&argc, &argv);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define _UAPI_LINUX_IN_H
|
#define _UAPI_LINUX_IN_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/stddef.h>
|
||||||
#include <linux/libc-compat.h>
|
#include <linux/libc-compat.h>
|
||||||
#include <linux/socket.h>
|
#include <linux/socket.h>
|
||||||
|
|
||||||
|
47
tools/include/uapi/linux/stddef.h
Normal file
47
tools/include/uapi/linux/stddef.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||||
|
#ifndef _LINUX_STDDEF_H
|
||||||
|
#define _LINUX_STDDEF_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __always_inline
|
||||||
|
#define __always_inline __inline__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __struct_group() - Create a mirrored named and anonyomous struct
|
||||||
|
*
|
||||||
|
* @TAG: The tag name for the named sub-struct (usually empty)
|
||||||
|
* @NAME: The identifier name of the mirrored sub-struct
|
||||||
|
* @ATTRS: Any struct attributes (usually empty)
|
||||||
|
* @MEMBERS: The member declarations for the mirrored structs
|
||||||
|
*
|
||||||
|
* Used to create an anonymous union of two structs with identical layout
|
||||||
|
* and size: one anonymous and one named. The former's members can be used
|
||||||
|
* normally without sub-struct naming, and the latter can be used to
|
||||||
|
* reason about the start, end, and size of the group of struct members.
|
||||||
|
* The named struct can also be explicitly tagged for layer reuse, as well
|
||||||
|
* as both having struct attributes appended.
|
||||||
|
*/
|
||||||
|
#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
|
||||||
|
union { \
|
||||||
|
struct { MEMBERS } ATTRS; \
|
||||||
|
struct TAG { MEMBERS } ATTRS NAME; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
|
||||||
|
*
|
||||||
|
* @TYPE: The type of each flexible array element
|
||||||
|
* @NAME: The name of the flexible array member
|
||||||
|
*
|
||||||
|
* In order to have a flexible array member in a union or alone in a
|
||||||
|
* struct, it needs to be wrapped in an anonymous struct with at least 1
|
||||||
|
* named member, but that member can be empty.
|
||||||
|
*/
|
||||||
|
#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
|
||||||
|
struct { \
|
||||||
|
struct { } __empty_ ## NAME; \
|
||||||
|
TYPE NAME[]; \
|
||||||
|
}
|
||||||
|
#endif
|
@ -1044,3 +1044,39 @@
|
|||||||
.result_unpriv = REJECT,
|
.result_unpriv = REJECT,
|
||||||
.errstr_unpriv = "unknown func",
|
.errstr_unpriv = "unknown func",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"reference tracking: try to leak released ptr reg",
|
||||||
|
.insns = {
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||||
|
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
BPF_MOV64_REG(BPF_REG_9, BPF_REG_0),
|
||||||
|
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_2, 8),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_3, 0),
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_ringbuf_reserve),
|
||||||
|
BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
|
||||||
|
|
||||||
|
BPF_MOV64_REG(BPF_REG_1, BPF_REG_8),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_2, 0),
|
||||||
|
BPF_EMIT_CALL(BPF_FUNC_ringbuf_discard),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||||
|
|
||||||
|
BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_8, 0),
|
||||||
|
BPF_EXIT_INSN()
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 4 },
|
||||||
|
.fixup_map_ringbuf = { 11 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.result_unpriv = REJECT,
|
||||||
|
.errstr_unpriv = "R8 !read_ok"
|
||||||
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user