Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge patch series "creds: add {scoped_}with_kernel_creds()"

Christian Brauner <brauner@kernel.org> says:

A few months ago I did work to make override_creds()/revert_creds()
completely reference count free - mostly for the sake of
overlayfs but it has been beneficial to everyone using this.

In a recent pull request from Jens that introduced another round of
override_creds()/revert_creds() for nbd Linus asked whether we could
avoide the prepare_kernel_creds() calls that duplicate the kernel
credentials and then drop them again later.

Yes, we can actually. We can use the guard infrastructure to completely
avoid the allocation and then also to never expose the temporary
variable to hold the kernel credentials anywhere in the callers.

So add with_kernel_creds() and scoped_with_kernel_creds() for this
purpose. Also take the opportunity to fixup the scoped_class() macro I
introduced two cycles ago.

* patches from https://patch.msgid.link/20251103-work-creds-init_cred-v1-0-cb3ec8711a6a@kernel.org:
unix: don't copy creds
target: don't copy kernel creds
nbd: don't copy kernel creds
firmware: don't copy kernel creds
cred: add {scoped_}with_kernel_creds
cred: make init_cred static
cred: add kernel_cred() helper
cleanup: fix scoped_class()

Link: https://patch.msgid.link/20251103-work-creds-init_cred-v1-0-cb3ec8711a6a@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

+101 -126
+25 -34
drivers/base/firmware_loader/main.c
··· 829 829 size_t offset, u32 opt_flags) 830 830 { 831 831 struct firmware *fw = NULL; 832 - struct cred *kern_cred = NULL; 833 - const struct cred *old_cred; 834 832 bool nondirect = false; 835 833 int ret; 836 834 ··· 869 871 * called by a driver when serving an unrelated request from userland, we use 870 872 * the kernel credentials to read the file. 871 873 */ 872 - kern_cred = prepare_kernel_cred(&init_task); 873 - if (!kern_cred) { 874 - ret = -ENOMEM; 875 - goto out; 876 - } 877 - old_cred = override_creds(kern_cred); 874 + scoped_with_kernel_creds() { 875 + ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); 878 876 879 - ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL); 880 - 881 - /* Only full reads can support decompression, platform, and sysfs. */ 882 - if (!(opt_flags & FW_OPT_PARTIAL)) 883 - nondirect = true; 877 + /* Only full reads can support decompression, platform, and sysfs. */ 878 + if (!(opt_flags & FW_OPT_PARTIAL)) 879 + nondirect = true; 884 880 885 881 #ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD 886 - if (ret == -ENOENT && nondirect) 887 - ret = fw_get_filesystem_firmware(device, fw->priv, ".zst", 888 - fw_decompress_zstd); 882 + if (ret == -ENOENT && nondirect) 883 + ret = fw_get_filesystem_firmware(device, fw->priv, ".zst", 884 + fw_decompress_zstd); 889 885 #endif 890 886 #ifdef CONFIG_FW_LOADER_COMPRESS_XZ 891 - if (ret == -ENOENT && nondirect) 892 - ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", 893 - fw_decompress_xz); 887 + if (ret == -ENOENT && nondirect) 888 + ret = fw_get_filesystem_firmware(device, fw->priv, ".xz", 889 + fw_decompress_xz); 894 890 #endif 895 - if (ret == -ENOENT && nondirect) 896 - ret = firmware_fallback_platform(fw->priv); 891 + if (ret == -ENOENT && nondirect) 892 + ret = firmware_fallback_platform(fw->priv); 897 893 898 - if (ret) { 899 - if (!(opt_flags & FW_OPT_NO_WARN)) 900 - dev_warn(device, 901 - "Direct firmware load for %s failed with error %d\n", 902 - name, ret); 903 - if (nondirect) 904 - ret = firmware_fallback_sysfs(fw, name, device, 905 - opt_flags, ret); 906 - } else 907 - ret = assign_fw(fw, device); 908 - 909 - revert_creds(old_cred); 910 - put_cred(kern_cred); 894 + if (ret) { 895 + if (!(opt_flags & FW_OPT_NO_WARN)) 896 + dev_warn(device, 897 + "Direct firmware load for %s failed with error %d\n", 898 + name, ret); 899 + if (nondirect) 900 + ret = firmware_fallback_sysfs(fw, name, device, 901 + opt_flags, ret); 902 + } else { 903 + ret = assign_fw(fw, device); 904 + } 905 + } 911 906 912 907 out: 913 908 if (ret < 0) {
+19 -31
drivers/block/nbd.c
··· 52 52 static DEFINE_IDR(nbd_index_idr); 53 53 static DEFINE_MUTEX(nbd_index_mutex); 54 54 static struct workqueue_struct *nbd_del_wq; 55 - static struct cred *nbd_cred; 56 55 static int nbd_total_devices = 0; 57 56 58 57 struct nbd_sock { ··· 554 555 int result; 555 556 struct msghdr msg = {} ; 556 557 unsigned int noreclaim_flag; 557 - const struct cred *old_cred; 558 558 559 559 if (unlikely(!sock)) { 560 560 dev_err_ratelimited(disk_to_dev(nbd->disk), ··· 562 564 return -EINVAL; 563 565 } 564 566 565 - old_cred = override_creds(nbd_cred); 566 - 567 567 msg.msg_iter = *iter; 568 568 569 569 noreclaim_flag = memalloc_noreclaim_save(); 570 - do { 571 - sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC; 572 - sock->sk->sk_use_task_frag = false; 573 - msg.msg_flags = msg_flags | MSG_NOSIGNAL; 574 570 575 - if (send) 576 - result = sock_sendmsg(sock, &msg); 577 - else 578 - result = sock_recvmsg(sock, &msg, msg.msg_flags); 571 + scoped_with_kernel_creds() { 572 + do { 573 + sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC; 574 + sock->sk->sk_use_task_frag = false; 575 + msg.msg_flags = msg_flags | MSG_NOSIGNAL; 579 576 580 - if (result <= 0) { 581 - if (result == 0) 582 - result = -EPIPE; /* short read */ 583 - break; 584 - } 585 - if (sent) 586 - *sent += result; 587 - } while (msg_data_left(&msg)); 577 + if (send) 578 + result = sock_sendmsg(sock, &msg); 579 + else 580 + result = sock_recvmsg(sock, &msg, msg.msg_flags); 581 + 582 + if (result <= 0) { 583 + if (result == 0) 584 + result = -EPIPE; /* short read */ 585 + break; 586 + } 587 + if (sent) 588 + *sent += result; 589 + } while (msg_data_left(&msg)); 590 + } 588 591 589 592 memalloc_noreclaim_restore(noreclaim_flag); 590 - 591 - revert_creds(old_cred); 592 593 593 594 return result; 594 595 } ··· 2680 2683 return -ENOMEM; 2681 2684 } 2682 2685 2683 - nbd_cred = prepare_kernel_cred(&init_task); 2684 - if (!nbd_cred) { 2685 - destroy_workqueue(nbd_del_wq); 2686 - unregister_blkdev(NBD_MAJOR, "nbd"); 2687 - return -ENOMEM; 2688 - } 2689 - 2690 2686 if (genl_register_family(&nbd_genl_family)) { 2691 - put_cred(nbd_cred); 2692 2687 destroy_workqueue(nbd_del_wq); 2693 2688 unregister_blkdev(NBD_MAJOR, "nbd"); 2694 2689 return -EINVAL; ··· 2735 2746 /* Also wait for nbd_dev_remove_work() completes */ 2736 2747 destroy_workqueue(nbd_del_wq); 2737 2748 2738 - put_cred(nbd_cred); 2739 2749 idr_destroy(&nbd_index_idr); 2740 2750 unregister_blkdev(NBD_MAJOR, "nbd"); 2741 2751 }
+2 -12
drivers/target/target_core_configfs.c
··· 3670 3670 { 3671 3671 struct configfs_subsystem *subsys = &target_core_fabrics; 3672 3672 struct t10_alua_lu_gp *lu_gp; 3673 - struct cred *kern_cred; 3674 - const struct cred *old_cred; 3675 3673 int ret; 3676 3674 3677 3675 pr_debug("TARGET_CORE[0]: Loading Generic Kernel Storage" ··· 3746 3748 if (ret < 0) 3747 3749 goto out; 3748 3750 3749 - /* We use the kernel credentials to access the target directory */ 3750 - kern_cred = prepare_kernel_cred(&init_task); 3751 - if (!kern_cred) { 3752 - ret = -ENOMEM; 3753 - goto out; 3754 - } 3755 - old_cred = override_creds(kern_cred); 3756 - target_init_dbroot(); 3757 - revert_creds(old_cred); 3758 - put_cred(kern_cred); 3751 + scoped_with_kernel_creds() 3752 + target_init_dbroot(); 3759 3753 3760 3754 return 0; 3761 3755
+8 -7
include/linux/cleanup.h
··· 290 290 class_##_name##_t var __cleanup(class_##_name##_destructor) = \ 291 291 class_##_name##_constructor 292 292 293 - #define scoped_class(_name, var, args) \ 294 - for (CLASS(_name, var)(args); \ 295 - __guard_ptr(_name)(&var) || !__is_cond_ptr(_name); \ 296 - ({ goto _label; })) \ 297 - if (0) { \ 298 - _label: \ 299 - break; \ 293 + #define __scoped_class(_name, var, _label, args...) \ 294 + for (CLASS(_name, var)(args); ; ({ goto _label; })) \ 295 + if (0) { \ 296 + _label: \ 297 + break; \ 300 298 } else 299 + 300 + #define scoped_class(_name, var, args...) \ 301 + __scoped_class(_name, var, __UNIQUE_ID(label), args) 301 302 302 303 /* 303 304 * DEFINE_GUARD(name, type, lock, unlock):
+15
include/linux/cred.h
··· 20 20 struct cred; 21 21 struct inode; 22 22 23 + extern struct task_struct init_task; 24 + 23 25 /* 24 26 * COW Supplementary groups list 25 27 */ ··· 158 156 extern int commit_creds(struct cred *); 159 157 extern void abort_creds(struct cred *); 160 158 extern struct cred *prepare_kernel_cred(struct task_struct *); 159 + static inline const struct cred *kernel_cred(void) 160 + { 161 + /* shut up sparse */ 162 + return rcu_dereference_raw(init_task.cred); 163 + } 161 164 extern int set_security_override(struct cred *, u32); 162 165 extern int set_security_override_from_ctx(struct cred *, const char *); 163 166 extern int set_create_files_as(struct cred *, struct inode *); ··· 186 179 { 187 180 return rcu_replace_pointer(current->cred, revert_cred, 1); 188 181 } 182 + 183 + DEFINE_CLASS(override_creds, 184 + const struct cred *, 185 + revert_creds(_T), 186 + override_creds(override_cred), const struct cred *override_cred) 187 + 188 + #define scoped_with_kernel_creds() \ 189 + scoped_class(override_creds, __UNIQUE_ID(cred), kernel_cred()) 189 190 190 191 /** 191 192 * get_cred_many - Get references on a set of credentials
-1
include/linux/init_task.h
··· 25 25 extern struct files_struct init_files; 26 26 extern struct fs_struct init_fs; 27 27 extern struct nsproxy init_nsproxy; 28 - extern struct cred init_cred; 29 28 30 29 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 31 30 #define INIT_PREV_CPUTIME(x) .prev_cputime = { \
+27
init/init_task.c
··· 62 62 }; 63 63 #endif 64 64 65 + /* init to 2 - one for init_task, one to ensure it is never freed */ 66 + static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) }; 67 + 68 + /* 69 + * The initial credentials for the initial task 70 + */ 71 + static struct cred init_cred = { 72 + .usage = ATOMIC_INIT(4), 73 + .uid = GLOBAL_ROOT_UID, 74 + .gid = GLOBAL_ROOT_GID, 75 + .suid = GLOBAL_ROOT_UID, 76 + .sgid = GLOBAL_ROOT_GID, 77 + .euid = GLOBAL_ROOT_UID, 78 + .egid = GLOBAL_ROOT_GID, 79 + .fsuid = GLOBAL_ROOT_UID, 80 + .fsgid = GLOBAL_ROOT_GID, 81 + .securebits = SECUREBITS_DEFAULT, 82 + .cap_inheritable = CAP_EMPTY_SET, 83 + .cap_permitted = CAP_FULL_SET, 84 + .cap_effective = CAP_FULL_SET, 85 + .cap_bset = CAP_FULL_SET, 86 + .user = INIT_USER, 87 + .user_ns = &init_user_ns, 88 + .group_info = &init_groups, 89 + .ucounts = &init_ucounts, 90 + }; 91 + 65 92 /* 66 93 * Set up the first task table, touch at your own risk!. Base=0, 67 94 * limit=0x1fffff (=2MB)
-27
kernel/cred.c
··· 35 35 36 36 static struct kmem_cache *cred_jar; 37 37 38 - /* init to 2 - one for init_task, one to ensure it is never freed */ 39 - static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) }; 40 - 41 - /* 42 - * The initial credentials for the initial task 43 - */ 44 - struct cred init_cred = { 45 - .usage = ATOMIC_INIT(4), 46 - .uid = GLOBAL_ROOT_UID, 47 - .gid = GLOBAL_ROOT_GID, 48 - .suid = GLOBAL_ROOT_UID, 49 - .sgid = GLOBAL_ROOT_GID, 50 - .euid = GLOBAL_ROOT_UID, 51 - .egid = GLOBAL_ROOT_GID, 52 - .fsuid = GLOBAL_ROOT_UID, 53 - .fsgid = GLOBAL_ROOT_GID, 54 - .securebits = SECUREBITS_DEFAULT, 55 - .cap_inheritable = CAP_EMPTY_SET, 56 - .cap_permitted = CAP_FULL_SET, 57 - .cap_effective = CAP_FULL_SET, 58 - .cap_bset = CAP_FULL_SET, 59 - .user = INIT_USER, 60 - .user_ns = &init_user_ns, 61 - .group_info = &init_groups, 62 - .ucounts = &init_ucounts, 63 - }; 64 - 65 38 /* 66 39 * The RCU callback to actually dispose of a set of credentials 67 40 */
+4 -13
net/unix/af_unix.c
··· 1210 1210 unix_mkname_bsd(sunaddr, addr_len); 1211 1211 1212 1212 if (flags & SOCK_COREDUMP) { 1213 - const struct cred *cred; 1214 - struct cred *kcred; 1215 1213 struct path root; 1216 - 1217 - kcred = prepare_kernel_cred(&init_task); 1218 - if (!kcred) { 1219 - err = -ENOMEM; 1220 - goto fail; 1221 - } 1222 1214 1223 1215 task_lock(&init_task); 1224 1216 get_fs_root(init_task.fs, &root); 1225 1217 task_unlock(&init_task); 1226 1218 1227 - cred = override_creds(kcred); 1228 - err = vfs_path_lookup(root.dentry, root.mnt, sunaddr->sun_path, 1229 - LOOKUP_BENEATH | LOOKUP_NO_SYMLINKS | 1230 - LOOKUP_NO_MAGICLINKS, &path); 1231 - put_cred(revert_creds(cred)); 1219 + scoped_with_kernel_creds() 1220 + err = vfs_path_lookup(root.dentry, root.mnt, sunaddr->sun_path, 1221 + LOOKUP_BENEATH | LOOKUP_NO_SYMLINKS | 1222 + LOOKUP_NO_MAGICLINKS, &path); 1232 1223 path_put(&root); 1233 1224 if (err) 1234 1225 goto fail;
+1 -1
security/keys/process_keys.c
··· 51 51 if (!reg_keyring) { 52 52 reg_keyring = keyring_alloc(".user_reg", 53 53 user_ns->owner, INVALID_GID, 54 - &init_cred, 54 + kernel_cred(), 55 55 KEY_POS_WRITE | KEY_POS_SEARCH | 56 56 KEY_USR_VIEW | KEY_USR_READ, 57 57 0,