From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1B84DC4724C for ; Wed, 6 May 2020 06:23:08 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id C8A8B20753 for ; Wed, 6 May 2020 06:23:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="HxroKVeB" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C8A8B20753 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=lst.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 5A2A58E0003; Wed, 6 May 2020 02:23:05 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 510758E0012; Wed, 6 May 2020 02:23:05 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 278778E0010; Wed, 6 May 2020 02:23:05 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0070.hostedemail.com [216.40.44.70]) by kanga.kvack.org (Postfix) with ESMTP id EF0D78E0003 for ; Wed, 6 May 2020 02:23:04 -0400 (EDT) Received: from smtpin12.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay03.hostedemail.com (Postfix) with ESMTP id B5EB3824559C for ; Wed, 6 May 2020 06:23:04 +0000 (UTC) X-FDA: 76785301488.12.cough44_1ad274b30f406 X-HE-Tag: cough44_1ad274b30f406 X-Filterd-Recvd-Size: 9207 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) by imf20.hostedemail.com (Postfix) with ESMTP for ; Wed, 6 May 2020 06:23:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender :Reply-To:Content-Type:Content-ID:Content-Description; bh=EgzCrGQ6Qxh33KJX/iL+nsU3Uwz9t7i6fxzkprPd6/s=; b=HxroKVeBseU/0gkk50Ux0r8UIP hY5NVFW09VFKc3C2a1uV/I7DDhZuT0TJagunzO10hMKHo0LlC8hCFlrxim9J5IG+yVRCXjEc/erew LFQpT4aFfZOxSDFflT6BDHjTqsK86T0mz4EvN2PNPO3URAdSQhwuqvZx/9NG3K9JAuERhvJEVslcl Sjnd6Dji7VfFZoC0HMP+k6gE6C3Zfqg89bV4qIe3hV6565uOrxXNneh3xvwoUYbXom3DQhb1ZV9AS qY4Z4zrdWexqbMoAPQp0SDi14Rbk85OiKB76zLEj8wr7fN+N6CJlMy1Z7Y7oeCQsOitv70muCKJJH 5rrLRRSg==; Received: from [2001:4bb8:191:66b6:c70:4a89:bc61:2] (helo=localhost) by bombadil.infradead.org with esmtpsa (Exim 4.92.3 #3 (Red Hat Linux)) id 1jWDSM-0006lb-Mc; Wed, 06 May 2020 06:22:59 +0000 From: Christoph Hellwig To: x86@kernel.org, Alexei Starovoitov , Daniel Borkmann , Masami Hiramatsu , Linus Torvalds , Andrew Morton Cc: linux-parisc@vger.kernel.org, linux-um@lists.infradead.org, netdev@vger.kernel.org, bpf@vger.kernel.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org Subject: [PATCH 11/15] maccess: remove strncpy_from_unsafe Date: Wed, 6 May 2020 08:22:19 +0200 Message-Id: <20200506062223.30032-12-hch@lst.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200506062223.30032-1-hch@lst.de> References: <20200506062223.30032-1-hch@lst.de> MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by bombadil.infradead.org. See http://www.infradead.org/rpr.html Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: All three callers really should try the explicit kernel and user copies instead. One has already deprecated the somewhat dangerous either kernel or user address concept, the other two still need to follow up eventually. Signed-off-by: Christoph Hellwig --- include/linux/uaccess.h | 1 - kernel/trace/bpf_trace.c | 40 ++++++++++++++++++++++++++----------- kernel/trace/trace_kprobe.c | 5 ++++- mm/maccess.c | 39 +----------------------------------- 4 files changed, 33 insertions(+), 52 deletions(-) diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index f8c47395a92df..09d6e358883cc 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -311,7 +311,6 @@ extern long probe_user_read(void *dst, const void __u= ser *src, size_t size); extern long notrace probe_kernel_write(void *dst, const void *src, size_= t size); extern long notrace probe_user_write(void __user *dst, const void *src, = size_t size); =20 -extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long= count); extern long strncpy_from_kernel_unsafe(char *dst, const void *unsafe_add= r, long count); extern long strncpy_from_user_unsafe(char *dst, const void __user *unsaf= e_addr, diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index e4e202f433903..ffe841433caa1 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -229,9 +229,10 @@ bpf_probe_read_kernel_str_common(void *dst, u32 size= , const void *unsafe_ptr, int ret =3D security_locked_down(LOCKDOWN_BPF_READ); =20 if (unlikely(ret < 0)) - goto out; + goto fail; + /* - * The strncpy_from_unsafe_*() call will likely not fill the entire + * The strncpy_from_*_unsafe() call will likely not fill the entire * buffer, but that's okay in this circumstance as we're probing * arbitrary memory anyway similar to bpf_probe_read_*() and might * as well probe the stack. Thus, memory is explicitly cleared @@ -239,11 +240,18 @@ bpf_probe_read_kernel_str_common(void *dst, u32 siz= e, const void *unsafe_ptr, * code altogether don't copy garbage; otherwise length of string * is returned that can be used for bpf_perf_event_output() et al. */ - ret =3D compat ? strncpy_from_unsafe(dst, unsafe_ptr, size) : - strncpy_from_kernel_unsafe(dst, unsafe_ptr, size); - if (unlikely(ret < 0)) -out: - memset(dst, 0, size); + ret =3D strncpy_from_kernel_unsafe(dst, unsafe_ptr, size); + if (unlikely(ret < 0)) { + if (compat) + ret =3D strncpy_from_user_unsafe(dst, + (__force const void __user *)unsafe_ptr, + size); + if (ret < 0) + goto fail; + } + return 0; +fail: + memset(dst, 0, size); return ret; } =20 @@ -321,6 +329,17 @@ static const struct bpf_func_proto *bpf_get_probe_wr= ite_proto(void) return &bpf_probe_write_user_proto; } =20 +#define BPF_STRNCPY_LEN 64 + +static void bpf_strncpy(char *buf, long unsafe_addr) +{ + buf[0] =3D 0; + if (strncpy_from_kernel_unsafe(buf, (void *)unsafe_addr, + BPF_STRNCPY_LEN)) + strncpy_from_user_unsafe(buf, (void __user *)unsafe_addr, + BPF_STRNCPY_LEN); +} + /* * Only limited trace_printk() conversion specifiers allowed: * %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %s @@ -332,7 +351,7 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_si= ze, u64, arg1, int mod[3] =3D {}; int fmt_cnt =3D 0; u64 unsafe_addr; - char buf[64]; + char buf[BPF_STRNCPY_LEN]; int i; =20 /* @@ -387,10 +406,7 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_s= ize, u64, arg1, arg3 =3D (long) buf; break; } - buf[0] =3D 0; - strncpy_from_unsafe(buf, - (void *) (long) unsafe_addr, - sizeof(buf)); + bpf_strncpy(buf, unsafe_addr); } continue; } diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a7f43c7ec9880..525d12137325c 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1238,7 +1238,10 @@ fetch_store_string(unsigned long addr, void *dest,= void *base) * Try to get string again, since the string can be changed while * probing. */ - ret =3D strncpy_from_unsafe(__dest, (void *)addr, maxlen); + ret =3D strncpy_from_kernel_unsafe(__dest, (void *)addr, maxlen); + if (ret < 0) + ret =3D strncpy_from_user_unsafe(__dest, (void __user *)addr, + maxlen); if (ret >=3D 0) *(u32 *)dest =3D make_data_loc(ret, __dest - base); =20 diff --git a/mm/maccess.c b/mm/maccess.c index 11563129cd490..cbd9d668aa46e 100644 --- a/mm/maccess.c +++ b/mm/maccess.c @@ -8,8 +8,6 @@ =20 static long __probe_kernel_read(void *dst, const void *src, size_t size, bool strict); -static long __strncpy_from_unsafe(char *dst, const void *unsafe_addr, - long count, bool strict); =20 bool __weak probe_kernel_read_allowed(void *dst, const void *unsafe_src, size_t size, bool strict) @@ -156,35 +154,6 @@ long probe_user_write(void __user *dst, const void *= src, size_t size) return 0; } =20 -/** - * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe addre= ss. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @unsafe_addr: Unsafe address. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from unsafe address to kernel buffer. - * - * On success, returns the length of the string INCLUDING the trailing N= UL. - * - * If access fails, returns -EFAULT (some data may have been copied - * and the trailing NUL added). - * - * If @count is smaller than the length of the string, copies @count-1 b= ytes, - * sets the last byte of @dst buffer to NUL and returns @count. - * - * Same as strncpy_from_kernel_unsafe() except that for architectures wi= th - * not fully separated user and kernel address spaces this function also= works - * for user address tanges. - * - * DO NOT USE THIS FUNCTION - it is broken on architectures with entirel= y - * separate kernel and user address spaces, and also a bad idea otherwis= e. - */ -long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) -{ - return __strncpy_from_unsafe(dst, unsafe_addr, count, false); -} - /** * strncpy_from_kernel_unsafe: - Copy a NUL terminated string from unsaf= e * address. @@ -204,12 +173,6 @@ long strncpy_from_unsafe(char *dst, const void *unsa= fe_addr, long count) * sets the last byte of @dst buffer to NUL and returns @count. */ long strncpy_from_kernel_unsafe(char *dst, const void *unsafe_addr, long= count) -{ - return __strncpy_from_unsafe(dst, unsafe_addr, count, true); -} - -static long __strncpy_from_unsafe(char *dst, const void *unsafe_addr, - long count, bool strict) { mm_segment_t old_fs =3D get_fs(); const void *src =3D unsafe_addr; @@ -217,7 +180,7 @@ static long __strncpy_from_unsafe(char *dst, const vo= id *unsafe_addr, =20 if (unlikely(count <=3D 0)) return 0; - if (!probe_kernel_read_allowed(dst, unsafe_addr, count, strict)) + if (!probe_kernel_read_allowed(dst, unsafe_addr, count, true)) return -EFAULT; =20 set_fs(KERNEL_DS); --=20 2.26.2