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:
Jakub Kicinski 2022-11-03 19:51:02 -07:00
commit f2c24be55b
10 changed files with 113 additions and 16 deletions

View File

@ -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);

View File

@ -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>

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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>

View 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

View File

@ -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"
},