2023-12-01 12:57:05

by Max Kellermann

[permalink] [raw]
Subject: [PATCH 1/2] kernel/cgroup: use kernfs_create_dir_ns()

By passing the fsugid to kernfs_create_dir_ns(), we don't need
cgroup_kn_set_ugid() any longer. That function was added for exactly
this purpose by commit 49957f8e2a ("cgroup: newly created dirs and
files should be owned by the creator").

Eliminating this piece of duplicate code means we benefit from future
improvements to kernfs_create_dir_ns(); for example, both are lacking
S_ISGID support currently, which my next patch will add to
kernfs_create_dir_ns(). It cannot (easily) be added to
cgroup_kn_set_ugid() because we can't dereference struct kernfs_iattrs
from there.

Signed-off-by: Max Kellermann <[email protected]>
---
kernel/cgroup/cgroup.c | 31 ++++---------------------------
1 file changed, 4 insertions(+), 27 deletions(-)

diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 4b9ff41ca603..a844b421fd83 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -4169,20 +4169,6 @@ static struct kernfs_ops cgroup_kf_ops = {
.seq_show = cgroup_seqfile_show,
};

-/* set uid and gid of cgroup dirs and files to that of the creator */
-static int cgroup_kn_set_ugid(struct kernfs_node *kn)
-{
- struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
- .ia_uid = current_fsuid(),
- .ia_gid = current_fsgid(), };
-
- if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
- gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
- return 0;
-
- return kernfs_setattr(kn, &iattr);
-}
-
static void cgroup_file_notify_timer(struct timer_list *timer)
{
cgroup_file_notify(container_of(timer, struct cgroup_file,
@@ -4195,25 +4181,18 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp,
char name[CGROUP_FILE_NAME_MAX];
struct kernfs_node *kn;
struct lock_class_key *key = NULL;
- int ret;

#ifdef CONFIG_DEBUG_LOCK_ALLOC
key = &cft->lockdep_key;
#endif
kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
cgroup_file_mode(cft),
- GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+ current_fsuid(), current_fsgid(),
0, cft->kf_ops, cft,
NULL, key);
if (IS_ERR(kn))
return PTR_ERR(kn);

- ret = cgroup_kn_set_ugid(kn);
- if (ret) {
- kernfs_remove(kn);
- return ret;
- }
-
if (cft->file_offset) {
struct cgroup_file *cfile = (void *)css + cft->file_offset;

@@ -5616,7 +5595,9 @@ static struct cgroup *cgroup_create(struct cgroup *parent, const char *name,
goto out_cancel_ref;

/* create the directory */
- kn = kernfs_create_dir(parent->kn, name, mode, cgrp);
+ kn = kernfs_create_dir_ns(parent->kn, name, mode,
+ current_fsuid(), current_fsgid(),
+ cgrp, NULL);
if (IS_ERR(kn)) {
ret = PTR_ERR(kn);
goto out_stat_exit;
@@ -5761,10 +5742,6 @@ int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, umode_t mode)
*/
kernfs_get(cgrp->kn);

- ret = cgroup_kn_set_ugid(cgrp->kn);
- if (ret)
- goto out_destroy;
-
ret = css_populate_dir(&cgrp->self);
if (ret)
goto out_destroy;
--
2.39.2


2023-12-01 12:57:11

by Max Kellermann

[permalink] [raw]
Subject: [PATCH 2/2] fs/kernfs/dir: obey S_ISGID

Handling of S_ISGID is usually done by inode_init_owner() in all other
filesystems, but kernfs doesn't use that function. In kernfs, struct
kernfs_node is the primary data structure, and struct inode is only
created from it on demand. Therefore, inode_init_owner() can't be
used and we need to imitate its behavior.

S_ISGID support is useful for the cgroup filesystem; it allows
subtrees managed by an unprivileged process to retain a certain owner
gid, which then enables sharing access to the subtree with another
unprivileged process.

Signed-off-by: Max Kellermann <[email protected]>
---
fs/kernfs/dir.c | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 8b2bd65d70e7..7580cc340d28 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -676,6 +676,17 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
{
struct kernfs_node *kn;

+ if (parent->mode & S_ISGID) {
+ /* this code block imitates inode_init_owner() for
+ * kernfs */
+
+ if (parent->iattr)
+ gid = parent->iattr->ia_gid;
+
+ if (flags & KERNFS_DIR)
+ mode |= S_ISGID;
+ }
+
kn = __kernfs_new_node(kernfs_root(parent), parent,
name, mode, uid, gid, flags);
if (kn) {
--
2.39.2

2023-12-01 16:59:44

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH 1/2] kernel/cgroup: use kernfs_create_dir_ns()

Hello,

On Fri, Dec 01, 2023 at 01:56:37PM +0100, Max Kellermann wrote:
> By passing the fsugid to kernfs_create_dir_ns(), we don't need
> cgroup_kn_set_ugid() any longer. That function was added for exactly
> this purpose by commit 49957f8e2a ("cgroup: newly created dirs and
> files should be owned by the creator").
>
> Eliminating this piece of duplicate code means we benefit from future
> improvements to kernfs_create_dir_ns(); for example, both are lacking
> S_ISGID support currently, which my next patch will add to
> kernfs_create_dir_ns(). It cannot (easily) be added to
> cgroup_kn_set_ugid() because we can't dereference struct kernfs_iattrs
> from there.
>
> Signed-off-by: Max Kellermann <[email protected]>

Acked-by: Tejun Heo <[email protected]>

Greg, given that the two patches are related, it'd probably be less
confusing to route them together through your tree. If you want to route
them differently, please let me know.

Thanks.

--
tejun

2023-12-01 17:00:00

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH 2/2] fs/kernfs/dir: obey S_ISGID

On Fri, Dec 01, 2023 at 01:56:38PM +0100, Max Kellermann wrote:
> Handling of S_ISGID is usually done by inode_init_owner() in all other
> filesystems, but kernfs doesn't use that function. In kernfs, struct
> kernfs_node is the primary data structure, and struct inode is only
> created from it on demand. Therefore, inode_init_owner() can't be
> used and we need to imitate its behavior.
>
> S_ISGID support is useful for the cgroup filesystem; it allows
> subtrees managed by an unprivileged process to retain a certain owner
> gid, which then enables sharing access to the subtree with another
> unprivileged process.
>
> Signed-off-by: Max Kellermann <[email protected]>

Acked-by: Tejun Heo <[email protected]>

Thanks.

--
tejun

2023-12-04 12:22:28

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 2/2] fs/kernfs/dir: obey S_ISGID

On Fri, Dec 01, 2023 at 01:56:38PM +0100, Max Kellermann wrote:
> Handling of S_ISGID is usually done by inode_init_owner() in all other
> filesystems, but kernfs doesn't use that function. In kernfs, struct
> kernfs_node is the primary data structure, and struct inode is only
> created from it on demand. Therefore, inode_init_owner() can't be
> used and we need to imitate its behavior.
>
> S_ISGID support is useful for the cgroup filesystem; it allows
> subtrees managed by an unprivileged process to retain a certain owner
> gid, which then enables sharing access to the subtree with another
> unprivileged process.
>
> Signed-off-by: Max Kellermann <[email protected]>
> ---
> fs/kernfs/dir.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)

I only see patch 2/2 here, what happened to patch 1/2?

Please send them as a full series, otherwise I don't know what to do
with just this one.

thanks,

greg k-h

2023-12-04 12:44:15

by Max Kellermann

[permalink] [raw]
Subject: Re: [PATCH 2/2] fs/kernfs/dir: obey S_ISGID

On Mon, Dec 4, 2023 at 1:22 PM Greg Kroah-Hartman
<[email protected]> wrote:
> I only see patch 2/2 here, what happened to patch 1/2?

I used "get_maintainer.pl" as "tocmd/cccmd", and apparently, only the
second patch touches code that you maintain, and "git send-email"
determines the destinations for each individual patch, not for the
series, so the first patch wasn't sent to you directly. Not sure how
to configure "git send-email" to merge the destinations of the whole
series for all patches, but I'll figure it out for v2 (fixing two
minor checkpatch warnings). Meanwhile, you can see the first patch
here: https://lore.kernel.org/lkml/[email protected]/