From patchwork Fri Jan 24 18:16:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jordan Rome X-Patchwork-Id: 13949811 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 55B45C02181 for ; Fri, 24 Jan 2025 18:16:44 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id B8AEF280087; Fri, 24 Jan 2025 13:16:43 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id B13F3280079; Fri, 24 Jan 2025 13:16:43 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 98CFA280087; Fri, 24 Jan 2025 13:16:43 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 77AEE280079 for ; Fri, 24 Jan 2025 13:16:43 -0500 (EST) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id CF4DA141701 for ; Fri, 24 Jan 2025 18:16:42 +0000 (UTC) X-FDA: 83043151044.21.1F6F76D Received: from mout.perfora.net (mout.perfora.net [74.208.4.196]) by imf23.hostedemail.com (Postfix) with ESMTP id 3EFA7140008 for ; Fri, 24 Jan 2025 18:16:40 +0000 (UTC) Authentication-Results: imf23.hostedemail.com; dkim=pass header.d=jordanrome.com header.s=s1-ionos header.b=WpAHqIUb; dmarc=none; spf=pass (imf23.hostedemail.com: domain of linux@jordanrome.com designates 74.208.4.196 as permitted sender) smtp.mailfrom=linux@jordanrome.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1737742600; a=rsa-sha256; cv=none; b=NEqGQzWPzk742lZPFgdhaYyhLXd0FmFJPsszWKTFT8ymC9PuQkhcnuP9PIi1GaNEW/G9HI FfY/w9UL2l36h9KPmlugWYRqi9sXWyGbiCs8vAfSWh9ogcTs4yFUb17kTUEDVuQD89tayX lvXTzCmVZ+5tVRKZYWrwhLQ5AIVdH0U= ARC-Authentication-Results: i=1; imf23.hostedemail.com; dkim=pass header.d=jordanrome.com header.s=s1-ionos header.b=WpAHqIUb; dmarc=none; spf=pass (imf23.hostedemail.com: domain of linux@jordanrome.com designates 74.208.4.196 as permitted sender) smtp.mailfrom=linux@jordanrome.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1737742600; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:references:dkim-signature; bh=CTtBpXoCRGF8xp6ipvPviZzZSvtuH9Unpp03LtW5iJU=; b=0rBEd4wclwjGEFd9KhgHoMI9M5pB4nvzEUfRz5w+HFFw61L8iQEUBnCns/B7AKYCiUdBn8 8csR3Ln1ztdZoHA1vV8d1T/ubQFUcbq4U0PLf6RYt2Hwvy2NmKVUf5wKS06pI3fMtcbh9B coQLfNBZt3DOiV0d4P/4238huUeiMD0= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jordanrome.com; s=s1-ionos; t=1737742569; x=1738347369; i=linux@jordanrome.com; bh=CTtBpXoCRGF8xp6ipvPviZzZSvtuH9Unpp03LtW5iJU=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:Message-ID: MIME-Version:Content-Transfer-Encoding:cc: content-transfer-encoding:content-type:date:from:message-id: mime-version:reply-to:subject:to; b=WpAHqIUb6JBP7zYvOxQWVs2lvFz869vVxxVYDEhA/cycVM+iVhCi2X73Z+23uW7s EGRKgjKFquBTgqgikkw6CM/fiM+/H62tw5f2toZbWFhsCvGJY5/VsBmgEwmfQ+R/d JmH3lgjsQcVzEtHPLg47PBkhsXQbUzT8Nic+4zcGqDajrxOGHVmlx6aHXVo5sbQMJ kuChatbIvj/F0IzU1nKWINWqBFgcFMuyk+feldv2vaeHpUB/jlkJfhm6zPud9KONu gDLZtwd4zZw2Q2+PmJE6CaxBdUlzGzqxCxCudfeB/0b8CYuuAxTsm8rqvHK0KZjKt v8IOX3/LVV6d+8lE+g== X-UI-Sender-Class: 55c96926-9e95-11ee-ae09-1f7a4046a0f6 Received: from localhost ([69.171.251.21]) by mrelay.perfora.net (mreueus003 [74.208.5.2]) with ESMTPSA (Nemesis) id 0MHVog-1tegXl2DWe-000X2F; Fri, 24 Jan 2025 19:16:09 +0100 From: Jordan Rome To: bpf@vger.kernel.org Cc: linux-mm@kvack.org, Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Kernel Team , Andrew Morton , Shakeel Butt , Alexander Potapenko Subject: [bpf-next v3 1/3] mm: add copy_remote_vm_str Date: Fri, 24 Jan 2025 10:16:00 -0800 Message-ID: <20250124181602.1872142-1-linux@jordanrome.com> X-Mailer: git-send-email 2.43.5 MIME-Version: 1.0 X-Provags-ID: V03:K1:aN627SuLhjaIjqrJzCgctnzWbHzLjJyMe1aVh1V6WI5NYAcFzNw ldODKGOaIFpbthhCKD6LEgQ1JQZCFzWLyoXwdXYHyIL+0wv/9Vf7Ua82jXyqmCjhw7tArGS fhoxyagyJWERY7esMKb+EHdJATLH+W6q3LgznzoRb0fEm+29ueoB0DoEGBSsLfXdzEQ1Qbe u4u1n19/YDTuW+rZhKfrg== UI-OutboundReport: notjunk:1;M01:P0:cur6L04UtGQ=;GMvQveJlWvHiQeB61qRIGA9W/Fj NMeVs2oJwNvWrcKile3JRc04jDbbCZ0hLlT5e4Np6OBo+JgORye0y5PbEVjJopt2ArQJEUH5I tOHUYAzXTk4fgz7i1+mHJ8T/GOt4AEN/Nnc1ySn5/sePxB/U/SjYijUHPmjhxPnS/NJXu3uMW 0nW3PgjC7Re8Lm731CMV1WyEwfOOQTNTwaUtgCU3ts6oXvH5mlfFeUNO0yRk/RLoI75Xht72C urPCd5P21fHLuC5F8LU7AcB4puTqE4FCDQEfLeorxp7jCCDQF+4t+Z3hK7PiAGa1OnjbAwHBs RWPW25uXHBZR6mq1WgRBTrrL8em/+mDUUIkt8Ao+2VaayOWjD2QJKPWdMMPRHdDDVPU+sEYUc KQAxAqHj2Ik81/UjaQyi9npY4P/Rall9MYbTi1/oqdncKt+bOapBWmxCs7E/Rd0DNgFRJ7JtZ 0rS8oScxl3mjk4ILekBWdksSOorDrrlTC2HyPLLKc9uV9CjceU0d5JB63x48Feo7tk/mpFQ7z z9Jt8KhcgqwNR2uyJlwGVCvfWFGP6WL9ZFEYfUwQf3EvJBYM/rSRTtHW0KL/ZqA8fxzpTFhUz 9/zk0jfTsrmrkvoEjMFR9U1hIzPSBGTIHUeDlSDWxkROphQPuYAep8BL2Uga+QuqitQzC1/AI 96P8M3j/E8zTrWpwnHnH+rgxNBlTvDJ5ObeSGePhzmkKC6u3cszrI5uBBgctddv2KLig2o5Th YH52WuIudoNzY7S6cpAYoCNdc+gBp0ex0S170PcwoLtprQGxWNtx7uba6UPzEg6vj/RKT/ztU 4y8CWbuCL700iKd1aMuwxXGVys1Bum4de24DcVzCpOMZHqISMzdT8nu52ygz5858lCai6tw9x 3dMJfT2zBBZuKtCiRJnOKnVVnQMNO/Z3qWgAe4+aCGnDcydEbAlPezalSSGfhPZDz8kwn/gJd 7LjcGHOmtwHS3jQ+jX/Zrx4t3sCnWliY4y2jQAzHf3NPEw42AzxZP6XHTtaWPW/7+wg2p1TE3 GA3gbOUXYPYienOW8p2JvY3NrK76Add33toc8Zxj8gXRiEWNNUTEMCbe21KMgAX0LO0EN7G7i 737ez39eiSAmb4y0sFmL3gd36TK3bKjI7vp8/FwjfIPpbXrprwYFZgXXZzjjFf19QQ6QTFWQB fBJoOtn1Gsa987RNX4ceQaZqO9nryKxzaW2z+3i/P2q1mbAlbyBDZpi2xRBh0eM/v2EbHPV8U A0ykc2LwIaD1+noVD3m5/6QhNE/kniBtvw== X-Rspam-User: X-Rspamd-Queue-Id: 3EFA7140008 X-Rspamd-Server: rspam10 X-Stat-Signature: zwatr6tgq77mij14otdwamturkyymfwn X-HE-Tag: 1737742600-784173 X-HE-Meta: U2FsdGVkX1/gpcEJEdMzmCXl8USpXXNcH9qy64w7s/wdX62sYc70jKj4jyJcGUjq0lqSbjYSz7mT2QfU6k7TsWlZMTfNS8FPIJDRATYj56EEcTHRX8hBRRiDZJjxA24Hfa4Yi5l870XqeQsD2UCit/7tVvRJheCcPsW540c0jZRJ6XIh9LzvT5cTc3czKIah8rsYxV6JwaCFdqaQimfdRQmMCiyxXnO4h+YICfMAlCCVHqNrbEoFhrULd9J/6flN1OO4XQ/PEH4+V//lJYMYJ3bPsrH2YfYLCxn9ntE0mVzczWguUWX83xV3XjCm5CHN+KcnF0S4fg+P/x0UEvY4gc8p1/oAE/PIHFDm2O2twyWP5Hvior+CySIqxE+L4VjFIzFKLSg7TtoqYWbe/p72PxsrJ4jifuPmSDuFERCy0xLB10S8BEntcc6moj01C06f54Cxov89Cn1dJCvgd3IwjSeM15N6D3yGz7JxAmDYPc7bgrhLiJ6Pu6LPWkz3B3lPRZL14WPDpimkxvY3UPZrHjqgchZbeJDfCbK1yjh6RXtIZ714DfX1pgdx+tWn5jRj8Gtl6Sz05sEr64bmV9Yo/cremOIW3/swAN+SUtmUn3hhnLetTRMaKRauZE/AF/8hCk+FZ7AhqwBsnNHlzS7O9pQbC3cXB8FNMzCLWDUwnsshf0iYCuH7/nmgenS6Vgn9b7QWJV+4EJuhsjrIC6e+P6lGyMMgUpKtg2xCFIbwOOVToceXmwGXH4Y1PS5+mgJ6e4vanyAjN41B17gFNtj7FbjH9jBpBe7pquvcRwn8v0d5OBEeE6Aqol3ASBhx/TvQs0q4xBeEPHoh1ysen/HBijhQ0xo6iA8wAUNnhJJGar38zFggCdEwOw1z32OlJ6O+v/AFAd9rDUM/dyFuQDJz80DVgaBEVfSVCPvL0xFFxhVe/NjksthroX8QpTtsHiRmkDOKpHhSdCc/nqtO0g/ IRftRoOe ANuy3yQPVDCUuY+haUCoPe88C1HQT4X2S5cwauEIjJFCSShf+QNVbbneB0MKHBLLUijAW/PU1ETXO2HSaPNKcbbRe+w21AeRDvxXLKRmrx18EjOkf1mWD5aWmPBuhd1sn8YLEQJB6umjb5/HQfZc2Va+2mKO5DWNsKRk5Jw1a/hBnMC0pMooLPHxVEcN+XTmckmXM2h+6gS3D05RXUgwLuwy0rOTUdcZigN6+KaIZEchVggQh3s3wq3ZPlj+Q0XjeIn7zEFMkS6EojErvuV4ryUhxc16IveOs7ap7IcyIqHfjsYZwLE8EHhAQ5GBciJ6a90Vf0KnZ0C1488W1Fjjz/55/MnZvbT44UO5yaYFo8+JRi/GJeaPtXFSjAWZ1OhqcdfTc 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: List-Subscribe: List-Unsubscribe: Similar to `access_process_vm` but specific to strings. Also chunks reads by page and utilizes `strscpy` for handling null termination. Signed-off-by: Jordan Rome --- include/linux/mm.h | 3 ++ mm/memory.c | 119 +++++++++++++++++++++++++++++++++++++++++++++ mm/nommu.c | 68 ++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) -- 2.43.5 diff --git a/include/linux/mm.h b/include/linux/mm.h index f02925447e59..f3a05b3eb2f2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2485,6 +2485,9 @@ extern int access_process_vm(struct task_struct *tsk, unsigned long addr, extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags); +extern int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags); + long get_user_pages_remote(struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, diff --git a/mm/memory.c b/mm/memory.c index 398c031be9ba..905e3f10fad0 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -6714,6 +6714,125 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, } EXPORT_SYMBOL_GPL(access_process_vm); +/* + * Copy a string from another process's address space as given in mm. + * If there is any error return -EFAULT. + */ +static int __copy_remote_vm_str(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags) +{ + void *old_buf = buf; + int err = 0; + + if (mmap_read_lock_killable(mm)) + return -EFAULT; + + /* Untag the address before looking up the VMA */ + addr = untagged_addr_remote(mm, addr); + + /* Avoid triggering the temporary warning in __get_user_pages */ + if (!vma_lookup(mm, addr)) { + err = -EFAULT; + goto out; + } + + while (len) { + int bytes, offset, retval, end; + void *maddr; + struct page *page; + struct vm_area_struct *vma = NULL; + + page = get_user_page_vma_remote(mm, addr, gup_flags, &vma); + + if (IS_ERR(page)) { + /* + * Treat as a total failure for now until we decide how + * to handle the CONFIG_HAVE_IOREMAP_PROT case and + * stack expansion. + */ + err = -EFAULT; + goto out; + } + + bytes = len; + offset = addr & (PAGE_SIZE - 1); + if (bytes > PAGE_SIZE - offset) + bytes = PAGE_SIZE - offset; + + maddr = kmap_local_page(page); + retval = strscpy(buf, maddr + offset, bytes); + unmap_and_put_page(page, maddr); + + if (retval > -1 && retval < bytes) { + /* found the end of the string */ + buf += retval; + goto out; + } + + if (retval == -E2BIG) { + retval = bytes; + /* + * Because strscpy always null terminates we need to + * copy the last byte in the page if we are going to + * load more pages + */ + if (bytes < len) { + end = bytes - 1; + copy_from_user_page(vma, + page, + addr + end, + buf + end, + maddr + (PAGE_SIZE - 1), + 1); + } + } + + len -= retval; + buf += retval; + addr += retval; + } + +out: + mmap_read_unlock(mm); + if (err) + return err; + + return buf - old_buf; +} + +/** + * copy_remote_vm_str - copy a string from another process's address space. + * @tsk: the task of the target address space + * @addr: start address to read from + * @buf: destination buffer + * @len: number of bytes to transfer + * @gup_flags: flags modifying lookup behaviour + * + * The caller must hold a reference on @mm. + * + * Return: number of bytes copied from @addr (source) to @buf (destination). + * If the source string is shorter than @len then return the length of the + * source string. If the source string is longer than @len, return @len. + * On any error, return -EFAULT. + */ +int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags) +{ + struct mm_struct *mm; + int ret; + + mm = get_task_mm(tsk); + if (!mm) + return -EFAULT; + + ret = __copy_remote_vm_str(mm, addr, buf, len, gup_flags); + + mmput(mm); + + return ret; +} +EXPORT_SYMBOL_GPL(copy_remote_vm_str); + /* * Print the name of a VMA. */ diff --git a/mm/nommu.c b/mm/nommu.c index 9cb6e99215e2..23281751b1eb 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1701,6 +1701,74 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in } EXPORT_SYMBOL_GPL(access_process_vm); +/* + * Copy a string from another process's address space as given in mm. + * If there is any error return -EFAULT. + */ +static int __copy_remote_vm_str(struct mm_struct *mm, unsigned long addr, + void *buf, int len) +{ + int ret = 0; + + if (mmap_read_lock_killable(mm)) + return -EFAULT; + + /* the access must start within one of the target process's mappings */ + vma = find_vma(mm, addr); + if (vma) { + /* don't overrun this mapping */ + if (addr + len >= vma->vm_end) + len = vma->vm_end - addr; + + /* only read mappings where it is permitted */ + if (vma->vm_flags & VM_MAYREAD) { + ret = strscpy(buf, addr, len); + if (ret == -E2BIG) + ret = len; + } else { + ret = -EFAULT; + } + } else { + ret = -EFAULT; + } + + mmap_read_unlock(mm); + return ret; +} + +/** + * copy_remote_vm_str - copy a string from another process's address space. + * @tsk: the task of the target address space + * @addr: start address to read from + * @buf: destination buffer + * @len: number of bytes to transfer + * @gup_flags: flags modifying lookup behaviour (unused) + * + * The caller must hold a reference on @mm. + * + * Return: number of bytes copied from @addr (source) to @buf (destination). + * If the source string is shorter than @len then return the length of the + * source string. If the source string is longer than @len, return @len. + * On any error, return -EFAULT. + */ +int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags) +{ + struct mm_struct *mm; + int ret; + + mm = get_task_mm(tsk); + if (!mm) + return -EFAULT; + + ret = __copy_remote_vm_str(mm, addr, buf, len); + + mmput(mm); + + return ret; +} +EXPORT_SYMBOL_GPL(copy_remote_vm_str); + /** * nommu_shrink_inode_mappings - Shrink the shared mappings on an inode * @inode: The inode to check