lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 24 Oct 2018 08:00:19 -0500
From:   Wenwen Wang <>
To:     Wenwen Wang <>
Cc:     Kangjie Lu <>, Alexei Starovoitov <>,
        Daniel Borkmann <>, (open list:BPF (Safe dynamic programs and tools)), (open list:BPF (Safe dynamic programs and
Subject: [PATCH v2] bpf: btf: Fix a missing-check bug

In btf_parse(), the header of the user-space btf data 'btf_data' is firstly
parsed and verified through btf_parse_hdr(). In btf_parse_hdr(), the header
is copied from user-space 'btf_data' to kernel-space 'btf->hdr' and then
verified. If no error happens during the verification process, the whole
data of 'btf_data', including the header, is then copied to 'data' in
btf_parse(). It is obvious that the header is copied twice here. More
importantly, no check is enforced after the second copy to make sure the
headers obtained in these two copies are same. Given that 'btf_data'
resides in the user space, a malicious user can race to modify the header
between these two copies. By doing so, the user can inject inconsistent
data, which can cause undefined behavior of the kernel and introduce
potential security risk.

To avoid the above issue, this patch copies the parsed header from
'btf->hdr' to 'data'. The remaining part in 'data' is still copied from the
user-space 'btf_data'.

Signed-off-by: Wenwen Wang <>
 kernel/bpf/btf.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 378cef7..b52a834a 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -2152,6 +2152,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
 	struct btf_verifier_env *env = NULL;
 	struct bpf_verifier_log *log;
 	struct btf *btf = NULL;
+	u32 hdr_len;
 	u8 *data;
 	int err;
@@ -2200,7 +2201,15 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
 	btf->data_size = btf_data_size;
 	btf->nohdr_data = btf->data + btf->hdr.hdr_len;
-	if (copy_from_user(data, btf_data, btf_data_size)) {
+	/*
+	 * The header at btf_data could be modified by a malicious user
+	 * after it is parsed. So we copy the parsed header here. The
+	 * remaining part is still copied from btf_data.
+	 */
+	hdr_len = min_t(u32, btf->hdr.hdr_len, sizeof(btf->hdr));
+	memcpy(data, &btf->hdr, hdr_len);
+	if (copy_from_user(data + hdr_len, (u8 __user *)btf_data + hdr_len,
+				btf_data_size - hdr_len)) {
 		err = -EFAULT;
 		goto errout;

Powered by blists - more mailing lists