linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
@ 2024-04-23 11:01 Stas Sergeev
  2024-04-23 11:01 ` [PATCH 1/2] fs: reorganize path_openat() Stas Sergeev
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Stas Sergeev @ 2024-04-23 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stas Sergeev, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche

This patch-set implements the OA2_INHERIT_CRED flag for openat2() syscall.
It is needed to perform an open operation with the creds that were in
effect when the dir_fd was opened. This allows the process to pre-open
some dirs and switch eUID (and other UIDs/GIDs) to the less-privileged
user, while still retaining the possibility to open/create files within
the pre-opened directory set.

Changes in v2:
- capture full struct cred instead of just fsuid/fsgid.
  Suggested by Stefan Metzmacher <metze@samba.org>

CC: Stefan Metzmacher <metze@samba.org>
CC: Eric Biederman <ebiederm@xmission.com>
CC: Alexander Viro <viro@zeniv.linux.org.uk>
CC: Andy Lutomirski <luto@kernel.org>
CC: Christian Brauner <brauner@kernel.org>
CC: Jan Kara <jack@suse.cz>
CC: Jeff Layton <jlayton@kernel.org>
CC: Chuck Lever <chuck.lever@oracle.com>
CC: Alexander Aring <alex.aring@gmail.com>
CC: linux-fsdevel@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: linux-api@vger.kernel.org
CC: Paolo Bonzini <pbonzini@redhat.com>
CC: Christian Göttsche <cgzones@googlemail.com>

Stas Sergeev (2):
  fs: reorganize path_openat()
  openat2: add OA2_INHERIT_CRED flag

 fs/internal.h                |  2 +-
 fs/namei.c                   | 52 +++++++++++++++++++++++++++++-------
 fs/open.c                    |  2 +-
 include/linux/fcntl.h        |  2 ++
 include/uapi/linux/openat2.h |  3 +++
 5 files changed, 50 insertions(+), 11 deletions(-)

-- 
2.44.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/2] fs: reorganize path_openat()
  2024-04-23 11:01 [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Stas Sergeev
@ 2024-04-23 11:01 ` Stas Sergeev
  2024-04-23 11:01 ` [PATCH 2/2] openat2: add OA2_INHERIT_CRED flag Stas Sergeev
  2024-04-23 16:44 ` [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Andy Lutomirski
  2 siblings, 0 replies; 13+ messages in thread
From: Stas Sergeev @ 2024-04-23 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stas Sergeev, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche

This patch moves the call to alloc_empty_file() below the call to
path_init(). That changes is needed for the next patch, which adds
a cred override for alloc_empty_file(). The needed cred info is only
available after the call to path_init().

No functional changes are intended by that patch.

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>

CC: Eric Biederman <ebiederm@xmission.com>
CC: Alexander Viro <viro@zeniv.linux.org.uk>
CC: Christian Brauner <brauner@kernel.org>
CC: Jan Kara <jack@suse.cz>
CC: Andy Lutomirski <luto@kernel.org>
CC: linux-fsdevel@vger.kernel.org
CC: linux-kernel@vger.kernel.org
---
 fs/namei.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index c5b2a25be7d0..2fde2c320ae9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3782,22 +3782,30 @@ static struct file *path_openat(struct nameidata *nd,
 	struct file *file;
 	int error;
 
-	file = alloc_empty_file(op->open_flag, current_cred());
-	if (IS_ERR(file))
-		return file;
-
-	if (unlikely(file->f_flags & __O_TMPFILE)) {
+	if (unlikely(op->open_flag & __O_TMPFILE)) {
+		file = alloc_empty_file(op->open_flag, current_cred());
+		if (IS_ERR(file))
+			return file;
 		error = do_tmpfile(nd, flags, op, file);
-	} else if (unlikely(file->f_flags & O_PATH)) {
+	} else if (unlikely(op->open_flag & O_PATH)) {
+		file = alloc_empty_file(op->open_flag, current_cred());
+		if (IS_ERR(file))
+			return file;
 		error = do_o_path(nd, flags, file);
 	} else {
 		const char *s = path_init(nd, flags);
-		while (!(error = link_path_walk(s, nd)) &&
-		       (s = open_last_lookups(nd, file, op)) != NULL)
-			;
+		file = alloc_empty_file(op->open_flag, current_cred());
+		error = PTR_ERR_OR_ZERO(file);
+		if (!error) {
+			while (!(error = link_path_walk(s, nd)) &&
+			       (s = open_last_lookups(nd, file, op)) != NULL)
+				;
+		}
 		if (!error)
 			error = do_open(nd, file, op);
 		terminate_walk(nd);
+		if (IS_ERR(file))
+			return file;
 	}
 	if (likely(!error)) {
 		if (likely(file->f_mode & FMODE_OPENED))
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/2] openat2: add OA2_INHERIT_CRED flag
  2024-04-23 11:01 [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Stas Sergeev
  2024-04-23 11:01 ` [PATCH 1/2] fs: reorganize path_openat() Stas Sergeev
@ 2024-04-23 11:01 ` Stas Sergeev
  2024-04-23 16:44 ` [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Andy Lutomirski
  2 siblings, 0 replies; 13+ messages in thread
From: Stas Sergeev @ 2024-04-23 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: Stas Sergeev, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche

This flag performs the open operation with the credentials that
were in effect when dir_fd was opened.
This allows the process to pre-open some directories and then
change eUID (and all other UIDs/GIDs) to a less-privileged user,
retaining the ability to open/create files within these directories.

Design goal:
The idea is to provide a very light-weight sandboxing, where the
process, without the use of any heavy-weight techniques like chroot
within namespaces, can restrict the access to the set of pre-opened
directories.
This patch is just a first step to such sandboxing. If things go
well, in the future the same extension can be added to more syscalls.
These should include at least unlinkat(), renameat2() and the
not-yet-upstreamed setxattrat().

Security considerations:
To avoid sandboxing escape, this patch makes sure the restricted
lookup modes are used. Namely, RESOLVE_BENEATH or RESOLVE_IN_ROOT.
To avoid leaking creds across exec, this patch requires O_CLOEXEC
flag on a directory.

Use cases:
Virtual machines that deal with untrusted code, can use that
instead of a more heavy-weighted approaches.
Currently the approach is being tested on a dosemu2 VM.

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>

CC: Stefan Metzmacher <metze@samba.org>
CC: Eric Biederman <ebiederm@xmission.com>
CC: Alexander Viro <viro@zeniv.linux.org.uk>
CC: Andy Lutomirski <luto@kernel.org>
CC: Christian Brauner <brauner@kernel.org>
CC: Jan Kara <jack@suse.cz>
CC: Jeff Layton <jlayton@kernel.org>
CC: Chuck Lever <chuck.lever@oracle.com>
CC: Alexander Aring <alex.aring@gmail.com>
CC: linux-fsdevel@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: Paolo Bonzini <pbonzini@redhat.com>
CC: Christian Göttsche <cgzones@googlemail.com>
---
 fs/internal.h                |  2 +-
 fs/namei.c                   | 30 ++++++++++++++++++++++++++++--
 fs/open.c                    |  2 +-
 include/linux/fcntl.h        |  2 ++
 include/uapi/linux/openat2.h |  3 +++
 5 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 7ca738904e34..692b53b19aad 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -169,7 +169,7 @@ static inline void sb_end_ro_state_change(struct super_block *sb)
  * open.c
  */
 struct open_flags {
-	int open_flag;
+	u64 open_flag;
 	umode_t mode;
 	int acc_mode;
 	int intent;
diff --git a/fs/namei.c b/fs/namei.c
index 2fde2c320ae9..0e0f2e32ef02 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -586,6 +586,7 @@ struct nameidata {
 	int		dfd;
 	vfsuid_t	dir_vfsuid;
 	umode_t		dir_mode;
+	const struct cred *dir_open_cred;
 } __randomize_layout;
 
 #define ND_ROOT_PRESET 1
@@ -695,6 +696,7 @@ static void terminate_walk(struct nameidata *nd)
 	nd->depth = 0;
 	nd->path.mnt = NULL;
 	nd->path.dentry = NULL;
+	put_cred(nd->dir_open_cred);
 }
 
 /* path_put is needed afterwards regardless of success or failure */
@@ -2414,6 +2416,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
 			get_fs_pwd(current->fs, &nd->path);
 			nd->inode = nd->path.dentry->d_inode;
 		}
+		nd->dir_open_cred = get_current_cred();
 	} else {
 		/* Caller must check execute permissions on the starting path component */
 		struct fd f = fdget_raw(nd->dfd);
@@ -2437,6 +2440,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
 			path_get(&nd->path);
 			nd->inode = nd->path.dentry->d_inode;
 		}
+		nd->dir_open_cred = get_cred(f.file->f_cred);
 		fdput(f);
 	}
 
@@ -3794,8 +3798,28 @@ static struct file *path_openat(struct nameidata *nd,
 		error = do_o_path(nd, flags, file);
 	} else {
 		const char *s = path_init(nd, flags);
-		file = alloc_empty_file(op->open_flag, current_cred());
-		error = PTR_ERR_OR_ZERO(file);
+		const struct cred *old_cred = NULL;
+
+		error = 0;
+		if (op->open_flag & OA2_INHERIT_CRED) {
+			/* Make sure to work only with restricted
+			 * look-up modes.
+			 */
+			if (!(nd->flags & (LOOKUP_BENEATH | LOOKUP_IN_ROOT)))
+				error = -EPERM;
+			/* Only work with O_CLOEXEC dirs. */
+			if (!get_close_on_exec(nd->dfd))
+				error = -EPERM;
+
+			if (!error)
+				old_cred = override_creds(nd->dir_open_cred);
+		}
+		if (!error) {
+			file = alloc_empty_file(op->open_flag, current_cred());
+			error = PTR_ERR_OR_ZERO(file);
+		} else {
+			file = ERR_PTR(error);
+		}
 		if (!error) {
 			while (!(error = link_path_walk(s, nd)) &&
 			       (s = open_last_lookups(nd, file, op)) != NULL)
@@ -3803,6 +3827,8 @@ static struct file *path_openat(struct nameidata *nd,
 		}
 		if (!error)
 			error = do_open(nd, file, op);
+		if (old_cred)
+			revert_creds(old_cred);
 		terminate_walk(nd);
 		if (IS_ERR(file))
 			return file;
diff --git a/fs/open.c b/fs/open.c
index ee8460c83c77..6be013182a35 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -1225,7 +1225,7 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op)
 	 * values before calling build_open_flags(), but openat2(2) checks all
 	 * of its arguments.
 	 */
-	if (flags & ~VALID_OPEN_FLAGS)
+	if (flags & ~VALID_OPENAT2_FLAGS)
 		return -EINVAL;
 	if (how->resolve & ~VALID_RESOLVE_FLAGS)
 		return -EINVAL;
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index a332e79b3207..b71f8b162102 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -12,6 +12,8 @@
 	 FASYNC	| O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
 	 O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
 
+#define VALID_OPENAT2_FLAGS (VALID_OPEN_FLAGS | OA2_INHERIT_CRED)
+
 /* List of all valid flags for the how->resolve argument: */
 #define VALID_RESOLVE_FLAGS \
 	(RESOLVE_NO_XDEV | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS | \
diff --git a/include/uapi/linux/openat2.h b/include/uapi/linux/openat2.h
index a5feb7604948..cdd676a10b62 100644
--- a/include/uapi/linux/openat2.h
+++ b/include/uapi/linux/openat2.h
@@ -40,4 +40,7 @@ struct open_how {
 					return -EAGAIN if that's not
 					possible. */
 
+/* openat2-specific flags go to upper 4 bytes. */
+#define OA2_INHERIT_CRED		(1ULL << 32)
+
 #endif /* _UAPI_LINUX_OPENAT2_H */
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-23 11:01 [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Stas Sergeev
  2024-04-23 11:01 ` [PATCH 1/2] fs: reorganize path_openat() Stas Sergeev
  2024-04-23 11:01 ` [PATCH 2/2] openat2: add OA2_INHERIT_CRED flag Stas Sergeev
@ 2024-04-23 16:44 ` Andy Lutomirski
  2024-04-23 18:05   ` stsp
                     ` (2 more replies)
  2 siblings, 3 replies; 13+ messages in thread
From: Andy Lutomirski @ 2024-04-23 16:44 UTC (permalink / raw)
  To: Stas Sergeev
  Cc: linux-kernel, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche


> On Apr 23, 2024, at 4:02 AM, Stas Sergeev <stsp2@yandex.ru> wrote:
> 
> This patch-set implements the OA2_INHERIT_CRED flag for openat2() syscall.
> It is needed to perform an open operation with the creds that were in
> effect when the dir_fd was opened. This allows the process to pre-open
> some dirs and switch eUID (and other UIDs/GIDs) to the less-privileged
> user, while still retaining the possibility to open/create files within
> the pre-opened directory set.

I like the concept, as it’s a sort of move toward a capability system. But I think that making a dirfd into this sort of capability would need to be much more explicit. Right now, any program could do this entirely by accident, and applying OA2_INHERIT_CRED to an fd fished out of /proc seems hazardous.

So perhaps if an open file description for a directory could have something like FMODE_CRED, and if OA2_INHERIT_CRED also blocked .., magic links, symlinks to anywhere above the dirfd (or maybe all symlinks) and absolute path lookups, then this would be okay.

Also, there are lots of ways that f_cred could be relevant: fsuid/fsgid, effective capabilities and security labels. And it gets more complex if this ever gets extended to support connecting or sending to a socket or if someone opens a device node.  Does CAP_SYS_ADMIN carry over?

> 
> Changes in v2:
> - capture full struct cred instead of just fsuid/fsgid.
>  Suggested by Stefan Metzmacher <metze@samba.org>
> 
> CC: Stefan Metzmacher <metze@samba.org>
> CC: Eric Biederman <ebiederm@xmission.com>
> CC: Alexander Viro <viro@zeniv.linux.org.uk>
> CC: Andy Lutomirski <luto@kernel.org>
> CC: Christian Brauner <brauner@kernel.org>
> CC: Jan Kara <jack@suse.cz>
> CC: Jeff Layton <jlayton@kernel.org>
> CC: Chuck Lever <chuck.lever@oracle.com>
> CC: Alexander Aring <alex.aring@gmail.com>
> CC: linux-fsdevel@vger.kernel.org
> CC: linux-kernel@vger.kernel.org
> CC: linux-api@vger.kernel.org
> CC: Paolo Bonzini <pbonzini@redhat.com>
> CC: Christian Göttsche <cgzones@googlemail.com>
> 
> Stas Sergeev (2):
>  fs: reorganize path_openat()
>  openat2: add OA2_INHERIT_CRED flag
> 
> fs/internal.h                |  2 +-
> fs/namei.c                   | 52 +++++++++++++++++++++++++++++-------
> fs/open.c                    |  2 +-
> include/linux/fcntl.h        |  2 ++
> include/uapi/linux/openat2.h |  3 +++
> 5 files changed, 50 insertions(+), 11 deletions(-)
> 
> --
> 2.44.0
> 
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-23 16:44 ` [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Andy Lutomirski
@ 2024-04-23 18:05   ` stsp
  2024-04-23 22:52   ` stsp
  2024-04-24 10:57   ` stsp
  2 siblings, 0 replies; 13+ messages in thread
From: stsp @ 2024-04-23 18:05 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: linux-kernel, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche

23.04.2024 19:44, Andy Lutomirski пишет:
>> On Apr 23, 2024, at 4:02 AM, Stas Sergeev <stsp2@yandex.ru> wrote:
>>
>> This patch-set implements the OA2_INHERIT_CRED flag for openat2() syscall.
>> It is needed to perform an open operation with the creds that were in
>> effect when the dir_fd was opened. This allows the process to pre-open
>> some dirs and switch eUID (and other UIDs/GIDs) to the less-privileged
>> user, while still retaining the possibility to open/create files within
>> the pre-opened directory set.
> I like the concept, as it’s a sort of move toward a capability system. But I think that making a dirfd into this sort of capability would need to be much more explicit. Right now, any program could do this entirely by accident, and applying OA2_INHERIT_CRED to an fd fished out of /proc seems hazardous.

Could you please clarify this a bit?
I think if you open someone else's
fd via /proc, then your current creds
would be stored in a struct file, rather
than the creds of the process from
which you open. I don't think creds
can be stolen that way, as I suppose
opening via proc is similar to open
via some symlink.
Or is there some magic going on
so that the process's creds can
actually be leaked this way?

> So perhaps if an open file description for a directory could have something like FMODE_CRED, and if OA2_INHERIT_CRED also blocked .., magic links, symlinks to anywhere above the dirfd (or maybe all symlinks) and absolute path lookups, then this would be okay.

This is already there.
My fault is that I put a short description
in a cover letter and a long description
in a patch itself. I should probably swap
them, as you only read the cover letter.
My patch takes care about possible escape
scenarios by working only with restricted
lookup modes: RESOLVE_BENEATH, RESOLVE_IN_ROOT.

I made sure that symlinks leading outside
of a sandbox, are rejected.
Also note that my patch requires O_CLOEXEC
on a dir_fd to avoid the cred leakage over
exec syscall.

> Also, there are lots of ways that f_cred could be relevant: fsuid/fsgid, effective capabilities and security labels. And it gets more complex if this ever gets extended to support connecting or sending to a socket or if someone opens a device node.  Does CAP_SYS_ADMIN carry over?
Hmm, I don't know.
The v1 version of a patch only changed
fsuid/fsgid. Stefan Metzmacher suggested
to use the full creds instead, but I haven't
considered the implications of that change
just yet.
So if using the full creds is too much because
it can carry things like CAP_SYS_ADMIN, then
should I get back to v1 and only change
fsuid/fsgid?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-23 16:44 ` [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Andy Lutomirski
  2024-04-23 18:05   ` stsp
@ 2024-04-23 22:52   ` stsp
  2024-04-24 10:57   ` stsp
  2 siblings, 0 replies; 13+ messages in thread
From: stsp @ 2024-04-23 22:52 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: linux-kernel, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche

23.04.2024 19:44, Andy Lutomirski пишет:
> Also, there are lots of ways that f_cred could be relevant: fsuid/fsgid, effective capabilities and security labels. And it gets more complex if this ever gets extended to support connecting or sending to a socket or if someone opens a device node.  Does CAP_SYS_ADMIN carry over?
I posted a v3 where I only override
fsuid, fsgid and group_info.
Capabilities and whatever else are
not overridden to avoid security risks.
Does this address your concern?

Note that I think your other concerns
are already addressed, I just added a
bit more of a description now.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-23 16:44 ` [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Andy Lutomirski
  2024-04-23 18:05   ` stsp
  2024-04-23 22:52   ` stsp
@ 2024-04-24 10:57   ` stsp
  2024-04-25  0:43     ` Andy Lutomirski
  2 siblings, 1 reply; 13+ messages in thread
From: stsp @ 2024-04-24 10:57 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: linux-kernel, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche

23.04.2024 19:44, Andy Lutomirski пишет:
>> On Apr 23, 2024, at 4:02 AM, Stas Sergeev <stsp2@yandex.ru> wrote:
>>
>> This patch-set implements the OA2_INHERIT_CRED flag for openat2() syscall.
>> It is needed to perform an open operation with the creds that were in
>> effect when the dir_fd was opened. This allows the process to pre-open
>> some dirs and switch eUID (and other UIDs/GIDs) to the less-privileged
>> user, while still retaining the possibility to open/create files within
>> the pre-opened directory set.
> I like the concept, as it’s a sort of move toward a capability system. But I think that making a dirfd into this sort of capability would need to be much more explicit. Right now, any program could do this entirely by accident, and applying OA2_INHERIT_CRED to an fd fished out of /proc seems hazardous.

While I still don't quite understand
the threat of /proc symlinks, I posted
v4 which disallows them.

> So perhaps if an open file description for a directory could have something like FMODE_CRED, and if OA2_INHERIT_CRED also blocked .., magic links, symlinks to anywhere above the dirfd (or maybe all symlinks) and absolute path lookups, then this would be okay.

So I think this all is now done.

> Also, there are lots of ways that f_cred could be relevant: fsuid/fsgid, effective capabilities and security labels. And it gets more complex if this ever gets extended to support connecting or sending to a socket or if someone opens a device node.  Does CAP_SYS_ADMIN carry over?
Not any more, nothin is carried but
fsuid, fsgid, groupinfo.

Thank you.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-24 10:57   ` stsp
@ 2024-04-25  0:43     ` Andy Lutomirski
  2024-04-25  1:43       ` Al Viro
  2024-04-25 11:02       ` stsp
  0 siblings, 2 replies; 13+ messages in thread
From: Andy Lutomirski @ 2024-04-25  0:43 UTC (permalink / raw)
  To: stsp
  Cc: linux-kernel, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche, Aleksa Sarai

On Wed, Apr 24, 2024 at 3:57 AM stsp <stsp2@yandex.ru> wrote:
>
> 23.04.2024 19:44, Andy Lutomirski пишет:
> >> On Apr 23, 2024, at 4:02 AM, Stas Sergeev <stsp2@yandex.ru> wrote:
> >>
> >> This patch-set implements the OA2_INHERIT_CRED flag for openat2() syscall.
> >> It is needed to perform an open operation with the creds that were in
> >> effect when the dir_fd was opened. This allows the process to pre-open
> >> some dirs and switch eUID (and other UIDs/GIDs) to the less-privileged
> >> user, while still retaining the possibility to open/create files within
> >> the pre-opened directory set.
> > I like the concept, as it’s a sort of move toward a capability system. But I think that making a dirfd into this sort of capability would need to be much more explicit. Right now, any program could do this entirely by accident, and applying OA2_INHERIT_CRED to an fd fished out of /proc seems hazardous.
>
> While I still don't quite understand
> the threat of /proc symlinks, I posted
> v4 which disallows them.
>

I like that, but you're blocking it the wrong way.  My concern is that
someone does dfd = open("/proc/PID/fd/3") and then openat(dfd, ...,
OA2_INHERIT_CRED);  IIRC open("/proc/PID/fd/3") is extremely magical
and returns the _same open file description_ (struct file) as PID's fd
3.

> > So perhaps if an open file description for a directory could have something like FMODE_CRED, and if OA2_INHERIT_CRED also blocked .., magic links, symlinks to anywhere above the dirfd (or maybe all symlinks) and absolute path lookups, then this would be okay.
>
> So I think this all is now done.

But you missed the FMODE_CRED part!

So here's the problem: right now, in current Linux, a dirfd pointing
to a directory that you can open anyway doesn't convey any new powers.
So, if I'm a regular program, and I do open("/etc", O_PATH), I get an
fd.  And if I get an fd pointing at /etc from somewhere else, I get
the same thing (possibly with different f_cred, but f_cred is largely
a hack to restrict things that would otherwise be insecure because
they were designed a bit wrong from the beginning).

But, with your patch, these fds suddenly convey a very strong
privilege: that of their f_cred *over the entire subtree to which they
refer*.  And you can attack it using exactly your intended use case:
if any program opens a dirfd and then drops privileges, well, oops, it
didn't actually fully drop privilege.

So I think that, if this whole concept has any chance of working well,
it needs to be opt-in *at the time of the original open*.  So a
privilege-carrying open would be an entirely new option like
O_CAPTURE_CREDS or FMODE_CREDS.  And OA2_INHERIT_CREDS is rejected if
the dirfd doesn't have that special mode.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-25  0:43     ` Andy Lutomirski
@ 2024-04-25  1:43       ` Al Viro
  2024-04-25  3:31         ` Andy Lutomirski
  2024-04-25 11:02       ` stsp
  1 sibling, 1 reply; 13+ messages in thread
From: Al Viro @ 2024-04-25  1:43 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: stsp, linux-kernel, Stefan Metzmacher, Eric Biederman,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche, Aleksa Sarai

On Wed, Apr 24, 2024 at 05:43:02PM -0700, Andy Lutomirski wrote:

> I like that, but you're blocking it the wrong way.  My concern is that
> someone does dfd = open("/proc/PID/fd/3") and then openat(dfd, ...,
> OA2_INHERIT_CRED);  IIRC open("/proc/PID/fd/3") is extremely magical
> and returns the _same open file description_ (struct file) as PID's fd
> 3.

No, it doesn't.  We could implement that, but if we do that'll be
*not* a part of procfs and it's going to be limited to current task
only.

There are two different variants of /dev/fd/* semantics - one is
"opening /dev/fd/42 is an equivalent of dup(42)", another is
"opening /dev/fd/42 is an equivalent of opening the same fs object
that is currently accessed via descriptor 42".  Linux is doing the
latter, and we can't switch - that would break a lot of userland
software, including a lot of scripts.

I'm not saying I like the series, but this particular objection is bogus -
open via procfs symlinks is *not* an equivalent of dup() and that is not
going to change.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-25  1:43       ` Al Viro
@ 2024-04-25  3:31         ` Andy Lutomirski
  0 siblings, 0 replies; 13+ messages in thread
From: Andy Lutomirski @ 2024-04-25  3:31 UTC (permalink / raw)
  To: Al Viro
  Cc: stsp, linux-kernel, Stefan Metzmacher, Eric Biederman,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche, Aleksa Sarai

On Wed, Apr 24, 2024 at 6:44 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Wed, Apr 24, 2024 at 05:43:02PM -0700, Andy Lutomirski wrote:
>
> > I like that, but you're blocking it the wrong way.  My concern is that
> > someone does dfd = open("/proc/PID/fd/3") and then openat(dfd, ...,
> > OA2_INHERIT_CRED);  IIRC open("/proc/PID/fd/3") is extremely magical
> > and returns the _same open file description_ (struct file) as PID's fd
> > 3.
>
> No, it doesn't.  We could implement that, but if we do that'll be
> *not* a part of procfs and it's going to be limited to current task
> only.

Egads -- why would we want to implement that?  In the apparently
incorrect model in my head, Linux's behavior was ridiculous and only
made sense for some historical reason.  But I wonder why I thought
that.

Diving a tiny bit down the rabbit hole, I have a copy of TLPI on my
bookshelf, and I bought it quite a long time ago and read a bunch of
it when I got it, and my copy is *wrong*!  Section 5.11 has the
behavior of /dev/fd very clearly documented as working like dup().

And here it is: erratum 107.  Whoopsies!

https://man7.org/tlpi/errata/index.html

Anyway, I retract that particular objection to the series.  But I
wouldn't be shocked if one can break a normal modern systemd using the
patchset -- systemd does all kinds of fun things involving passing
file descriptors around.

--Andy

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-25  0:43     ` Andy Lutomirski
  2024-04-25  1:43       ` Al Viro
@ 2024-04-25 11:02       ` stsp
  1 sibling, 0 replies; 13+ messages in thread
From: stsp @ 2024-04-25 11:02 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: linux-kernel, Stefan Metzmacher, Eric Biederman, Alexander Viro,
	Andy Lutomirski, Christian Brauner, Jan Kara, Jeff Layton,
	Chuck Lever, Alexander Aring, linux-fsdevel, linux-api,
	Paolo Bonzini, Christian Göttsche, Aleksa Sarai

25.04.2024 03:43, Andy Lutomirski пишет:
> But you missed the FMODE_CRED part!

OK, I thought its not needed if fd
is limited to the one created by the
same process. But your explanation
is quite clear on that its needed anyway,
or otherwise the unsuspecting process
doesn't fully drop his privs.
Thank you for explaining that bit.
Which leaves just one question: is
such an opt-in enough or not?
Viro points it may not be enough,
but doesn't explain why exactly.

Maybe we need such an opt-in, and
it should be dropped on exec() and
on passing via unix fd? I don't know
what additional restrictions are needed,
as Viro didn't clarify that part, but the
opt-in is needed for sure.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
  2024-04-23 10:58 ` Stefan Metzmacher
@ 2024-04-23 11:02   ` stsp
  0 siblings, 0 replies; 13+ messages in thread
From: stsp @ 2024-04-23 11:02 UTC (permalink / raw)
  To: Stefan Metzmacher, linux-kernel
  Cc: Eric Biederman, Alexander Viro, Andy Lutomirski,
	Christian Brauner, Jan Kara, Jeff Layton, Chuck Lever,
	Alexander Aring, linux-fsdevel, Paolo Bonzini,
	Christian Göttsche, Linux API Mailing List

23.04.2024 13:58, Stefan Metzmacher пишет:
>
> I guess this is something that should cc linux-api@vger.kernel.org ... 
Done, thanks.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2()
       [not found] <20240423104824.10464-1-stsp2@yandex.ru>
@ 2024-04-23 10:58 ` Stefan Metzmacher
  2024-04-23 11:02   ` stsp
  0 siblings, 1 reply; 13+ messages in thread
From: Stefan Metzmacher @ 2024-04-23 10:58 UTC (permalink / raw)
  To: Stas Sergeev, linux-kernel
  Cc: Eric Biederman, Alexander Viro, Andy Lutomirski,
	Christian Brauner, Jan Kara, Jeff Layton, Chuck Lever,
	Alexander Aring, linux-fsdevel, Paolo Bonzini,
	Christian Göttsche, Linux API Mailing List

Am 23.04.24 um 12:48 schrieb Stas Sergeev:
> This patch-set implements the OA2_INHERIT_CRED flag for openat2() syscall.
> It is needed to perform an open operation with the creds that were in
> effect when the dir_fd was opened. This allows the process to pre-open
> some dirs and switch eUID (and other UIDs/GIDs) to the less-privileged
> user, while still retaining the possibility to open/create files within
> the pre-opened directory set.
> 
> Changes in v2:
> - capture full struct cred instead of just fsuid/fsgid.
>    Suggested by Stefan Metzmacher <metze@samba.org>
> 
> CC: Stefan Metzmacher <metze@samba.org>
> CC: Eric Biederman <ebiederm@xmission.com>
> CC: Alexander Viro <viro@zeniv.linux.org.uk>
> CC: Andy Lutomirski <luto@kernel.org>
> CC: Christian Brauner <brauner@kernel.org>
> CC: Jan Kara <jack@suse.cz>
> CC: Jeff Layton <jlayton@kernel.org>
> CC: Chuck Lever <chuck.lever@oracle.com>
> CC: Alexander Aring <alex.aring@gmail.com>
> CC: linux-fsdevel@vger.kernel.org
> CC: linux-kernel@vger.kernel.org

I guess this is something that should cc linux-api@vger.kernel.org ...

metze


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-04-25 11:02 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-23 11:01 [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Stas Sergeev
2024-04-23 11:01 ` [PATCH 1/2] fs: reorganize path_openat() Stas Sergeev
2024-04-23 11:01 ` [PATCH 2/2] openat2: add OA2_INHERIT_CRED flag Stas Sergeev
2024-04-23 16:44 ` [PATCH v2 0/2] implement OA2_INHERIT_CRED flag for openat2() Andy Lutomirski
2024-04-23 18:05   ` stsp
2024-04-23 22:52   ` stsp
2024-04-24 10:57   ` stsp
2024-04-25  0:43     ` Andy Lutomirski
2024-04-25  1:43       ` Al Viro
2024-04-25  3:31         ` Andy Lutomirski
2024-04-25 11:02       ` stsp
     [not found] <20240423104824.10464-1-stsp2@yandex.ru>
2024-04-23 10:58 ` Stefan Metzmacher
2024-04-23 11:02   ` stsp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).