From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D1CB51D513 for ; Mon, 7 Sep 2026 16:52:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799977; cv=none; b=Xxkre7mCPEklSayKNpY6brULOZQ74nbtUcvr0bdsjlejSrALlEO/MpYb+YX5LLYSwWnCb3yHDZvLOE42yyb8jasbvz7yLpcu9pQQoLabVPh91OLoy5CvIkIBk544/l8lyc3SbTXy7aZfW9A3HyQ8qcmgNBiMloXVlUTuDYh9sso= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799977; c=relaxed/simple; bh=Q0tWSBlQLFk3oEvXn8y4hkhcwkljNZY80ooFvpI2RrA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SiHSIa7Lnwt5u0MEBi1goZE3nWvgmKxKZg3zHErhlxbeT0tPKM4rIobB798ApyPZhqbcnNmxaIBCu26zQLCxhsorpyTJxYTIDZM6x03VbZDJ2RjIEj7jrMAa//9AP/6fjumd3X7zuQwXJsOUoCH7GLp1Ylegg4nda4EG11M92hI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=U9dAsqCs; arc=none smtp.client-ip=209.85.221.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="U9dAsqCs" Received: by mail-wr1-f50.google.com with SMTP id ffacd0b85a97d-47de0093c42so3648719f8f.3 for ; Mon, 07 Sep 2026 09:52:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799974; x=1789404774; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=aYJwxo5Nb9UiMMNksSdgP6g3PKaxvBMYGoOE/hW9Rkk=; b=U9dAsqCsC1Ng7j2pEbxxLUChmGYvpqUervfvREs7heCNRIOn9cu9aMRFNGKnSknHYh C2fzC0K9xb39/myBFYeRVx0hBDg5E8IxTeGv8un+Cfc+9Nehw7osc1sVHg5QZOdbPF47 yfSFYlde+XetyaAago/GAJPiihSea7kU1TF0Sizw2mw0kdeWHTMohDTkWjyqlPed9mm9 sWQqemLNx+AFhc1cNhBSKi6o5I1gjYYdoPQZEJMDKIAOYPenHBeIjyb9LB2YihTIWlAA QKT0rBPph+hU9wAV3xVc1MbGyc5PlG68LUcG2d0ob5Cmh3L36EmrkZOJCC6WZQIsjigb s8jw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799974; x=1789404774; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=aYJwxo5Nb9UiMMNksSdgP6g3PKaxvBMYGoOE/hW9Rkk=; b=BGlX0738VZK8ITvfjDkNEAmEtN5QQjuHIkt7aihbqfPvCisl8xZyYsqP3fnWGSL+KJ PLsHJw7lCVG3f8Juzq/Xix6WHcHmCaVt2SGvZGNrBdwCF8uWmzsvMJH7R0Uk8agTIAZu SGW+Bm+njmAqqgLTv4ze+UMmKBIxa8eA2LDMczZhQ/kwvnlpqO6NXErHNqATSw89Xyp1 U2rRtUTjgRkP2ZC7l2F0nlaEwGlj4AyYWpJpTB5Kdub73LV2NcfsSZCg+9IyxiPS/LEf CDKWBbRllxY9Y6LhUfEEClV0+QdIQJISr6X7q02NjSGhLwLFdWxY+xuBNkWvq/gnXWGC NtVQ== X-Forwarded-Encrypted: i=1; AKwUvBwwuM1PVacK/IIuDoRlJ1EREwO2s46g6zPfCTfPmKn40UfgVcQnoSKGBzWjCLQnr3VCeo1eQJgpQkhbBKE=@vger.kernel.org X-Gm-Message-State: AFuF++nJAXPBVHt04KMOMDrPz05BH8Fb8oNd+KmjcRYbQWOlMu9VYSOc Inpr+zHko+LkkImS83r8BKSz/iXinzChGwkw57LawwsSl/aD51h8ojHN X-Gm-Gg: AYBFou2PiIBTpZMXAI9mbFNl6V6yoMl3RnUboA0RpkXLer42XprvfhRAzyEQMSyTYRR BYjHkqjEQ1iUIIrfVJbKAxsuhpvCulrHq5OmqdFIEBjCAi87lWiSfCd2/3tajh0838g7kuyGgww Zctgtzllya/tH+KMdxj0YZvKrV7Oz2cTawpmGxVhE7eOEaS3CXViqrHAtrcb35czND3NSjs2qYA 8vxo/bwslZfEJgOciSQEZtDWr5wOEIQSjjnf93zuUf9hI1PgeONTSBK6uTwq3kNZFG65iKckWT1 rvNB1NpnNprAiVz66U96X8R1zRkR5YZeY1WHEPV0RgtdbtqOcSGkG5PC8SKUaE/V0he05JH4QsD LbQHy96yjKCu68StxQuKIdT7JLyC0uCh2pKSK1WtZrp55NJzIPLp+5aTSGEvyTfzGIxRdL1svvu 3ar3xdKXvsf5RGUhsoKgvKccbr7kPVUMuVVW6eLrOCMkXiCUH65SC5/QcY4jMgQN/3xO8hwCIi6 A== X-Received: by 2002:a05:600c:4fc9:b0:49c:fc6e:8cb9 with SMTP id 5b1f17b1804b1-49cfc6e8e1emr209497255e9.29.1788799973392; Mon, 07 Sep 2026 09:52:53 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.52.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:52:52 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 1/7] mm: Add copy_remote_mm_str() Date: Mon, 7 Sep 2026 19:52:14 +0300 Message-ID: <20260907165220.52431-2-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" copy_remote_vm_str() gets the target address space from a struct task_struct. This does not work for an address space that exists but is not yet associated with a task_struct, such as the mm held by struct linux_binprm during exec. Add copy_remote_mm_str(), which operates directly on a struct mm_struct. Use a common internal interface for the MMU and NOMMU implementations and define both public wrappers in mm/util.c. Preserve the existing copy_remote_vm_str() behavior, including handling zero-length requests before acquiring the task's mm. Signed-off-by: Anastasios Papagiannis Acked-by: Lorenzo Stoakes (ARM) --- include/linux/mm.h | 2 ++ mm/internal.h | 5 ++++ mm/memory.c | 41 ++---------------------------- mm/nommu.c | 41 ++---------------------------- mm/util.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 78 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index dd09c438fa23..d5bde1f71a97 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3326,6 +3326,8 @@ extern int access_remote_vm(struct mm_struct *mm, uns= igned long addr, void *buf, int len, unsigned int gup_flags); =20 #ifdef CONFIG_BPF_SYSCALL +extern int copy_remote_mm_str(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); #endif diff --git a/mm/internal.h b/mm/internal.h index 38b1165212c9..8264a346d18a 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -25,6 +25,11 @@ struct folio_batch; struct hstate; =20 +#ifdef CONFIG_BPF_SYSCALL +int __copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags); +#endif + struct huge_bootmem_page { struct list_head list; struct hstate *hstate; diff --git a/mm/memory.c b/mm/memory.c index 8b0c2c735d3d..fe2f5e988fb9 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -7331,8 +7331,8 @@ 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) +int __copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags) { void *old_buf =3D buf; int err =3D 0; @@ -7407,43 +7407,6 @@ static int __copy_remote_vm_str(struct mm_struct *mm= , unsigned long addr, 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 copy - * @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= ); - * not including the trailing NUL. Always guaranteed to leave NUL-terminat= ed - * buffer. 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; - - if (unlikely(len =3D=3D 0)) - return 0; - - mm =3D get_task_mm(tsk); - if (!mm) { - *(char *)buf =3D '\0'; - return -EFAULT; - } - - ret =3D __copy_remote_vm_str(mm, addr, buf, len, gup_flags); - - mmput(mm); - - return ret; -} -EXPORT_SYMBOL_GPL(copy_remote_vm_str); #endif /* CONFIG_BPF_SYSCALL */ =20 /* diff --git a/mm/nommu.c b/mm/nommu.c index 498e01ee40b0..98596e60311f 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1746,8 +1746,8 @@ 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 __copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags) { unsigned long addr_end; struct vm_area_struct *vma; @@ -1781,43 +1781,6 @@ static int __copy_remote_vm_str(struct mm_struct *mm= , unsigned long addr, 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 copy - * @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= ); - * not including the trailing NUL. Always guaranteed to leave NUL-terminat= ed - * buffer. 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; - - if (unlikely(len =3D=3D 0)) - return 0; - - mm =3D get_task_mm(tsk); - if (!mm) { - *(char *)buf =3D '\0'; - return -EFAULT; - } - - ret =3D __copy_remote_vm_str(mm, addr, buf, len); - - mmput(mm); - - return ret; -} -EXPORT_SYMBOL_GPL(copy_remote_vm_str); #endif /* CONFIG_BPF_SYSCALL */ =20 /** diff --git a/mm/util.c b/mm/util.c index bf0513d1d3d0..2eca27b02791 100644 --- a/mm/util.c +++ b/mm/util.c @@ -1061,6 +1061,68 @@ int get_cmdline(struct task_struct *task, char *buff= er, int buflen) return res; } =20 +#ifdef CONFIG_BPF_SYSCALL +/** + * copy_remote_mm_str - copy a string from a remote address space. + * @mm: the remote address space + * @addr: start address to read from + * @buf: destination buffer + * @len: number of bytes to copy + * @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= ), + * not including the trailing NUL. If @len is zero, return 0 without acces= sing + * @buf. Otherwise, @buf is always NUL-terminated. On any error, return + * -EFAULT. + */ +int copy_remote_mm_str(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags) +{ + if (unlikely(len =3D=3D 0)) + return 0; + + return __copy_remote_mm_str(mm, addr, buf, len, gup_flags); +} + +/** + * 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 copy + * @gup_flags: flags modifying lookup behaviour + * + * Return: number of bytes copied from @addr (source) to @buf (destination= ), + * not including the trailing NUL. If @len is zero, return 0 without acces= sing + * @buf. Otherwise, @buf is always NUL-terminated. 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; + + if (unlikely(len =3D=3D 0)) + return 0; + + mm =3D get_task_mm(tsk); + if (!mm) { + *(char *)buf =3D '\0'; + return -EFAULT; + } + + ret =3D __copy_remote_mm_str(mm, addr, buf, len, gup_flags); + + mmput(mm); + + return ret; +} +EXPORT_SYMBOL_GPL(copy_remote_vm_str); +#endif /* CONFIG_BPF_SYSCALL */ + int __weak memcmp_pages(struct page *page1, struct page *page2) { char *addr1, *addr2; --=20 2.55.0 From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AA53451D50C for ; Mon, 7 Sep 2026 16:53:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799982; cv=none; b=esoGxNNmFC4XeGSDgBmFFUbjWMl1tTHNzSiU13pmJvDtfgNrmO8fLig9GwMqYCTl3+1VWXqMV/8/U5MlQ/oDnvb2/VyTAsYi+8qLuinJx4aEwq7SLtd4boPrqMnkfR8K+yZjzbe8x6lQ0/HaImlzZ9ulevIGPXTtS2geRl7sQ30= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799982; c=relaxed/simple; bh=oxBm833C8T+jxHgAdbU6D4xcv4E4TYoli1xZPpTW0yQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UR+7urHHRZ3wFwEf4LAZTj3QIQnFRKaUVZU+xX0D+SKUP98jEDi3nY1FGB7paYvwvHZTEpt82yHzDNhgVvJfFtV1rq/PhugMI3p+VutqXKoYI6lmo9q1FQtkvrkZr+g3P+PRMeC+OomnaxPTNNYVwpB2anN/9//D+HsKxqHYcDk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jfBW7WzR; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jfBW7WzR" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-499b2981a7bso40194165e9.3 for ; Mon, 07 Sep 2026 09:53:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799978; x=1789404778; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=BcITG13Gvl8i0HA4g724jWVmnWns/ceZ5ECxTEaQlok=; b=jfBW7WzRy1LDdYAfQnEc9I7mCDw90Ps5LjnC8imAutx+H5oG0GQNtSpUarqQPRbWvc dXgYKxKmJTx1ZVCWaubdw1ZKolpVgVxr9pwoO+RzGUkmtSW4oHtHB4vFDCKUt83lUEsq 0krNRDpkkYQXu+QbiTCavOwrrSvxY34ZRAzpqMYg8VtF/rw+efZUbxzwmd89/4R2xULf ZSrFj+ctcmCm+CrY1oAN9JEugFOMgn/8aX1C4MZXxLia6XQqpjKnZn1iUf/2O0La3qk9 SwjoKhy6G2allTRGy4WXZDkcM3J8l59twAQOMwYkWiM7O1rxm59RVwsjW1yHieQ/nk6D 68QA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799978; x=1789404778; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=BcITG13Gvl8i0HA4g724jWVmnWns/ceZ5ECxTEaQlok=; b=clUG/6ICWOowL4yT25UnJ0i96wD6FdU7E5TTkViAzSR4fEUYe5FAgcONJwnMPNsi5r v1w020czD0dc/lNWddRiV6IRCzKHdLTNf9AJu5p7t3jNddi8l/X7oOfkhXK95nEZT0ul sFNz5OPLOyK0wUK5Zi3NuvG4lk+E+lyOQU/LkIkLLCYIf/PaTGhcWWuMZzscD4sCtsr0 aptzHsjV85Gq3aTqXq/OqWg6Z+vproAhtPJ9TOFtxXW4z78kXrbzNUMs0ufB9gTOgBED lsudym+l5hBE+EfkWv1BY9Tpy1UyB+vKlZZjOZH+l7eZkjn0cacmT4EIV5hsQc2QBMXE U9nQ== X-Forwarded-Encrypted: i=1; AKwUvBwBsKeseLManG4bmIfaDCTT7jmOmbfEsOmBYDKqI4DctrJW5fIiG13AbAd6D7taC/Ce6qib8tdf2ao2N0E=@vger.kernel.org X-Gm-Message-State: AFuF++mP+XpAUZUcPKUh2Kwb49WhjBeHDj/rLZt0vSia7Zwog3kQ0JWZ sVBurojF3WbGJ9EK2cBO25OqlYXpB1nEcS7qHWX4bJLKB8PzPbXA7Ztf X-Gm-Gg: AYBFou0V/18DWILo2JRBBQB9YSd088Qg7jjtYhEykDScnma8fMqKOrSVe1niNzgnbSQ MBTd96kAIzT3DfTYCCHu+V2VGGGiX/XMeLxiq3TvwyjMnpfFfQUiXV7Mdm6wlsBcto5Aj58K9cm pBCkTqF1OPmwG465WSX+6/j4Tx8ZSe+JzMYE7d9WzvX0LNOwJ+u8S8jmQQXXh4O8YhJjVNRWrfD 9Vxd1iqznVMw1EwXk8QHH0cAJcw0wI6ByIPc3MrYq8omRaOb5oIS7CFAmvqfEGY6kG4miKcwTHi PiJHKeCNCEvYexp9znp6bQcepybxb9e0ROQyxHHRc7U0RsXo67ox/GV/WvGLTim8jEoCC0oH3vU t3MmAEluVP62jmzGRUhgujLxnue00HHUp5e/mNUUVNj0tfomKVtoNwHUKRuhg/7ag+CZYDMLlUH dJJLVhvq2qjlHFyj9vUhzBRFpGGz47k1wWcQI66HC223su6TvhZ3JTtRWh1UaXBH+fWMbh8RFlh g== X-Received: by 2002:a05:600c:8b6d:b0:499:a277:e8b5 with SMTP id 5b1f17b1804b1-49cf7fdd67emr472395245e9.3.1788799978274; Mon, 07 Sep 2026 09:52:58 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.52.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:52:57 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 2/7] exec: Clear bprm->mm before dropping its reference Date: Mon, 7 Sep 2026 19:52:15 +0300 Message-ID: <20260907165220.52431-3-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Once mmput() drops the final reference to bprm->mm, the pointer must no longer remain accessible through struct linux_binprm. The successful exec path and the bprm initialization error path already clear bprm->mm when ownership is transferred or released. Do the same in free_bprm() before calling mmput(). This is required for BPF kfuncs where bprm->mm is either NULL or points to a live mm_struct to ensure safe access. Signed-off-by: Anastasios Papagiannis Reviewed-by: Sun Jian --- fs/exec.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 745f6eb5279e..4ddd403fd91c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1456,9 +1456,12 @@ void bprm_drop_loader(struct linux_binprm *bprm) =20 static void free_bprm(struct linux_binprm *bprm) { - if (bprm->mm) { + struct mm_struct *mm =3D bprm->mm; + + if (mm) { acct_arg_size(bprm, 0); - mmput(bprm->mm); + bprm->mm =3D NULL; + mmput(mm); } if (bprm->user_ns) put_user_ns(bprm->user_ns); --=20 2.55.0 From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7782B51FCC8 for ; Mon, 7 Sep 2026 16:53:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799985; cv=none; b=plLK4MrU0X6vNskuUinGkPA5uh271WbW39Mdu7S4IQgLVQC4kwnfeEmZLJ91fKxcyXVP+/pH0jt76ilIrwaXGECUrZur6G633irMY36+O0I4PpbrKOhJNO///L3BWgoC+UhGizNvMU1wZo9ANsfHF1sBGs2JgaxVW6pXRtgWeRM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799985; c=relaxed/simple; bh=mSyr5ubBmdluKcCLSrzLFo733QFcQsmlfRW8JWiocpU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M9GjjJtBaag/yay4G6B+GQLwTQRC/WZ6tCDEpd0Z5gFq8Xd//k8q/77qZeGF2MxedORfyBidsCTjzk4aXyouHSZk66sWXHKQeGDLLfpwd3ai1OUDbJ4l7D+7TdL/vQl4eXjT1A8WvvoeG5VxE2Hy11dq/NnnHhXyXu/2ExHsWy8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Jmd3/vPH; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Jmd3/vPH" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-49b392ccaacso56667405e9.2 for ; Mon, 07 Sep 2026 09:53:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799982; x=1789404782; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=WsJst8PFRStuSDVwSJV/FL2xzbq9iEwS7FDAi7P/CCA=; b=Jmd3/vPHlMNlIXCIv42F3gv4nKW8TAf2xV3YcAgVtta4Z3J/0ndsuCK4SXOrK9wfKr gfVyGN08Fv8qQoH5SlpJrEJs9J9YZezxO9z3PablBebYEMmpvGcR5mBNiolnG+yO8QNc qCbJha8S5ccRcUoMzv6st+LvVEOblPgdPKMOTj/yiqlcUZAH9C6Gtt841mK2uZ6y2ank wmw4lrxjyH9McrrkvStuhKJFza+yMLKn5aBB/uVHw3HTnqKbRcU73kCpsET8LGlm/srF rYG/kx2Q11O4UADfB91ul2pCZ3TG2MLiG1xJjR3XjorGcCKa3qpJhZJKBTMOvDJV76sY 2U+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799982; x=1789404782; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=WsJst8PFRStuSDVwSJV/FL2xzbq9iEwS7FDAi7P/CCA=; b=T7ifznBN46pr9VPC7dnK5Vu+06b7r38jQeyXepCKdoVUKxljsm3cedWm5FzbTpoOw8 gPSTV4xb4vDmHCzvcR/TyL5jNl0Tq3/0GvwTuIq45yv1Xn6yppq4mBdgetK1mqhQt1qx ugYyESSYdKVZE7wPhXMlTNrf7z+VgdJ5Fx3DIZz3CKnFO1sVPE0a69aEFTCZ6jfQKfi0 3QfD6fPka58I7iLfIKYLdPfIwgwdd3Hvdq+E1Ex7L4R/6jm/zWLy9QLoSz9ZK/y4J1q0 Z3o/Trptr80Kxh031bSaa49MFCe5JaiS+x4+D1+cA4nd3Yqrcwe8JJTJrLmL06FBsdxQ cREw== X-Forwarded-Encrypted: i=1; AKwUvBw2GA/eovLHcYnD6XaRnqqTA8IEIn/2/1tflGp3Va/2r7m7Vc1YovJE7Lg2wDrYumtaJESOU+ckl1EAFys=@vger.kernel.org X-Gm-Message-State: AFuF++lMIr4Gonvl6U0ZVoel/e6aO7Eub7OtkPhW8y98EDlUWzNuaVMj /JBpxrf26IBmScvz8SwCSnjsgUXIrU4ugX0h0zoP/+mYL5Dv5n1btlYD+3qasm9xxqY= X-Gm-Gg: AYBFou3s2DBeUJjAwY0bN4aYft9aChwMgRp/tWlcdckEeYAVvcs7XLSHkVfHCOiGvSv DudXIMuxO4YRLXYmswEWIdG1rkzsXhtp16RMFUfW6v0GW1HDav4xBasYFyoLjsJVW5+HxEOy6ol dVT+88NhgohuTApHPP/6rBtafV3FIEFiQ67kgFXYhl77AIsRI3rwgIIZIQUzPTM4s9P986tl5W3 C/LgdigMc7dXIIw97Sv7SpSsPzEjZGxpbbpxNGIICbto3Knm32DIXslSQw7lxpXKb8JLDnSv/yD 99jGIMb9p+P7YmfVkuh7o3RIEN1sJDLLwKu7HiOQQznqx79XKgvyZVtzLbXDDezR1GEgdI+ukmC sxWxo3Q1LmFX4xG0c0z8lB+6c8A1PxTLG8zwuCsh6sXhH3CTfjwdtUhMU3j0iYp4S2SODehV6pr WD0tSlR9UXbtOA8Etb1NV+Qm8LB7WoM6o1o/ScdftPWUSqOd0PVJew9ctdlL4ksEwR+WEG5Xb4Q Q== X-Received: by 2002:a05:600d:6451:10b0:49c:fa21:1c8c with SMTP id 5b1f17b1804b1-49cfa211d1amr150738145e9.33.1788799981617; Mon, 07 Sep 2026 09:53:01 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.52.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:53:01 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 3/7] bpf: Add user memory access kfuncs for mm_struct Date: Mon, 7 Sep 2026 19:52:16 +0300 Message-ID: <20260907165220.52431-4-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On CONFIG_MMU kernels, when security_bprm_check() runs, the argument and environment strings for the exec have been copied into bprm->mm. The new address space is not associated with a task_struct until exec_mmap(), so existing BPF user memory helpers cannot access it. Add bpf_copy_from_user_mm() and bpf_copy_from_user_mm_str() kfuncs. Both take a struct mm_struct pointer directly, allowing callers to access trusted address spaces that are not associated with a task_struct. bpf_copy_from_user_mm() has similar semantics to bpf_copy_from_user_task(). bpf_copy_from_user_mm_str() copies one NUL-terminated string and returns its size including the NUL terminator. It accepts BPF_F_PAD_ZEROS to clear unused destination bytes on success. Refactor bpf_copy_from_user_task() and bpf_copy_from_user_task_str() to acquire the task's mm with get_task_mm() and delegate to the corresponding mm-based implementations. No behavior change is intended for the existing task-based interfaces. Register both new kfuncs and mark them KF_SLEEPABLE because accessing a remote address space can fault. Signed-off-by: Anastasios Papagiannis --- kernel/bpf/helpers.c | 142 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 113 insertions(+), 29 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index b3cc5c8fc875..d3c564437ad0 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -32,6 +32,10 @@ =20 #include "../../lib/kstrtox.h" =20 +__bpf_kfunc int bpf_copy_from_user_mm(void *dst, u32 dst__sz, + const void __user *unsafe_ptr__ign, + struct mm_struct *mm, u64 flags); + /* If kernel subsystem is allowing eBPF programs to call this function, * inside its own verifier_ops->get_func_proto() callback it should return * bpf_map_lookup_elem_proto, so that verifier can properly check the argu= ments @@ -682,22 +686,15 @@ const struct bpf_func_proto bpf_copy_from_user_proto = =3D { BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size, const void __user *, user_ptr, struct task_struct *, tsk, u64, flags) { + struct mm_struct *mm; int ret; =20 - /* flags is not used yet */ - if (unlikely(flags)) - return -EINVAL; - - if (unlikely(!size)) - return 0; - - ret =3D access_process_vm(tsk, (unsigned long)user_ptr, dst, size, 0); - if (ret =3D=3D size) - return 0; + mm =3D get_task_mm(tsk); + ret =3D bpf_copy_from_user_mm(dst, size, user_ptr, mm, flags); + if (mm) + mmput(mm); =20 - memset(dst, 0, size); - /* Return -EFAULT for partial read */ - return ret < 0 ? ret : -EFAULT; + return ret; } =20 const struct bpf_func_proto bpf_copy_from_user_task_proto =3D { @@ -3658,6 +3655,100 @@ __bpf_kfunc int bpf_copy_from_user_str(void *dst, u= 32 dst__sz, const void __user return ret + 1; } =20 +/** + * bpf_copy_from_user_mm() - Copy data from an address space + * @dst: Destination address, in kernel space + * @dst__sz: Number of bytes to copy + * @unsafe_ptr__ign: Source address in the address space + * @mm: Address space to copy from + * @flags: Reserved for future use; must be zero + * + * Copies data from the user address space associated with @mm. The destin= ation + * is zeroed if an attempted copy cannot be completed in full. Unsupported + * flags return -EINVAL without modifying @dst. + * + * Return: 0 on success, -EINVAL if @flags is non-zero, or -EFAULT if the = copy + * fails or is partial. + */ +__bpf_kfunc int bpf_copy_from_user_mm(void *dst, u32 dst__sz, + const void __user *unsafe_ptr__ign, + struct mm_struct *mm, u64 flags) +{ + int ret; + + if (unlikely(flags)) + return -EINVAL; + + if (unlikely(!dst__sz)) + return 0; + + if (unlikely(!mm)) { + memset(dst, 0, dst__sz); + return -EFAULT; + } + + ret =3D access_remote_vm(mm, (unsigned long)unsafe_ptr__ign, + dst, dst__sz, 0); + if (ret =3D=3D dst__sz) + return 0; + + memset(dst, 0, dst__sz); + return ret < 0 ? ret : -EFAULT; +} + +/** + * bpf_copy_from_user_mm_str() - Copy a string from an address space + * @dst: Destination address, in kernel space. This buffer mus= t be + * at least @dst__sz bytes long + * @dst__sz: Maximum number of bytes to copy, including the traili= ng NUL + * @unsafe_ptr__ign: Source address in the address space + * @mm: Address space to copy from + * @flags: The only supported flag is BPF_F_PAD_ZEROS + * + * Copies a NUL-terminated string from the user address space associated w= ith + * @mm. If the string is too long, @dst is still NUL-terminated unless @ds= t__sz + * is zero. + * + * If the flags are valid and BPF_F_PAD_ZEROS is set, the unused portion of + * @dst is cleared on success and all of @dst is cleared on a copy failure. + * Unsupported flags return -EINVAL without modifying @dst. + * + * Return: The number of copied bytes including the NUL terminator on succ= ess, + * or a negative error code on failure. + */ +__bpf_kfunc int bpf_copy_from_user_mm_str(void *dst, u32 dst__sz, + const void __user *unsafe_ptr__ign, + struct mm_struct *mm, u64 flags) +{ + int ret; + + if (unlikely(flags & ~BPF_F_PAD_ZEROS)) + return -EINVAL; + + if (unlikely(dst__sz =3D=3D 0)) + return 0; + + if (unlikely(!mm)) { + if (flags & BPF_F_PAD_ZEROS) + memset(dst, 0, dst__sz); + else + *(char *)dst =3D '\0'; + return -EFAULT; + } + + ret =3D copy_remote_mm_str(mm, (unsigned long)unsafe_ptr__ign, dst, dst__= sz, 0); + if (ret < 0) { + if (flags & BPF_F_PAD_ZEROS) + memset(dst, 0, dst__sz); + return ret; + } + + if (flags & BPF_F_PAD_ZEROS) + memset(dst + ret, 0, dst__sz - ret); + + return ret + 1; +} + /** * bpf_copy_from_user_task_str() - Copy a string from an task's address sp= ace * @dst: Destination address, in kernel space. This buffer mu= st be @@ -3681,25 +3772,16 @@ __bpf_kfunc int bpf_copy_from_user_task_str(void *d= st, u32 dst__sz, const void __user *unsafe_ptr__ign, struct task_struct *tsk, u64 flags) { + struct mm_struct *mm; int ret; =20 - if (unlikely(flags & ~BPF_F_PAD_ZEROS)) - return -EINVAL; - - if (unlikely(dst__sz =3D=3D 0)) - return 0; + mm =3D get_task_mm(tsk); + ret =3D bpf_copy_from_user_mm_str(dst, dst__sz, unsafe_ptr__ign, + mm, flags); + if (mm) + mmput(mm); =20 - ret =3D copy_remote_vm_str(tsk, (unsigned long)unsafe_ptr__ign, dst, dst_= _sz, 0); - if (ret < 0) { - if (flags & BPF_F_PAD_ZEROS) - memset(dst, 0, dst__sz); - return ret; - } - - if (flags & BPF_F_PAD_ZEROS) - memset(dst + ret, 0, dst__sz - ret); - - return ret + 1; + return ret; } =20 /* Keep unsigned long in prototype so that kfunc is usable when emitted to @@ -4924,6 +5006,8 @@ BTF_ID_FLAGS(func, bpf_iter_bits_new, KF_ITER_NEW) BTF_ID_FLAGS(func, bpf_iter_bits_next, KF_ITER_NEXT | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_iter_bits_destroy, KF_ITER_DESTROY) BTF_ID_FLAGS(func, bpf_copy_from_user_str, KF_SLEEPABLE) +BTF_ID_FLAGS(func, bpf_copy_from_user_mm, KF_SLEEPABLE) +BTF_ID_FLAGS(func, bpf_copy_from_user_mm_str, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_copy_from_user_task_str, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_get_kmem_cache) BTF_ID_FLAGS(func, bpf_iter_kmem_cache_new, KF_ITER_NEW | KF_SLEEPABLE) --=20 2.55.0 From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 878E952122B for ; Mon, 7 Sep 2026 16:53:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799988; cv=none; b=Q5M4CPz6elfqY6kLX2s7H6QS/6TDS8ry/YAxsGZZLnAGIiZ5qrmmk+VgGcwkx21afFqJLh2+Zja2lywrtKSO6Jp60MmAkFn9rrl0USbfhLtPrMkEw7An77p2UjiDfljyCRdWn8sHaFpGJpcGRWjSs7ZHOcsUdBHz3HDOzH75QdE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799988; c=relaxed/simple; bh=R3NKE8VV7/HGFaVaAkyaFS//KWA1lQPQoXgESTqRSFY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PwRnoQjrCqmnAnC6ZmAOGpc2iF/hpdZv2lvEUFhc9Pg9MMb1zwFgOUeDf0uYCzwi2gKDax85joOnTQ3xyRRZJxw52DGHmeZflqA6wVFe3N07r8dUG1JpZCHjysmGY61Vfdih+fEWfWxsKM06EWEVJJxrFlfNNIk/NLJ4liZHHZ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=qQfgxVBd; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="qQfgxVBd" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-49b96837ca3so29955525e9.3 for ; Mon, 07 Sep 2026 09:53:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799985; x=1789404785; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=XAeQPdPGwWZkycRcbqHqvUFSglicl66turt58h60TpQ=; b=qQfgxVBdYHALDM8ysUetakrcOL/+wv44doC0iXNdGiWZ+YeOeYKW1cU0cYuhF7sQ6p 5G+R3jnC4IQIsn8CLP7ChtEvJiKd59FPO7lCdi74pgxBOf/8IyoxAtnN3AuE8r15hOjh hzXllWXyex75czpT14rftxHj7A2YDKDV87AWWNuIknMAkViO7pKno+8npEqiOBi4usQr wxX0T7twXd/9BuIbreM3NqQT/0luxObM2+VtTnXB899GSLyZsub/8vPfyitpOX6tTdrL 0NCaWIeQ2CyO7BI2pJRW48vhoCpEv3zBythIKSvMPF6rYPIvyoZELWyuFISiJitzvgAT JqOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799985; x=1789404785; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=XAeQPdPGwWZkycRcbqHqvUFSglicl66turt58h60TpQ=; b=puTQWd9Hs1zgRSy8/KElZjvcMR/CdYXaojUaSburA5kLXJc9cL/D/yIk+eZxCkB0el 9WHbUgbHeACPl3vm7ArlGTTpkpOVWrKE/uPSjbuVrUDrch9BfDRM5FBKUJXX52vAHZBi WPfoKkmmJhdsnyDMUsgntl3hhlGxQPYiTvbiXp3xBc67yyuqi+mi2+oL7nnLvuE2M+kN lr/aaO7XcRjV3e3pyoaF/0wSZ5MoQ9auVS7QQr5uNEAehdEN84puv8jZixS+4zQ4qj+W w+lN/MOf8k22UHE3kAU5a0V4v42T9MqV82DROIDY1N2mP/Lp//o8sLIPRApsRBpy83Uw DIdA== X-Forwarded-Encrypted: i=1; AKwUvBzftKIRi74sxdYnBBo/Az+TU04dwGEHQMnPPrzQIBpvjIOhJ8cNchDgrP4n0/npVJgA0bLVdOPKM/2ueNw=@vger.kernel.org X-Gm-Message-State: AFuF++ntWrDwCe9i6A8utMXmsHew7AmhCy7gv3AUjMLCphCpIvQ4DZz8 dWEiCCvOQ0D86Yd8zQGUYc4ewwbsiXuCsGGd0YfiFHX1brT8eXT9L/Sb X-Gm-Gg: AYBFou2InWl8w+N6n4xXCUa/lorpciM8Ir8S/2NEoC6RNixeK+eVpZMLCWNGqR39y3t OIdKSHnCRf0y/tn5wUmjvFS8h5Z7PGSjX5MJ4mwytmEUpw3wVyZXbPtSvoKNxTCcOUn9R51Weo3 3gCl0MZikMOAk2M1Z04OYOGYKpwAmE8U8aNr1jTn38lkPHurtO5oeUHVaz9q1aMEjKYuS/qcpO5 FG62I1HYcxQ8/beJIiu9YkwZLtGu4kRmpStVntIJsRT2wA6bdgLz/TlDVhGUj0FJ4AbkpxSNJir nvdREAPEQMMofTJ3TQO0LjZNAfDtNmomVOw06icLaa9Ijs4JEXiXTIInL4KDWf8N7DQ64/QSGUp 7fNadAy3XK5IKNcgQTlChEy6O47Pv7p4vG1H8V6xYhn7w1NFhYSxbKTspeYlV9uVmFqbRxSL/Gh tkUkcl9bL5dLzeYUk91NSh06iM7BBRUTTV6ISBAFt1GgAhE+8lj9sEHsuVFwYFrgcZd2X0cbGYb g== X-Received: by 2002:a05:600c:474a:b0:49c:e42b:a4ac with SMTP id 5b1f17b1804b1-49cf823f60amr212091925e9.11.1788799984684; Mon, 07 Sep 2026 09:53:04 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.53.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:53:04 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 4/7] bpf: Allow reads through trusted-or-null BTF pointers Date: Mon, 7 Sep 2026 19:52:17 +0300 Message-ID: <20260907165220.52431-5-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, a trusted-or-null pointer (i.e. PTR_TO_BTF_ID|PTR_TRUSTED|PTR_MAYBE_NULL) has to be checked for NULL before it can be dereferenced. Marking a field from PTR_TO_BTF_ID typing to trusted-or-null can reject programs that previously dereferenced the pointer directly. This is useful as we need to mark new fields as trusted in order to pass those as arguments to kfuncs. Allow reads through pointers marked as PTR_TO_BTF_ID|PTR_TRUSTED|PTR_MAYBE_NULL without an explicit NULL check. Treat these pointers as potentially faulting so the reads happen through BPF_PROBE_MEM. If a read produces another BTF pointer, clear its trusted flags and mark it as PTR_UNTRUSTED. This applies only to reads. Other cases still require an explicit NULL check. After such a check, the pointer retains PTR_TRUSTED and can be used normally. The unchecked read path has two consequences: 1. It uses BPF_PROBE_MEM, which is slower than a normal load. An explicit NULL check refines the pointer to PTR_TRUSTED and allows a normal load. 2. A faulting read returns zero, which is indistinguishable from a legitimately zero-valued field. Programs that need to distinguish those cases must check the pointer before reading the field. The next patch updates current tests and also introduces more checks to ensure this change does not break anything. Signed-off-by: Anastasios Papagiannis --- include/linux/bpf_verifier.h | 9 ++++++++- kernel/bpf/verifier.c | 12 +++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 9727df5af83a..4f032ad83c67 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -1339,6 +1339,11 @@ static inline bool bpf_is_ptr_to_mem_or_btf_id(enum = bpf_reg_type type) } } =20 +static inline bool bpf_is_trusted_or_null_btf_ptr(enum bpf_reg_type type) +{ + return type =3D=3D (PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL); +} + static inline bool bpf_may_fault_on_deref(enum bpf_reg_type type) { /* @@ -1346,7 +1351,9 @@ static inline bool bpf_may_fault_on_deref(enum bpf_re= g_type type) * protection, that is, the ones bpf_convert_ctx_accesses() has to * turn a BPF_LDX into a BPF_PROBE_MEM one for. */ - return type =3D=3D PTR_TO_BTF_ID || (type_flag(type) & PTR_UNTRUSTED); + return type =3D=3D PTR_TO_BTF_ID || + (type_flag(type) & PTR_UNTRUSTED) || + bpf_is_trusted_or_null_btf_ptr(type); } =20 static inline bool bpf_prog_has_arena_ctx_arg(const struct bpf_prog *prog) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9e79750e2480..b5186e664aea 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6168,6 +6168,15 @@ static int check_ptr_to_btf_access(struct bpf_verifi= er_env *env, if (ret !=3D PTR_TO_BTF_ID) { /* just mark; */ =20 + } else if (bpf_is_trusted_or_null_btf_ptr(reg->type)) { + /* + * An unchecked load through a trusted-or-NULL pointer is + * fault-protected. Any pointer derived from that load must be + * untrusted, as a fault produces a NULL value. + */ + clear_trusted_flags(&flag); + flag |=3D PTR_UNTRUSTED; + } else if (type_flag(reg->type) & PTR_UNTRUSTED) { /* If this is an untrusted pointer, all pointers formed by walking it * also inherit the untrusted flag. @@ -6644,7 +6653,8 @@ static int check_mem_access(struct bpf_verifier_env *= env, int insn_idx, struct b if (!err && t =3D=3D BPF_READ && value_regno >=3D 0) mark_reg_unknown(env, regs, value_regno); } else if (base_type(reg->type) =3D=3D PTR_TO_BTF_ID && - !type_may_be_null(reg->type)) { + (!type_may_be_null(reg->type) || + (t =3D=3D BPF_READ && bpf_is_trusted_or_null_btf_ptr(reg->type)))) { err =3D check_ptr_to_btf_access(env, regs, reg, argno, off, size, t, value_regno); } else if (reg->type =3D=3D CONST_PTR_TO_MAP) { --=20 2.55.0 From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1471C51E43B for ; Mon, 7 Sep 2026 16:53:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799992; cv=none; b=MtVNzSSNCdqv8a1uPQii7v2YzDJegQEA6hrUvIgD3uuYPuX52rNrDJjNBSwf5T6iQy0PyHXwZeA8vlYEf3kgfVDl9auCp9dHnFkrZ3sDdryovYfzCwHJfvuXKPJRCU6ddh64p2XUERnLxZkLh3/xtosVCFZIOcbADoJLh3dVinM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799992; c=relaxed/simple; bh=hUiRfb4pPtGSt1XRoYIWNSwJicLgvBYrE8+iFiVEXj8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VxPfps3iFECIVihDr2KGyGVMTuPW47F49X1fmEnKliwzMAJELA60qhJoTPJIReUqmgsDtFTSKtIhd7mtnmMAkGULOCpuYJjFzSDhJ8AoG0tRj+A/VwuD/Wd8IrQd/hZvrclJNCUo+ljsfpvjVHkOgAPnVnxop+WjPZ+9IcHEsKc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Vk+dNN1c; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Vk+dNN1c" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-498028b3d5eso35741075e9.1 for ; Mon, 07 Sep 2026 09:53:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799988; x=1789404788; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=wiDantY2ppJjyfqauG6RKR7rX8GZTmilPQrscV/V7A4=; b=Vk+dNN1cRSI1T20TmfDCeWcN2d2r54IPfCqatLuE3s5m+ogZPBGx27OQYy7G5RFo+F 3FLJoZsvfgEFEE/o0He6cT09e0lvkE5hN6s/4kaibIaVDrKLQ5E5/0AJ/kisfhSDNe6B OoWvK+nFTV0Wm6o2qDDhu7H60Y9vMb1+szG/cOQ+9IQEwR9ATENM2Wx+tCXW1PLmsYcS uuNnR8ixtvQkLCvnfG+fFmHf2wM833Bx8eB+BvcFK/tUxXo4CiY+igA0drs0sISKvvDW WQU/0GwwJHw3pxaShURzAjX2/Yt6J4X2JATrTtBdErrxfHH6fQ1PM97ZszgRj2BF0dSD Ofwg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799988; x=1789404788; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=wiDantY2ppJjyfqauG6RKR7rX8GZTmilPQrscV/V7A4=; b=h92MGPF0eaSLhK23QyoqsOp4MXxQb3HvLoNRLPX1pSfk039Q+jEqjdG2PuUwDyd164 y7pIy5KJmwjdKxjp3P3/6DqlT29ggkFQx/wRmoF2UO+om3rl5azDtQw7biYjDNmgmbmg DCOv4v34J8g6eG+FzskM15y1PVzOg+KxCJjYNfMb352Wd0nGPkPOMYHhC5LfR+Por/d9 AVBE+qTsrDvm/F+yNemF7T2dvEGGhD6a2HdxgEyd+T0BV9gC5sfjoPm+Jj6Cy+mxOfgH goqV9LgXylSiBG1lD6o2/e23rD2k6iz/JIHvtOvWyYXKe1OxBGCpzmMKlpt6fvIxJl8C XFWw== X-Forwarded-Encrypted: i=1; AKwUvBxGLTXBC+CdJlu028uIO6U3rlo+ahZSd6b34YerWdSE+C9rlKz/vDKYvkxRXfXtB9s/TkxhoY1I2z8ANw0=@vger.kernel.org X-Gm-Message-State: AFuF++nj5avD5Nwu3D/thfa5cfconlClz0dd4lfHaTmddoNr8z995QbL NbwwzgFvWe0+oqcZoUwM7bJ9p4VmFgPhZFFRVW7fZkjP2kDBdR3uGPrn X-Gm-Gg: AYBFou0VuaqbfowkQCvpyUHfl1PlgFiW2/ArzGXWaFXi+2fP4bbwKE5NxyAf3sqPO74 7N18cLdisK3WXr2zAXQA2XYGllhZnrRnQVz0Rc6rOCYpQudlMJSx+E2D038MlRnrEeMUg6gFReL 0+az/CnXESs9noxfzxk6fe6lz0cV5HGCejxAW+nnPAJ7/gW7MpXTmG3t4sjTbaJmJWiLkBA9XMT S30Q2pE5yCMuQY4X5kXhggEPkTOR1aE14KPFwJYu2vta2bmdUjyNW4EsF1ko9A8tt/3FZoWhrIe QEpMH7ehhyP9sTlJIcvZiCYj+KcQ6oHnqx6JMLX+p/zlV1UcxkBImQUg05aWVoDlRWWTbFDQJkA SoSXipKqEXH+reF3MYG1n2LiCf60k3ty/1KCMmqJFgbRsIRdPKIduJyxcIlBHPwUDTc07f8jlkT Dl7fybxm3X3dAtSnj7xLRWlT5FL+NIw5fx067tcasQKIlXPsq5J0kuREjbJeCEOcTHJSC0RK8lI A== X-Received: by 2002:a05:600c:3e06:b0:49d:99:1d98 with SMTP id 5b1f17b1804b1-49d00991db1mr173226525e9.9.1788799987801; Mon, 07 Sep 2026 09:53:07 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.53.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:53:07 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 5/7] selftests/bpf: Cover trusted-or-null BTF pointer reads Date: Mon, 7 Sep 2026 19:52:18 +0300 Message-ID: <20260907165220.52431-6-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Update verifier tests that expected an unchecked trusted-or-null BTF pointer dereference to fail. Cover scalar reads and chained reads through BTF and memory pointers. Add a runtime test which verifies that non-NULL reads return the field value and NULL reads return zero. Verify that pointer arithmetic, stores, atomic RMW operations, and BPF_LOAD_ACQ accesses remain prohibited. Assert that a BTF pointer derived from an unchecked trusted-or-null load is PTR_UNTRUSTED. Verify that attempting to NULL-check the derived pointer remains rejected and that it cannot be passed to a kfunc requiring an RCU pointer. Keep the existing NULL-check tests to verify that an explicit check of the original pointer recovers normal trusted pointer behavior. Signed-off-by: Anastasios Papagiannis --- .../selftests/bpf/prog_tests/bpf_iter.c | 6 +- .../prog_tests/test_struct_ops_maybe_null.c | 13 ++-- .../bpf/prog_tests/tp_btf_nullable.c | 28 +++++++ .../selftests/bpf/progs/raw_tp_null_fail.c | 78 +++++++++++++++++-- .../bpf/progs/test_tp_btf_nullable.c | 45 ++++++++++- .../bpf/progs/test_tp_btf_nullable_runtime.c | 35 +++++++++ .../selftests/bpf/progs/verifier_lsm.c | 18 ++++- .../selftests/bpf/progs/verifier_vfs_accept.c | 14 ++++ .../selftests/bpf/progs/verifier_vfs_reject.c | 14 ---- .../selftests/bpf/test_kmods/bpf_testmod.c | 1 + .../sched_ext/maybe_null_fail_dsp.bpf.c | 5 +- 11 files changed, 221 insertions(+), 36 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/test_tp_btf_nullable_= runtime.c diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/test= ing/selftests/bpf/prog_tests/bpf_iter.c index c69080ca14f5..99a16a1add70 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c @@ -39,10 +39,10 @@ static void test_btf_id_or_null(void) struct bpf_iter_test_kern3 *skel; =20 skel =3D bpf_iter_test_kern3__open_and_load(); - if (!ASSERT_ERR_PTR(skel, "bpf_iter_test_kern3__open_and_load")) { - bpf_iter_test_kern3__destroy(skel); + if (!ASSERT_OK_PTR(skel, "bpf_iter_test_kern3__open_and_load")) return; - } + + bpf_iter_test_kern3__destroy(skel); } =20 static void do_dummy_read_opts(struct bpf_program *prog, struct bpf_iter_a= ttach_opts *opts) diff --git a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_n= ull.c b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c index 01dc2613c8a5..45af6f00ad90 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c +++ b/tools/testing/selftests/bpf/prog_tests/test_struct_ops_maybe_null.c @@ -19,15 +19,16 @@ static void maybe_null(void) struct_ops_maybe_null__destroy(skel); } =20 -/* Test that the verifier rejects a program that access a nullable pointer - * without a check beforehand. +/* + * Test that the verifier accepts a fault-protected read through a nullable + * trusted pointer without an explicit NULL check. */ -static void maybe_null_fail(void) +static void maybe_null_no_check(void) { struct struct_ops_maybe_null_fail *skel; =20 skel =3D struct_ops_maybe_null_fail__open_and_load(); - if (ASSERT_ERR_PTR(skel, "struct_ops_module_fail__open_and_load")) + if (!ASSERT_OK_PTR(skel, "struct_ops_maybe_null_fail__open_and_load")) return; =20 struct_ops_maybe_null_fail__destroy(skel); @@ -41,6 +42,6 @@ void test_struct_ops_maybe_null(void) */ if (test__start_subtest("maybe_null")) maybe_null(); - if (test__start_subtest("maybe_null_fail")) - maybe_null_fail(); + if (test__start_subtest("maybe_null_no_check")) + maybe_null_no_check(); } diff --git a/tools/testing/selftests/bpf/prog_tests/tp_btf_nullable.c b/too= ls/testing/selftests/bpf/prog_tests/tp_btf_nullable.c index accc42e01f8a..825fe7a92d74 100644 --- a/tools/testing/selftests/bpf/prog_tests/tp_btf_nullable.c +++ b/tools/testing/selftests/bpf/prog_tests/tp_btf_nullable.c @@ -2,6 +2,31 @@ =20 #include #include "test_tp_btf_nullable.skel.h" +#include "test_tp_btf_nullable_runtime.skel.h" + +static void test_nullable_runtime(void) +{ + struct test_tp_btf_nullable_runtime *skel; + + skel =3D test_tp_btf_nullable_runtime__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + skel->bss->monitored_tid =3D sys_gettid(); + + if (!ASSERT_OK(test_tp_btf_nullable_runtime__attach(skel), "attach")) + goto out; + + if (!ASSERT_OK(trigger_module_test_read(2), "trigger")) + goto out; + + ASSERT_EQ(skel->bss->calls, 2, "calls"); + ASSERT_EQ(skel->bss->nonnull_len, 2, "nonnull_len"); + ASSERT_EQ(skel->bss->null_len, 0, "null_len"); + +out: + test_tp_btf_nullable_runtime__destroy(skel); +} =20 void test_tp_btf_nullable(void) { @@ -11,4 +36,7 @@ void test_tp_btf_nullable(void) } =20 RUN_TESTS(test_tp_btf_nullable); + + if (test__start_subtest("runtime")) + test_nullable_runtime(); } diff --git a/tools/testing/selftests/bpf/progs/raw_tp_null_fail.c b/tools/t= esting/selftests/bpf/progs/raw_tp_null_fail.c index 725d73c9ffe1..163124793d0a 100644 --- a/tools/testing/selftests/bpf/progs/raw_tp_null_fail.c +++ b/tools/testing/selftests/bpf/progs/raw_tp_null_fail.c @@ -2,22 +2,34 @@ /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ =20 #include +#include #include #include "bpf_misc.h" =20 char _license[] SEC("license") =3D "GPL"; =20 -/* Ensure module parameter has PTR_MAYBE_NULL */ +extern struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; +extern void bpf_task_release(struct task_struct *p) __ksym; + +/* + * Ensure the module tracepoint argument is trusted-or-NULL while allowing + * a fault-protected read without an explicit NULL check. + */ SEC("tp_btf/bpf_testmod_test_raw_tp_null_tp") -__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") +__success __log_level(2) +__msg("R1=3Dtrusted_ptr_or_null_sk_buff") int test_raw_tp_null_bpf_testmod_test_raw_tp_null_arg_1(void *ctx) { asm volatile("r1 =3D *(u64 *)(r1 +0); r1 =3D *(u64 *)(r1 +0);" ::: __c= lobber_all); return 0; } =20 -/* Check NULL marking */ +/* + * Ensure sched_pi_setprio's second argument is trusted-or-NULL while allo= wing + * a fault-protected read without an explicit NULL check. + */ SEC("tp_btf/sched_pi_setprio") -__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") +__success __log_level(2) +__msg("R1=3Dtrusted_ptr_or_null_task_struct") int test_raw_tp_null_sched_pi_setprio_arg_2(void *ctx) { asm volatile("r1 =3D *(u64 *)(r1 +8); r1 =3D *(u64 *)(r1 +0);" ::: __c= lobber_all); return 0; @@ -60,7 +72,8 @@ int test_tp_btf_signal_deliver_info_no_deref(void *ctx) } =20 SEC("tp_btf/sched_process_wait") -__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") +__success __log_level(2) +__msg("R1=3Dtrusted_ptr_or_null_pid") int test_raw_tp_null_sched_process_wait_arg_1(void *ctx) { asm volatile("r1 =3D *(u64 *)(r1 +0); r1 =3D *(u32 *)(r1 +0);" ::: __clob= ber_all); @@ -75,3 +88,58 @@ int test_raw_tp_null_sched_process_wait_arg_1_checked(vo= id *ctx) "r1 =3D *(u32 *)(r1 +0);" ::: __clobber_all); return 0; } + +SEC("tp_btf/sched_pi_setprio") +__failure __log_level(2) +__msg("R1=3Duntrusted_ptr_task_struct") +__msg("R1 must be a rcu pointer") +int BPF_PROG(trusted_or_null_walk_is_untrusted, struct task_struct *task, + struct task_struct *pi_task) +{ + struct task_struct *parent, *acquired; + + parent =3D pi_task->real_parent; + acquired =3D bpf_task_acquire(parent); + if (acquired) + bpf_task_release(acquired); + return 0; +} + +SEC("tp_btf/sched_pi_setprio") +__failure __msg("R1 must be a rcu pointer") +int BPF_PROG(derived_ptr_null_check_does_not_restore_trust, + struct task_struct *task, struct task_struct *pi_task) +{ + struct task_struct *parent, *acquired; + + parent =3D pi_task->real_parent; + if (!parent) + return 0; + + acquired =3D bpf_task_acquire(parent); + if (acquired) + bpf_task_release(acquired); + + return 0; +} + +/* + * In contrast, checking the original trusted-or-NULL pointer removes + * PTR_MAYBE_NULL while retaining PTR_TRUSTED. + */ +SEC("tp_btf/sched_pi_setprio") +__success +int BPF_PROG(original_ptr_null_check_retains_trust, + struct task_struct *task, struct task_struct *pi_task) +{ + struct task_struct *acquired; + + if (!pi_task) + return 0; + + acquired =3D bpf_task_acquire(pi_task); + if (acquired) + bpf_task_release(acquired); + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c b/too= ls/testing/selftests/bpf/progs/test_tp_btf_nullable.c index cf0547a613ff..b7914224ba19 100644 --- a/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c +++ b/tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c @@ -7,7 +7,7 @@ #include "bpf_misc.h" =20 SEC("tp_btf/bpf_testmod_test_nullable_bare_tp") -__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") +__success int BPF_PROG(handle_tp_btf_nullable_bare1, struct bpf_testmod_test_read_ct= x *nullable_ctx) { return nullable_ctx->len; @@ -21,4 +21,47 @@ int BPF_PROG(handle_tp_btf_nullable_bare2, struct bpf_te= stmod_test_read_ctx *nul return 0; } =20 +SEC("tp_btf/bpf_testmod_test_nullable_bare_tp") +__success +int BPF_PROG(handle_tp_btf_nullable_mem, struct bpf_testmod_test_read_ctx = *nullable_ctx) +{ + return nullable_ctx->buf[0]; +} + +SEC("tp_btf/bpf_testmod_test_nullable_bare_tp") +__failure __msg("pointer arithmetic on trusted_ptr_or_null_ prohibited") +int BPF_PROG(handle_tp_btf_nullable_arith, struct bpf_testmod_test_read_ct= x *nullable_ctx) +{ + asm volatile("%[ctx] +=3D 1" : [ctx] "+r"(nullable_ctx)); + return nullable_ctx->len; +} + +SEC("tp_btf/bpf_testmod_test_nullable_bare_tp") +__failure __msg("invalid mem access 'trusted_ptr_or_null_'") +int BPF_PROG(handle_tp_btf_nullable_atomic_rmw, + struct bpf_testmod_test_read_ctx *nullable_ctx) +{ + asm volatile ("r1 =3D %[ctx];" + "w2 =3D 1;" + "lock *(u32 *)(r1 + %[len]) +=3D w2;" + : + : [ctx] "r"(nullable_ctx), + __imm_const(len, + offsetof(struct bpf_testmod_test_read_ctx, + len)) + : "r1", "r2", "memory"); + return 0; +} + +#ifdef __BPF_FEATURE_LOAD_ACQ_STORE_REL +SEC("tp_btf/bpf_testmod_test_nullable_bare_tp") +__failure +__msg("BPF_ATOMIC loads from R{{[0-9]+}} trusted_ptr_or_null_") +int BPF_PROG(handle_tp_btf_nullable_load_acquire, + struct bpf_testmod_test_read_ctx *nullable_ctx) +{ + return __atomic_load_n(&nullable_ctx->len, __ATOMIC_ACQUIRE); +} +#endif + char _license[] SEC("license") =3D "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_tp_btf_nullable_runtime= .c b/tools/testing/selftests/bpf/progs/test_tp_btf_nullable_runtime.c new file mode 100644 index 000000000000..5c9c7f94040d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tp_btf_nullable_runtime.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include +#include "../test_kmods/bpf_testmod.h" + +char _license[] SEC("license") =3D "GPL"; + +int monitored_tid; +int calls; +__u64 nonnull_len; +__u64 null_len; + +SEC("tp_btf/bpf_testmod_test_nullable_bare_tp") +int BPF_PROG(handle_nullable_runtime, + struct bpf_testmod_test_read_ctx *nullable_ctx) +{ + __u32 tid =3D bpf_get_current_pid_tgid(); + __u64 len; + int call; + + if (tid !=3D monitored_tid) + return 0; + + len =3D nullable_ctx->len; + call =3D calls++; + + if (call =3D=3D 0) + nonnull_len =3D len; + else if (call =3D=3D 1) + null_len =3D len; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/verifier_lsm.c b/tools/testi= ng/selftests/bpf/progs/verifier_lsm.c index c724bf389f5c..fac133d90f5e 100644 --- a/tools/testing/selftests/bpf/progs/verifier_lsm.c +++ b/tools/testing/selftests/bpf/progs/verifier_lsm.c @@ -162,13 +162,13 @@ __naked int disabled_hook_test3(void *ctx) =20 SEC("lsm/mmap_file") __description("not null checking nullable pointer in bpf_lsm_mmap_file") -__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") +__success int BPF_PROG(no_null_check, struct file *file) { - struct inode *inode; + ino_t ino; =20 - inode =3D file->f_inode; - __sink(inode); + ino =3D file->f_inode->i_ino; + __sink(ino); =20 return 0; } @@ -188,6 +188,16 @@ int BPF_PROG(null_check, struct file *file) return 0; } =20 +SEC("lsm/mmap_file") +__description("store through trusted-or-null file is rejected") +__failure +__msg("R{{[0-9]+}} invalid mem access 'trusted_ptr_or_null_'") +int BPF_PROG(store_through_trusted_or_null_file, struct file *file) +{ + file->f_flags =3D 0; + return 0; +} + SEC("lsm_cgroup/file_open") __description("sleepable lsm_cgroup program is rejected") __failure __msg("Program of this type cannot be sleepable") diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c b/tool= s/testing/selftests/bpf/progs/verifier_vfs_accept.c index 55398c04290a..17c1542cc7e1 100644 --- a/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c +++ b/tools/testing/selftests/bpf/progs/verifier_vfs_accept.c @@ -100,4 +100,18 @@ int BPF_PROG(inode_rename, struct inode *old_dir, stru= ct dentry *old_dentry, return 0; } =20 +SEC("lsm.s/inode_rename") +__success __log_level(2) +__msg("R{{[0-9]+}}=3Dtrusted_ptr_or_null_inode") +int BPF_PROG(inode_rename_no_null_check, struct inode *old_dir, + struct dentry *old_dentry, struct inode *new_dir, + struct dentry *new_dentry, unsigned int flags) +{ + ino_t ino =3D new_dentry->d_inode->i_ino; + + if (ino =3D=3D 0) + return -EACCES; + return 0; +} + char _license[] SEC("license") =3D "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tool= s/testing/selftests/bpf/progs/verifier_vfs_reject.c index 8f0c45421f89..2a0813258183 100644 --- a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c +++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c @@ -159,18 +159,4 @@ int BPF_PROG(path_d_path_kfunc_non_lsm, struct path *p= ath, struct file *f) return 0; } =20 -SEC("lsm.s/inode_rename") -__failure __msg("invalid mem access 'trusted_ptr_or_null_'") -int BPF_PROG(inode_rename, struct inode *old_dir, struct dentry *old_dentr= y, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - struct inode *inode =3D new_dentry->d_inode; - ino_t ino; - - ino =3D inode->i_ino; - if (ino =3D=3D 0) - return -EACCES; - return 0; -} char _license[] SEC("license") =3D "GPL"; diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/t= esting/selftests/bpf/test_kmods/bpf_testmod.c index f798bbbb4d13..2ba6a83d243f 100644 --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c @@ -702,6 +702,7 @@ bpf_testmod_test_read(struct file *file, struct kobject= *kobj, if (bpf_testmod_loop_test(101) > 100) trace_bpf_testmod_test_read(current, &ctx); =20 + trace_bpf_testmod_test_nullable_bare_tp(&ctx); trace_bpf_testmod_test_nullable_bare_tp(NULL); =20 /* Magic number to enable writable tp */ diff --git a/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c b/= tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c index ec724d7b33d1..ecaa36355cae 100644 --- a/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c +++ b/tools/testing/selftests/sched_ext/maybe_null_fail_dsp.bpf.c @@ -7,14 +7,13 @@ =20 char _license[] SEC("license") =3D "GPL"; =20 -u64 vtime_test; - void BPF_STRUCT_OPS(maybe_null_running, struct task_struct *p) {} =20 void BPF_STRUCT_OPS(maybe_null_fail_dispatch, s32 cpu, struct task_struct = *p) { - vtime_test =3D p->scx.dsq_vtime; + /* Pointer arithmetic on a trusted-or-NULL pointer must be rejected. */ + asm volatile("%[p] +=3D 0" : [p] "+r"(p)); } =20 SEC(".struct_ops.link") --=20 2.55.0 From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wm1-f47.google.com (mail-wm1-f47.google.com [209.85.128.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1C9AE4FB9DF for ; Mon, 7 Sep 2026 16:53:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799994; cv=none; b=S+xeDSf0hOMndACPiwo+/t9cfCgqqWkkXOOoMhZbreiYhM9omi4iP13Zo0XVLhayU4lhTEg+9v9gyrW7XJ4fARO8psQbcpSO4q0WDM0gA1b9mphSfezLOqOdAq9/EeZ9+dqMhmqDPuvPoJJRTsY/u8LW0kooFJsq+g7ctj24qPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799994; c=relaxed/simple; bh=37ZkkZNqxkhdoz/COm3n2Pon+sMf3f11UDjmNND0D2Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I/ijtPMwyROtd3VmsjGXrvFapInlTOIMEOXn6WrqxQZcfwzBtKRIwOB+PLt9Rfld7ObYbLqrEGFfX1hd5IU561IuOtarBp+ZmZkQ0eaGyWt7+O6NcZ2JeG8J7QN+wle2DLm4B1gsZA+1U7LkMTnIFhU9mIgTbERnUMM5LzdS82k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hmw1WqJC; arc=none smtp.client-ip=209.85.128.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hmw1WqJC" Received: by mail-wm1-f47.google.com with SMTP id 5b1f17b1804b1-49557167508so45587035e9.1 for ; Mon, 07 Sep 2026 09:53:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799991; x=1789404791; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=OXEATw0LCoNw3+DI3xDTgsz8l5QDzPtCPOwXyA9u26Q=; b=hmw1WqJCHRhE3G87DR1g4BeBvh/68di1WUMzePtbbPNHpnNepsaWsyTZ058+17dMhj becWdVE0tzS8gom2LRDufMLM68HqVeOYy5QQI/HZMHR6X+aRPgZK/IKqGpMBiUpHgJ8G ghckD/wRZpeyY0vw/6wij58gXw0sDZ1t9uVkDQDnKbQiCAh98PxeGMqfES4xWaRKeBur MIxWCaHT778rCG7i4VkFPENR+3Y8fQFZOLkL0lUrRu2lcOVaW4j1zjTkKrtULdtMvD/d fyLvy13dXZXB/dftz/kymru7gvQ0MsKdRpXePwQ+ONRQ6BOtKfu21Wb0DFV9eZtq5DsZ T/AQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799991; x=1789404791; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=OXEATw0LCoNw3+DI3xDTgsz8l5QDzPtCPOwXyA9u26Q=; b=kwyj2XSGn1/jGOY2680QoyMxz7mOV9F6zkju0jsCb6RG/nm4KHXd6Z/xxblajGI9xn K4AyXmQ9JA3jVHdy/f/jY4m4kSv50vN3ayMpaR9miS0lHzmCBKRoAOF/zymr/rT8h+sW HaTvRlgrEQtuOfzNtsbvqWRFhHzd1FSbVn4Kcs4FXlPi5uPlWcqe+cyUwlTtsYu8OrGM P6+AkW6ylzF6t5rN0ZzPP+7rjiQA28AYWEx7zknTGcoA+i0Lt2ZxynhZ9w3eeuoHLR3c BQkDIydkz5E8lMdb8CHk8vQe/wP5mFZCeNKWBL3yxcPnJWcQVvwMNYzjWm9oYkAL5Zg1 gOEQ== X-Forwarded-Encrypted: i=1; AKwUvBxjsl/ekShHks9XGgXInmqjMYUpROUS0WAavD1GLVZnCRYMXpph7BwAPQtZw2McRyG/L+VjRM19j8Lk+ug=@vger.kernel.org X-Gm-Message-State: AFuF++m0UzQlWokJCUx3NNyKlJjtQiFWzy3KlRGnv1CiR5mMaflAQynA 0HfHTDreHAJWkUHxZJF/ekRTyhsXTi+DtCY4PDgLtQAjX3QY5BIf/UoE X-Gm-Gg: AYBFou0xALiEGV96vxCfpTYttGX1oZqf+3CGbFy59v0s5EqpH+FCdqmolT+jdzEyWl6 GL5q84eUeKoCPkaJRjj9SAkcUWt+hmFozGeepkahB5tBiKYuCqtN6OhC9xT7yo4+TR+ZZZI5DvD VP5hr3vhMsVj2LxbJvFjxu1BphHZ91bqXuumG9qJwbeDILJu6AnXK54JWY2VV5ERS+KtmCs+eDe 7BDx2PfOiyi6PI97kb/B6yMCIAn7ZL6F5nFiKAECn2GctIUJSFBtCny3BeLhBdz2RRe5WAQjaYr ml1xqOByCelkGOeI02/RYbheY2AMx5VtkNfwMthS8ENj9+rSGz7etbsLbk5Q47xsutU30fbXpOh vhQPV3UhFLoeVxNBtLX5BmWXYGA9QhPkILtoPEceh55TYZvWuZQZ3dDteLTJxHDY6xeNvP/Coqo ncnA9l+v1pyTNFFEWl6LtfxX86w8IgrZzOtQS27G+FKJ7fC3dQ/W3s83nksuwtCdXV23czWaOE2 w== X-Received: by 2002:a05:600c:3485:b0:49c:cee0:e7c1 with SMTP id 5b1f17b1804b1-49cf825c119mr525133835e9.16.1788799991022; Mon, 07 Sep 2026 09:53:11 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.53.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:53:10 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 6/7] bpf: Mark linux_binprm->mm as trusted-or-null Date: Mon, 7 Sep 2026 19:52:19 +0300 Message-ID: <20260907165220.52431-7-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Mark linux_binprm->mm as a trusted-or-null nested pointer so BPF programs can pass it to kfuncs after a NULL check. The field is either NULL or points to a live mm_struct whenever BPF can access a linux_binprm. On successful exec, exec_mmap() installs the new address space before begin_new_exec() clears bprm->mm. The bprm_mm_init() error path clears the field before mmdrop(), and free_bprm() clears it before mmput(), as ensured by an earlier patch in this series. Signed-off-by: Anastasios Papagiannis Reviewed-by: Sun Jian Reviewed-By: Matt Bobrowski --- kernel/bpf/verifier.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b5186e664aea..6799d9e080fc 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6004,6 +6004,10 @@ BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct dentry) { struct inode *d_inode; }; =20 +BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct linux_binprm) { + struct mm_struct *mm; +}; + BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket) { struct sock *sk; }; @@ -6058,6 +6062,7 @@ static bool type_is_trusted_or_null(struct bpf_verifi= er_env *env, { BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket)); BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct dentry)); + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct linux_binprm)); BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct vm_area_struct)); =20 return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id, --=20 2.55.0 From nobody Fri Sep 25 23:09:47 2026 Received: from mail-wm1-f47.google.com (mail-wm1-f47.google.com [209.85.128.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2F2BE52379B for ; Mon, 7 Sep 2026 16:53:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799998; cv=none; b=AoAZY4UjeVDr70cLVerBwXUBN//sblkHjKkMOrimydQJhHWmuLUgM04Di8ASn/jOLReK8TWymSjpZNpZIFDp4QQynxcQ11ROopUSpxkcn8DVIj0SjxG+s3pFDpW8VHlTKz8xksmGg1ZJtV0OG8dUhWwRjP6T/U+j5r2G3uWYh/g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788799998; c=relaxed/simple; bh=nSBS+rlhEpu4GtYBRlDxNT0IMhKXrWZBlDW7Ai/0My4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m1wBnHCfOOFM2TYqnkdTXEtp2vu3lYgDajt9kkfZXzJpji2VMzLa8AWeOqgmV9H2W489/HY0CJQowGW3KyF8JRdmMGp46GYfPEFu7vHulgrb+cAxCWX6P/VNuaPwFAjZN/6yF3eEybDVlluRWCODTy7fZO+JsLbyueGDrfw4LII= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=gvLU/83Q; arc=none smtp.client-ip=209.85.128.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gvLU/83Q" Received: by mail-wm1-f47.google.com with SMTP id 5b1f17b1804b1-49d036e0e99so12834195e9.1 for ; Mon, 07 Sep 2026 09:53:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788799994; x=1789404794; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=6KgsraBrUcToWRNGkqj8MPFUdOM/wW4nUtZo/xB90w4=; b=gvLU/83QWw+BBDbY7MKMk3tCFSXW3BMFl5bWQjLrzb3eSbsX7CgvOuqkuT3+icxm2R bPBdMwcZkuj4gFm1mrvSDOiMzTWzL5430Oh1BK8VtAfdYHNEJRwXft5FMeiEnbgFyVus ACImVqzqwnZwmVwrNm4rTCFRpWpun0bb3inLerxAAKGQO4ho3Zvk+NdEnPseRa1qMSjq n4vb65ahHimcjBmrRV/yEstLuePXTqRYuxGSJsm2reSg5a4W5sNXt4o7zfCiArqDg4Ss iiWOklDQaaOhMIu21mehblND5bzrbiC6vJ+INHYWYALeS5eYI3F9bOa6DFPGIknoEsZi WcxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788799994; x=1789404794; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=6KgsraBrUcToWRNGkqj8MPFUdOM/wW4nUtZo/xB90w4=; b=ioHfPzxxVqhsldDA9yuUB+vsMF3Z7JEA9W/XZ7URtTGUnwyqwh2nfJB7Ll66W0V2xh JQklW6dIrzWVoF0HM3+GlJWXJK/4fNxQI2nF/tq75lwahNelPKFdWBbjbkd1f46aI8kC G2N10BtDEJtdKIiTKM2XmHaTcu08JcAtfElrns8xt7AVUa6cALF1+q7MZ74UJfuVGtSg ljqBL/0LGZBcUkBchnjLohbIGqZ2QejgtS71bSoJfp9sFEiy9GYI9hCpyKHDfzpkq0tv wEGmT4HLmNLzaU6DORgCwNzsKY61MkpQhouagBPsMmOg1I4U577L5O9ZrejBBpbGZ5yV +iDg== X-Forwarded-Encrypted: i=1; AKwUvBzjmEOspSsUTYYs8IV7yebLDMYNeIFfcDpmc4wkxYDAfp/g5MVpLlNLTUUd3NllZwVv9vcv8I+eMfzKvxs=@vger.kernel.org X-Gm-Message-State: AFuF++lKSZTfIv9OykNegZRA/l4vgfEaeR1n2MgkImf/1bDxANo9MNXV KBG7RVuBBkOk0zgVNvnzWv7kBaU3G9qEcL3N7N93OscefjVkO133Gklq X-Gm-Gg: AYBFou3Eq8pFy7cf3oYV/VF65npiOel04X/ruCdNADdprEBx5hWRMaERZKxqux+6gcB 51aSXADvxcgVjIlRv5H0UHXQZmIobdYg/vEfL4NkE/hteEA8iaNt8tEcGQMscisdiVBJm9bT72l uXvDcZYVMjpTALOWzumJPnQY/NW4WVKuHWJIdGbGMISN57vkrzVgpldRubGraTmrJ1vUC0M/Db/ bkOKK8ub57FBrBxESRZNH/CIW1PSJkIidD8rdaNNnwyDFUD3xTDzUe0X1DeET5+H8BFB2uSCKC5 EHmshji/G7MhHmbYGS86EzHa+sWWlfbcY84uzIBMTTJd6zXlWLOMRPIZKD+/3VS02QvQmD716yW egCCysJdsbVEjGjP1n+1MzdDNOfYtm/Dp1c57XQvyUUqoCDLUrga/WW0PR+Tpk0S6LKuhMaqOeA BryjugwEP3Fy67HnEe+BxVuKYd8c7TiBNOSyWoamkKT5qYlflZwr9Q4KhZMjbeYNXG6liwNfrI4 5oiKhY1h9uK X-Received: by 2002:a05:600d:650c:20b0:49c:fc6c:be08 with SMTP id 5b1f17b1804b1-49cfc6cc026mr166941545e9.31.1788799994171; Mon, 07 Sep 2026 09:53:14 -0700 (PDT) Received: from dell-desktop ([2a02:587:4b5f:900:ef25:2f4:1792:4e6f]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49d03543064sm233022415e9.13.2026.09.07.09.53.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Sep 2026 09:53:13 -0700 (PDT) From: Anastasios Papagiannis To: bpf@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, david@kernel.org, akpm@linux-foundation.org, andrii@kernel.org, ast@kernel.org, brauner@kernel.org, daniel@iogearbox.net, eddyz87@gmail.com, kpsingh@kernel.org, ljs@kernel.org, matt@bobrowski.net, memxor@gmail.com, song@kernel.org, sun.jian.kdev@gmail.com, tasos.papagiannnis@gmail.com, utilityemal77@gmail.com, viro@zeniv.linux.org.uk Subject: [PATCH bpf-next v5 7/7] selftests/bpf: Test mm_struct user memory kfuncs with linux_binprm Date: Mon, 7 Sep 2026 19:52:20 +0300 Message-ID: <20260907165220.52431-8-tasos.papagiannnis@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> References: <20260907165220.52431-1-tasos.papagiannnis@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a sleepable BPF LSM program attached to bprm_check_security to test bpf_copy_from_user_mm() and bpf_copy_from_user_mm_str() on CONFIG_MMU kernels. Starting at bprm->p, verify that bpf_copy_from_user_mm() can copy the contiguous NUL-separated argument and environment data. Then use bpf_copy_from_user_mm_str() to read each argument and environment string separately, advancing the offset by the length returned from each call. Skip the test on !CONFIG_MMU. In that configuration, exec argument and environment strings remain in bprm->page[] until the binary loader transfers them to the new process stack, so they are not accessible through bprm->mm at the bprm_check_security hook. Signed-off-by: Anastasios Papagiannis --- .../bpf/prog_tests/copy_from_user_bprm.c | 72 ++++++++++ .../selftests/bpf/progs/copy_from_user_bprm.c | 123 ++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/copy_from_user_b= prm.c create mode 100644 tools/testing/selftests/bpf/progs/copy_from_user_bprm.c diff --git a/tools/testing/selftests/bpf/prog_tests/copy_from_user_bprm.c b= /tools/testing/selftests/bpf/prog_tests/copy_from_user_bprm.c new file mode 100644 index 000000000000..b2325b193576 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/copy_from_user_bprm.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include + +#include "copy_from_user_bprm.skel.h" + +void test_copy_from_user_bprm(void) +{ + char arg0[] =3D "first"; + char arg1[] =3D "second-argument"; + char env0[] =3D "SOME_ENV=3Da"; + char env1[] =3D "OTHER_ENV=3Dsomething"; + struct copy_from_user_bprm *skel; + pid_t child; + int status; + + skel =3D copy_from_user_bprm__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + + /* + * On !CONFIG_MMU, exec strings are held in bprm->page[] rather than + * being mapped in bprm->mm. + */ + if (!skel->kconfig->CONFIG_MMU) { + printf("%s:SKIP: test requires CONFIG_MMU\n", __func__); + test__skip(); + goto out; + } + + if (!ASSERT_OK(copy_from_user_bprm__attach(skel), "attach")) + goto out; + + child =3D fork(); + if (!ASSERT_GE(child, 0, "fork")) + goto out; + + if (!child) { + char *const argv[] =3D { arg0, arg1, NULL }; + char *const envp[] =3D { env0, env1, NULL }; + + skel->bss->monitored_pid =3D getpid(); + execve("/bin/true", argv, envp); + _exit(errno); + } + + if (!ASSERT_EQ(waitpid(child, &status, 0), child, "waitpid")) + goto out; + + if (ASSERT_TRUE(WIFEXITED(status), "child_exited")) + ASSERT_EQ(WEXITSTATUS(status), EPERM, "exec_errno"); + + ASSERT_EQ(skel->bss->bprm_argc, 2, "bprm_argc"); + ASSERT_EQ(skel->bss->bprm_envc, 2, "bprm_envc"); + ASSERT_EQ(skel->bss->data_len_match, 1, "data_len_match"); + ASSERT_EQ(skel->bss->invalid_flags_ret, -EINVAL, "invalid_flags_ret"); + ASSERT_EQ(skel->bss->copy_ret, 0, "copy_ret"); + ASSERT_EQ(skel->bss->str_arg0_ret, sizeof(arg0), "str_arg0_ret"); + ASSERT_EQ(skel->bss->str_arg1_ret, sizeof(arg1), "str_arg1_ret"); + ASSERT_EQ(skel->bss->str_env0_ret, sizeof(env0), "str_env0_ret"); + ASSERT_EQ(skel->bss->str_env1_ret, sizeof(env1), "str_env1_ret"); + ASSERT_EQ(skel->bss->data_match, 1, "data_match"); + ASSERT_EQ(skel->bss->str_args_match, 1, "str_args_match"); + ASSERT_EQ(skel->bss->str_envs_match, 1, "str_envs_match"); + +out: + copy_from_user_bprm__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/copy_from_user_bprm.c b/tool= s/testing/selftests/bpf/progs/copy_from_user_bprm.c new file mode 100644 index 000000000000..b334a157419e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/copy_from_user_bprm.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" + +#include +#include +#include +#include "bpf_misc.h" + +char _license[] SEC("license") =3D "GPL"; + +static const char expected_data[] =3D "first\0second-argument\0" + "SOME_ENV=3Da\0OTHER_ENV=3Dsomething"; +static const char expected_arg0[] =3D "first"; +static const char expected_arg1[] =3D "second-argument"; +static const char expected_env0[] =3D "SOME_ENV=3Da"; +static const char expected_env1[] =3D "OTHER_ENV=3Dsomething"; + +int monitored_pid; +int bprm_argc; +int bprm_envc; +int data_len_match; +int invalid_flags_ret; +int copy_ret; +int str_arg0_ret; +int str_arg1_ret; +int str_env0_ret; +int str_env1_ret; +int data_match; +int str_args_match; +int str_envs_match; + +extern bool CONFIG_MMU __kconfig __weak; + +extern int bpf_copy_from_user_mm(void *dst, u32 dst__sz, + const void *unsafe_ptr__ign, + struct mm_struct *mm, u64 flags) __ksym; + +extern int bpf_copy_from_user_mm_str(void *dst, u32 dst__sz, + const void *unsafe_ptr__ign, + struct mm_struct *mm, u64 flags) __ksym; + +SEC("lsm.s/bprm_check_security") +int BPF_PROG(check_exec_args, struct linux_binprm *bprm) +{ + u32 pid =3D bpf_get_current_pid_tgid() >> 32; + char data[sizeof(expected_data)] =3D {}; + struct mm_struct *mm; + char arg0[32] =3D {}; + char arg1[32] =3D {}; + char env0[32] =3D {}; + char env1[32] =3D {}; + u64 offset =3D 0; + u64 data_len; + + if (!CONFIG_MMU) + return 0; + + if (pid !=3D monitored_pid) + return 0; + + mm =3D bprm->mm; + if (!mm) + return 0; + + bprm_argc =3D bprm->argc; + bprm_envc =3D bprm->envc; + + /* this is the total size of args and envs starting from bprm->p */ + data_len =3D bprm->exec - bprm->p; + data_len_match =3D data_len =3D=3D sizeof(expected_data); + + invalid_flags_ret =3D bpf_copy_from_user_mm(data, + sizeof(data), (void *)bprm->p, mm, ~0ULL); + + copy_ret =3D bpf_copy_from_user_mm(data, sizeof(data), (void *)bprm->p, + mm, 0); + if (copy_ret) + return 0; + + data_match =3D + !__builtin_memcmp(data, expected_data, sizeof(expected_data)); + + /* arg0 is at bprm->p */ + str_arg0_ret =3D bpf_copy_from_user_mm_str(arg0, sizeof(arg0), + (void *)(bprm->p + offset), + mm, BPF_F_PAD_ZEROS); + if (str_arg0_ret !=3D sizeof(expected_arg0)) + return 0; + offset +=3D str_arg0_ret; + + /* arg1 is at bprm->p + sizeof(arg0) */ + str_arg1_ret =3D bpf_copy_from_user_mm_str(arg1, sizeof(arg1), + (void *)(bprm->p + offset), + mm, BPF_F_PAD_ZEROS); + if (str_arg1_ret !=3D sizeof(expected_arg1)) + return 0; + offset +=3D str_arg1_ret; + + /* env0 is at bprm->p + sizeof(arg0) + sizeof(arg1) */ + str_env0_ret =3D bpf_copy_from_user_mm_str(env0, sizeof(env0), + (void *)(bprm->p + offset), + mm, BPF_F_PAD_ZEROS); + if (str_env0_ret !=3D sizeof(expected_env0)) + return 0; + offset +=3D str_env0_ret; + + /* env1 is at bprm->p + sizeof(arg0) + sizeof(arg1) + sizeof(env0) */ + str_env1_ret =3D bpf_copy_from_user_mm_str(env1, sizeof(env1), + (void *)(bprm->p + offset), + mm, BPF_F_PAD_ZEROS); + if (str_env1_ret !=3D sizeof(expected_env1)) + return 0; + + str_args_match =3D + !__builtin_memcmp(arg0, expected_arg0, sizeof(expected_arg0)) && + !__builtin_memcmp(arg1, expected_arg1, sizeof(expected_arg1)); + str_envs_match =3D + !__builtin_memcmp(env0, expected_env0, sizeof(expected_env0)) && + !__builtin_memcmp(env1, expected_env1, sizeof(expected_env1)); + + return data_match && str_args_match && str_envs_match ? -EPERM : 0; +} --=20 2.55.0