lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241211142929.247692-1-mjg59@srcf.ucam.org>
Date: Wed, 11 Dec 2024 14:29:29 +0000
From: Matthew Garrett <mjg59@...f.ucam.org>
To: linux-fsdevel@...r.kernel.org
Cc: linux-kernel@...r.kernel.org,
	Matthew Garrett <mjg59@...f.ucam.org>
Subject: [RFC] Add a prctl to disable ".." traversal in path resolution

Path traversal attacks remain a common security vulnerability
(https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=%22path+traversal%22)
and many are due to either failing to filter out ".." when validating a
path or incorrectly collapsing other sequences of "."s into ".." .
Evidence suggests that improving education isn't fixing the problem.

The majority of internet-facing applications are unlikely to require the
ability to handle ".." in a path after startup, and many are unlikely to
require it at all. This patch adds a prctl() to simply request that the
VFS path resolution code return -EPERM if it hits a ".." in the process.
Applications can either call this themselves, or a service manager can
do this on their behalf before execing them.

Note that this does break resolution of symlinks with ".." in them,
which means it breaks the common case of /etc/whatever/sites-available.d
containing site-specific configuration, with
/etc/whatever/sites-enabled.d containing a set of relative symlinks to
../sites-available.d/ entries. In this case either configuration would
need to be updated before deployment, or the process would call prctl()
itself after parsing configuration (and then disable and re-enable the
feature whenever re-reading configuration). Getting this right for all
scenarios involving symlinks seems awkward and I'm not sure it's worth
it, but also I don't even play a VFS expert on TV so if someone has
clever ideas here we can extend this to support that case.

Signed-off-by: Matthew Garrett <mjg59@...f.ucam.org>
---
 fs/namei.c                 | 7 +++++++
 include/linux/sched.h      | 1 +
 include/uapi/linux/prctl.h | 3 +++
 kernel/sys.c               | 5 +++++
 4 files changed, 16 insertions(+)

diff --git a/fs/namei.c b/fs/namei.c
index 9d30c7aa9aa6..01d0fa415b64 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2431,6 +2431,13 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 
 		switch(lastword) {
 		case LAST_WORD_IS_DOTDOT:
+			/*
+			 * Deny .. in resolution if the process has indicated
+			 * it wants to protect against path traversal
+			 * vulnerabilities
+			 */
+			if (unlikely(current->deny_path_traversal))
+				return -EPERM;
 			nd->last_type = LAST_DOTDOT;
 			nd->state |= ND_JUMPED;
 			break;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index d380bffee2ef..9fc7f4c11645 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1008,6 +1008,7 @@ struct task_struct {
 	/* delay due to memory thrashing */
 	unsigned                        in_thrashing:1;
 #endif
+	unsigned                        deny_path_traversal:1;
 #ifdef CONFIG_PREEMPT_RT
 	struct netdev_xmit		net_xmit;
 #endif
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 5c6080680cb2..d289acecef6c 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -353,4 +353,7 @@ struct prctl_mm_map {
  */
 #define PR_LOCK_SHADOW_STACK_STATUS      76
 
+/* Block resolution of "../" in paths, returning -EPERM instead */
+#define PR_SET_PATH_TRAVERSAL_BLOCK      77
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index c4c701c6f0b4..204ea88d5597 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2809,6 +2809,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 			return -EINVAL;
 		error = arch_lock_shadow_stack_status(me, arg2);
 		break;
+	case PR_SET_PATH_TRAVERSAL_BLOCK:
+		if ((arg2 > 1) || arg3 || arg4 || arg5)
+			return -EINVAL;
+		current->deny_path_traversal = !!arg2;
+		break;
 	default:
 		error = -EINVAL;
 		break;
-- 
2.47.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ