Skip to content

Commit 303a427

Browse files
Christian Braunerdavem330
authored andcommitted
sysfs: add sysfs_group{s}_change_owner()
Add helpers to change the owner of sysfs groups. This function will be used to correctly account for kobject ownership changes, e.g. when moving network devices between network namespaces. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0666a3a commit 303a427

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

fs/sysfs/group.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/dcache.h>
1414
#include <linux/namei.h>
1515
#include <linux/err.h>
16+
#include <linux/fs.h>
1617
#include "sysfs.h"
1718

1819

@@ -457,3 +458,117 @@ int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj,
457458
return PTR_ERR_OR_ZERO(link);
458459
}
459460
EXPORT_SYMBOL_GPL(__compat_only_sysfs_link_entry_to_kobj);
461+
462+
static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
463+
const struct attribute_group *grp,
464+
struct iattr *newattrs)
465+
{
466+
struct kernfs_node *kn;
467+
int error;
468+
469+
if (grp->attrs) {
470+
struct attribute *const *attr;
471+
472+
for (attr = grp->attrs; *attr; attr++) {
473+
kn = kernfs_find_and_get(grp_kn, (*attr)->name);
474+
if (!kn)
475+
return -ENOENT;
476+
477+
error = kernfs_setattr(kn, newattrs);
478+
kernfs_put(kn);
479+
if (error)
480+
return error;
481+
}
482+
}
483+
484+
if (grp->bin_attrs) {
485+
struct bin_attribute *const *bin_attr;
486+
487+
for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
488+
kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name);
489+
if (!kn)
490+
return -ENOENT;
491+
492+
error = kernfs_setattr(kn, newattrs);
493+
kernfs_put(kn);
494+
if (error)
495+
return error;
496+
}
497+
}
498+
499+
return 0;
500+
}
501+
502+
/**
503+
* sysfs_group_change_owner - change owner of an attribute group.
504+
* @kobj: The kobject containing the group.
505+
* @grp: The attribute group.
506+
* @kuid: new owner's kuid
507+
* @kgid: new owner's kgid
508+
*
509+
* Returns 0 on success or error code on failure.
510+
*/
511+
int sysfs_group_change_owner(struct kobject *kobj,
512+
const struct attribute_group *grp, kuid_t kuid,
513+
kgid_t kgid)
514+
{
515+
struct kernfs_node *grp_kn;
516+
int error;
517+
struct iattr newattrs = {
518+
.ia_valid = ATTR_UID | ATTR_GID,
519+
.ia_uid = kuid,
520+
.ia_gid = kgid,
521+
};
522+
523+
if (!kobj->state_in_sysfs)
524+
return -EINVAL;
525+
526+
if (grp->name) {
527+
grp_kn = kernfs_find_and_get(kobj->sd, grp->name);
528+
} else {
529+
kernfs_get(kobj->sd);
530+
grp_kn = kobj->sd;
531+
}
532+
if (!grp_kn)
533+
return -ENOENT;
534+
535+
error = kernfs_setattr(grp_kn, &newattrs);
536+
if (!error)
537+
error = sysfs_group_attrs_change_owner(grp_kn, grp, &newattrs);
538+
539+
kernfs_put(grp_kn);
540+
541+
return error;
542+
}
543+
EXPORT_SYMBOL_GPL(sysfs_group_change_owner);
544+
545+
/**
546+
* sysfs_groups_change_owner - change owner of a set of attribute groups.
547+
* @kobj: The kobject containing the groups.
548+
* @groups: The attribute groups.
549+
* @kuid: new owner's kuid
550+
* @kgid: new owner's kgid
551+
*
552+
* Returns 0 on success or error code on failure.
553+
*/
554+
int sysfs_groups_change_owner(struct kobject *kobj,
555+
const struct attribute_group **groups,
556+
kuid_t kuid, kgid_t kgid)
557+
{
558+
int error = 0, i;
559+
560+
if (!kobj->state_in_sysfs)
561+
return -EINVAL;
562+
563+
if (!groups)
564+
return 0;
565+
566+
for (i = 0; groups[i]; i++) {
567+
error = sysfs_group_change_owner(kobj, groups[i], kuid, kgid);
568+
if (error)
569+
break;
570+
}
571+
572+
return error;
573+
}
574+
EXPORT_SYMBOL_GPL(sysfs_groups_change_owner);

include/linux/sysfs.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,12 @@ int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid,
314314
kgid_t kgid);
315315
int sysfs_link_change_owner(struct kobject *kobj, struct kobject *targ,
316316
const char *name, kuid_t kuid, kgid_t kgid);
317+
int sysfs_groups_change_owner(struct kobject *kobj,
318+
const struct attribute_group **groups,
319+
kuid_t kuid, kgid_t kgid);
320+
int sysfs_group_change_owner(struct kobject *kobj,
321+
const struct attribute_group *groups, kuid_t kuid,
322+
kgid_t kgid);
317323

318324
#else /* CONFIG_SYSFS */
319325

@@ -542,6 +548,20 @@ static inline int sysfs_link_change_owner(struct kobject *kobj,
542548
return 0;
543549
}
544550

551+
static inline int sysfs_groups_change_owner(struct kobject *kobj,
552+
const struct attribute_group **groups,
553+
kuid_t kuid, kgid_t kgid)
554+
{
555+
return 0;
556+
}
557+
558+
static inline int sysfs_group_change_owner(struct kobject *kobj,
559+
const struct attribute_group **groups,
560+
kuid_t kuid, kgid_t kgid)
561+
{
562+
return 0;
563+
}
564+
545565
#endif /* CONFIG_SYSFS */
546566

547567
static inline int __must_check sysfs_create_file(struct kobject *kobj,

0 commit comments

Comments
 (0)