1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * fs/sysfs/group.c - Operations for adding/removing multiple files at once. 4 * 5 * Copyright (c) 2003 Patrick Mochel 6 * Copyright (c) 2003 Open Source Development Lab 7 * Copyright (c) 2013 Greg Kroah-Hartman 8 * Copyright (c) 2013 The Linux Foundation 9 */ 10 11 #include <linux/kobject.h> 12 #include <linux/module.h> 13 #include <linux/dcache.h> 14 #include <linux/namei.h> 15 #include <linux/err.h> 16 #include <linux/fs.h> 17 #include "sysfs.h" 18 19 20 static void remove_files(struct kernfs_node *parent, 21 const struct attribute_group *grp) 22 { 23 struct attribute *const *attr; 24 struct bin_attribute *const *bin_attr; 25 26 if (grp->attrs) 27 for (attr = grp->attrs; *attr; attr++) 28 kernfs_remove_by_name(parent, (*attr)->name); 29 if (grp->bin_attrs) 30 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) 31 kernfs_remove_by_name(parent, (*bin_attr)->attr.name); 32 } 33 34 static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj) 35 { 36 if (grp->attrs && grp->attrs[0] && grp->is_visible) 37 return grp->is_visible(kobj, grp->attrs[0], 0); 38 39 if (grp->bin_attrs && grp->bin_attrs[0] && grp->is_bin_visible) 40 return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0); 41 42 return 0; 43 } 44 45 static int create_files(struct kernfs_node *parent, struct kobject *kobj, 46 kuid_t uid, kgid_t gid, 47 const struct attribute_group *grp, int update) 48 { 49 struct attribute *const *attr; 50 struct bin_attribute *const *bin_attr; 51 int error = 0, i; 52 53 if (grp->attrs) { 54 for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { 55 umode_t mode = (*attr)->mode; 56 57 /* 58 * In update mode, we're changing the permissions or 59 * visibility. Do this by first removing then 60 * re-adding (if required) the file. 61 */ 62 if (update) 63 kernfs_remove_by_name(parent, (*attr)->name); 64 if (grp->is_visible) { 65 mode = grp->is_visible(kobj, *attr, i); 66 mode &= ~SYSFS_GROUP_INVISIBLE; 67 if (!mode) 68 continue; 69 } 70 71 WARN(mode & ~(SYSFS_PREALLOC | 0664), 72 "Attribute %s: Invalid permissions 0%o\n", 73 (*attr)->name, mode); 74 75 mode &= SYSFS_PREALLOC | 0664; 76 error = sysfs_add_file_mode_ns(parent, *attr, mode, uid, 77 gid, NULL); 78 if (unlikely(error)) 79 break; 80 } 81 if (error) { 82 remove_files(parent, grp); 83 goto exit; 84 } 85 } 86 87 if (grp->bin_attrs) { 88 for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) { 89 umode_t mode = (*bin_attr)->attr.mode; 90 91 if (update) 92 kernfs_remove_by_name(parent, 93 (*bin_attr)->attr.name); 94 if (grp->is_bin_visible) { 95 mode = grp->is_bin_visible(kobj, *bin_attr, i); 96 mode &= ~SYSFS_GROUP_INVISIBLE; 97 if (!mode) 98 continue; 99 } 100 101 WARN(mode & ~(SYSFS_PREALLOC | 0664), 102 "Attribute %s: Invalid permissions 0%o\n", 103 (*bin_attr)->attr.name, mode); 104 105 mode &= SYSFS_PREALLOC | 0664; 106 error = sysfs_add_bin_file_mode_ns(parent, *bin_attr, 107 mode, uid, gid, 108 NULL); 109 if (error) 110 break; 111 } 112 if (error) 113 remove_files(parent, grp); 114 } 115 exit: 116 return error; 117 } 118 119 120 static int internal_create_group(struct kobject *kobj, int update, 121 const struct attribute_group *grp) 122 { 123 struct kernfs_node *kn; 124 kuid_t uid; 125 kgid_t gid; 126 int error; 127 128 if (WARN_ON(!kobj || (!update && !kobj->sd))) 129 return -EINVAL; 130 131 /* Updates may happen before the object has been instantiated */ 132 if (unlikely(update && !kobj->sd)) 133 return -EINVAL; 134 135 if (!grp->attrs && !grp->bin_attrs) { 136 pr_debug("sysfs: (bin_)attrs not set by subsystem for group: %s/%s, skipping\n", 137 kobj->name, grp->name ?: ""); 138 return 0; 139 } 140 141 kobject_get_ownership(kobj, &uid, &gid); 142 if (grp->name) { 143 umode_t mode = __first_visible(grp, kobj); 144 145 if (mode & SYSFS_GROUP_INVISIBLE) 146 mode = 0; 147 else 148 mode = S_IRWXU | S_IRUGO | S_IXUGO; 149 150 if (update) { 151 kn = kernfs_find_and_get(kobj->sd, grp->name); 152 if (!kn) { 153 pr_debug("attr grp %s/%s not created yet\n", 154 kobj->name, grp->name); 155 /* may have been invisible prior to this update */ 156 update = 0; 157 } else if (!mode) { 158 sysfs_remove_group(kobj, grp); 159 kernfs_put(kn); 160 return 0; 161 } 162 } 163 164 if (!update) { 165 if (!mode) 166 return 0; 167 kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode, 168 uid, gid, kobj, NULL); 169 if (IS_ERR(kn)) { 170 if (PTR_ERR(kn) == -EEXIST) 171 sysfs_warn_dup(kobj->sd, grp->name); 172 return PTR_ERR(kn); 173 } 174 } 175 } else { 176 kn = kobj->sd; 177 } 178 179 kernfs_get(kn); 180 error = create_files(kn, kobj, uid, gid, grp, update); 181 if (error) { 182 if (grp->name) 183 kernfs_remove(kn); 184 } 185 kernfs_put(kn); 186 187 if (grp->name && update) 188 kernfs_put(kn); 189 190 return error; 191 } 192 193 /** 194 * sysfs_create_group - given a directory kobject, create an attribute group 195 * @kobj: The kobject to create the group on 196 * @grp: The attribute group to create 197 * 198 * This function creates a group for the first time. It will explicitly 199 * warn and error if any of the attribute files being created already exist. 200 * 201 * Returns 0 on success or error code on failure. 202 */ 203 int sysfs_create_group(struct kobject *kobj, 204 const struct attribute_group *grp) 205 { 206 return internal_create_group(kobj, 0, grp); 207 } 208 EXPORT_SYMBOL_GPL(sysfs_create_group); 209 210 static int internal_create_groups(struct kobject *kobj, int update, 211 const struct attribute_group **groups) 212 { 213 int error = 0; 214 int i; 215 216 if (!groups) 217 return 0; 218 219 for (i = 0; groups[i]; i++) { 220 error = internal_create_group(kobj, update, groups[i]); 221 if (error) { 222 while (--i >= 0) 223 sysfs_remove_group(kobj, groups[i]); 224 break; 225 } 226 } 227 return error; 228 } 229 230 /** 231 * sysfs_create_groups - given a directory kobject, create a bunch of attribute groups 232 * @kobj: The kobject to create the group on 233 * @groups: The attribute groups to create, NULL terminated 234 * 235 * This function creates a bunch of attribute groups. If an error occurs when 236 * creating a group, all previously created groups will be removed, unwinding 237 * everything back to the original state when this function was called. 238 * It will explicitly warn and error if any of the attribute files being 239 * created already exist. 240 * 241 * Returns 0 on success or error code from sysfs_create_group on failure. 242 */ 243 int sysfs_create_groups(struct kobject *kobj, 244 const struct attribute_group **groups) 245 { 246 return internal_create_groups(kobj, 0, groups); 247 } 248 EXPORT_SYMBOL_GPL(sysfs_create_groups); 249 250 /** 251 * sysfs_update_groups - given a directory kobject, create a bunch of attribute groups 252 * @kobj: The kobject to update the group on 253 * @groups: The attribute groups to update, NULL terminated 254 * 255 * This function update a bunch of attribute groups. If an error occurs when 256 * updating a group, all previously updated groups will be removed together 257 * with already existing (not updated) attributes. 258 * 259 * Returns 0 on success or error code from sysfs_update_group on failure. 260 */ 261 int sysfs_update_groups(struct kobject *kobj, 262 const struct attribute_group **groups) 263 { 264 return internal_create_groups(kobj, 1, groups); 265 } 266 EXPORT_SYMBOL_GPL(sysfs_update_groups); 267 268 /** 269 * sysfs_update_group - given a directory kobject, update an attribute group 270 * @kobj: The kobject to update the group on 271 * @grp: The attribute group to update 272 * 273 * This function updates an attribute group. Unlike 274 * sysfs_create_group(), it will explicitly not warn or error if any 275 * of the attribute files being created already exist. Furthermore, 276 * if the visibility of the files has changed through the is_visible() 277 * callback, it will update the permissions and add or remove the 278 * relevant files. Changing a group's name (subdirectory name under 279 * kobj's directory in sysfs) is not allowed. 280 * 281 * The primary use for this function is to call it after making a change 282 * that affects group visibility. 283 * 284 * Returns 0 on success or error code on failure. 285 */ 286 int sysfs_update_group(struct kobject *kobj, 287 const struct attribute_group *grp) 288 { 289 return internal_create_group(kobj, 1, grp); 290 } 291 EXPORT_SYMBOL_GPL(sysfs_update_group); 292 293 /** 294 * sysfs_remove_group: remove a group from a kobject 295 * @kobj: kobject to remove the group from 296 * @grp: group to remove 297 * 298 * This function removes a group of attributes from a kobject. The attributes 299 * previously have to have been created for this group, otherwise it will fail. 300 */ 301 void sysfs_remove_group(struct kobject *kobj, 302 const struct attribute_group *grp) 303 { 304 struct kernfs_node *parent = kobj->sd; 305 struct kernfs_node *kn; 306 307 if (grp->name) { 308 kn = kernfs_find_and_get(parent, grp->name); 309 if (!kn) { 310 pr_debug("sysfs group '%s' not found for kobject '%s'\n", 311 grp->name, kobject_name(kobj)); 312 return; 313 } 314 } else { 315 kn = parent; 316 kernfs_get(kn); 317 } 318 319 remove_files(kn, grp); 320 if (grp->name) 321 kernfs_remove(kn); 322 323 kernfs_put(kn); 324 } 325 EXPORT_SYMBOL_GPL(sysfs_remove_group); 326 327 /** 328 * sysfs_remove_groups - remove a list of groups 329 * 330 * @kobj: The kobject for the groups to be removed from 331 * @groups: NULL terminated list of groups to be removed 332 * 333 * If groups is not NULL, remove the specified groups from the kobject. 334 */ 335 void sysfs_remove_groups(struct kobject *kobj, 336 const struct attribute_group **groups) 337 { 338 int i; 339 340 if (!groups) 341 return; 342 for (i = 0; groups[i]; i++) 343 sysfs_remove_group(kobj, groups[i]); 344 } 345 EXPORT_SYMBOL_GPL(sysfs_remove_groups); 346 347 /** 348 * sysfs_merge_group - merge files into a pre-existing named attribute group. 349 * @kobj: The kobject containing the group. 350 * @grp: The files to create and the attribute group they belong to. 351 * 352 * This function returns an error if the group doesn't exist, the .name field is 353 * NULL or any of the files already exist in that group, in which case none of 354 * the new files are created. 355 */ 356 int sysfs_merge_group(struct kobject *kobj, 357 const struct attribute_group *grp) 358 { 359 struct kernfs_node *parent; 360 kuid_t uid; 361 kgid_t gid; 362 int error = 0; 363 struct attribute *const *attr; 364 int i; 365 366 parent = kernfs_find_and_get(kobj->sd, grp->name); 367 if (!parent) 368 return -ENOENT; 369 370 kobject_get_ownership(kobj, &uid, &gid); 371 372 for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr)) 373 error = sysfs_add_file_mode_ns(parent, *attr, (*attr)->mode, 374 uid, gid, NULL); 375 if (error) { 376 while (--i >= 0) 377 kernfs_remove_by_name(parent, (*--attr)->name); 378 } 379 kernfs_put(parent); 380 381 return error; 382 } 383 EXPORT_SYMBOL_GPL(sysfs_merge_group); 384 385 /** 386 * sysfs_unmerge_group - remove files from a pre-existing named attribute group. 387 * @kobj: The kobject containing the group. 388 * @grp: The files to remove and the attribute group they belong to. 389 */ 390 void sysfs_unmerge_group(struct kobject *kobj, 391 const struct attribute_group *grp) 392 { 393 struct kernfs_node *parent; 394 struct attribute *const *attr; 395 396 parent = kernfs_find_and_get(kobj->sd, grp->name); 397 if (parent) { 398 for (attr = grp->attrs; *attr; ++attr) 399 kernfs_remove_by_name(parent, (*attr)->name); 400 kernfs_put(parent); 401 } 402 } 403 EXPORT_SYMBOL_GPL(sysfs_unmerge_group); 404 405 /** 406 * sysfs_add_link_to_group - add a symlink to an attribute group. 407 * @kobj: The kobject containing the group. 408 * @group_name: The name of the group. 409 * @target: The target kobject of the symlink to create. 410 * @link_name: The name of the symlink to create. 411 */ 412 int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, 413 struct kobject *target, const char *link_name) 414 { 415 struct kernfs_node *parent; 416 int error = 0; 417 418 parent = kernfs_find_and_get(kobj->sd, group_name); 419 if (!parent) 420 return -ENOENT; 421 422 error = sysfs_create_link_sd(parent, target, link_name); 423 kernfs_put(parent); 424 425 return error; 426 } 427 EXPORT_SYMBOL_GPL(sysfs_add_link_to_group); 428 429 /** 430 * sysfs_remove_link_from_group - remove a symlink from an attribute group. 431 * @kobj: The kobject containing the group. 432 * @group_name: The name of the group. 433 * @link_name: The name of the symlink to remove. 434 */ 435 void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, 436 const char *link_name) 437 { 438 struct kernfs_node *parent; 439 440 parent = kernfs_find_and_get(kobj->sd, group_name); 441 if (parent) { 442 kernfs_remove_by_name(parent, link_name); 443 kernfs_put(parent); 444 } 445 } 446 EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); 447 448 /** 449 * compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing 450 * to a group or an attribute 451 * @kobj: The kobject containing the group. 452 * @target_kobj: The target kobject. 453 * @target_name: The name of the target group or attribute. 454 * @symlink_name: The name of the symlink file (target_name will be 455 * considered if symlink_name is NULL). 456 */ 457 int compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, 458 struct kobject *target_kobj, 459 const char *target_name, 460 const char *symlink_name) 461 { 462 struct kernfs_node *target; 463 struct kernfs_node *entry; 464 struct kernfs_node *link; 465 466 /* 467 * We don't own @target_kobj and it may be removed at any time. 468 * Synchronize using sysfs_symlink_target_lock. See sysfs_remove_dir() 469 * for details. 470 */ 471 spin_lock(&sysfs_symlink_target_lock); 472 target = target_kobj->sd; 473 if (target) 474 kernfs_get(target); 475 spin_unlock(&sysfs_symlink_target_lock); 476 if (!target) 477 return -ENOENT; 478 479 entry = kernfs_find_and_get(target, target_name); 480 if (!entry) { 481 kernfs_put(target); 482 return -ENOENT; 483 } 484 485 if (!symlink_name) 486 symlink_name = target_name; 487 488 link = kernfs_create_link(kobj->sd, symlink_name, entry); 489 if (PTR_ERR(link) == -EEXIST) 490 sysfs_warn_dup(kobj->sd, symlink_name); 491 492 kernfs_put(entry); 493 kernfs_put(target); 494 return PTR_ERR_OR_ZERO(link); 495 } 496 EXPORT_SYMBOL_GPL(compat_only_sysfs_link_entry_to_kobj); 497 498 static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn, 499 const struct attribute_group *grp, 500 struct iattr *newattrs) 501 { 502 struct kernfs_node *kn; 503 int error; 504 505 if (grp->attrs) { 506 struct attribute *const *attr; 507 508 for (attr = grp->attrs; *attr; attr++) { 509 kn = kernfs_find_and_get(grp_kn, (*attr)->name); 510 if (!kn) 511 return -ENOENT; 512 513 error = kernfs_setattr(kn, newattrs); 514 kernfs_put(kn); 515 if (error) 516 return error; 517 } 518 } 519 520 if (grp->bin_attrs) { 521 struct bin_attribute *const *bin_attr; 522 523 for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) { 524 kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name); 525 if (!kn) 526 return -ENOENT; 527 528 error = kernfs_setattr(kn, newattrs); 529 kernfs_put(kn); 530 if (error) 531 return error; 532 } 533 } 534 535 return 0; 536 } 537 538 /** 539 * sysfs_group_change_owner - change owner of an attribute group. 540 * @kobj: The kobject containing the group. 541 * @grp: The attribute group. 542 * @kuid: new owner's kuid 543 * @kgid: new owner's kgid 544 * 545 * Returns 0 on success or error code on failure. 546 */ 547 int sysfs_group_change_owner(struct kobject *kobj, 548 const struct attribute_group *grp, kuid_t kuid, 549 kgid_t kgid) 550 { 551 struct kernfs_node *grp_kn; 552 int error; 553 struct iattr newattrs = { 554 .ia_valid = ATTR_UID | ATTR_GID, 555 .ia_uid = kuid, 556 .ia_gid = kgid, 557 }; 558 559 if (!kobj->state_in_sysfs) 560 return -EINVAL; 561 562 if (grp->name) { 563 grp_kn = kernfs_find_and_get(kobj->sd, grp->name); 564 } else { 565 kernfs_get(kobj->sd); 566 grp_kn = kobj->sd; 567 } 568 if (!grp_kn) 569 return -ENOENT; 570 571 error = kernfs_setattr(grp_kn, &newattrs); 572 if (!error) 573 error = sysfs_group_attrs_change_owner(grp_kn, grp, &newattrs); 574 575 kernfs_put(grp_kn); 576 577 return error; 578 } 579 EXPORT_SYMBOL_GPL(sysfs_group_change_owner); 580 581 /** 582 * sysfs_groups_change_owner - change owner of a set of attribute groups. 583 * @kobj: The kobject containing the groups. 584 * @groups: The attribute groups. 585 * @kuid: new owner's kuid 586 * @kgid: new owner's kgid 587 * 588 * Returns 0 on success or error code on failure. 589 */ 590 int sysfs_groups_change_owner(struct kobject *kobj, 591 const struct attribute_group **groups, 592 kuid_t kuid, kgid_t kgid) 593 { 594 int error = 0, i; 595 596 if (!kobj->state_in_sysfs) 597 return -EINVAL; 598 599 if (!groups) 600 return 0; 601 602 for (i = 0; groups[i]; i++) { 603 error = sysfs_group_change_owner(kobj, groups[i], kuid, kgid); 604 if (error) 605 break; 606 } 607 608 return error; 609 } 610 EXPORT_SYMBOL_GPL(sysfs_groups_change_owner); 611