Skip to content

Commit e0876bd

Browse files
committed
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>
2 parents dcb6fa3 + 1ad5b41 commit e0876bd

10 files changed

Lines changed: 103 additions & 128 deletions

File tree

drivers/base/firmware_loader/main.c

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -829,8 +829,6 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
829829
size_t offset, u32 opt_flags)
830830
{
831831
struct firmware *fw = NULL;
832-
struct cred *kern_cred = NULL;
833-
const struct cred *old_cred;
834832
bool nondirect = false;
835833
int ret;
836834

@@ -871,45 +869,38 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
871869
* called by a driver when serving an unrelated request from userland, we use
872870
* the kernel credentials to read the file.
873871
*/
874-
kern_cred = prepare_kernel_cred(&init_task);
875-
if (!kern_cred) {
876-
ret = -ENOMEM;
877-
goto out;
878-
}
879-
old_cred = override_creds(kern_cred);
872+
scoped_with_kernel_creds() {
873+
ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
880874

881-
ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
882-
883-
/* Only full reads can support decompression, platform, and sysfs. */
884-
if (!(opt_flags & FW_OPT_PARTIAL))
885-
nondirect = true;
875+
/* Only full reads can support decompression, platform, and sysfs. */
876+
if (!(opt_flags & FW_OPT_PARTIAL))
877+
nondirect = true;
886878

887879
#ifdef CONFIG_FW_LOADER_COMPRESS_ZSTD
888-
if (ret == -ENOENT && nondirect)
889-
ret = fw_get_filesystem_firmware(device, fw->priv, ".zst",
890-
fw_decompress_zstd);
880+
if (ret == -ENOENT && nondirect)
881+
ret = fw_get_filesystem_firmware(device, fw->priv, ".zst",
882+
fw_decompress_zstd);
891883
#endif
892884
#ifdef CONFIG_FW_LOADER_COMPRESS_XZ
893-
if (ret == -ENOENT && nondirect)
894-
ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
895-
fw_decompress_xz);
885+
if (ret == -ENOENT && nondirect)
886+
ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
887+
fw_decompress_xz);
896888
#endif
897-
if (ret == -ENOENT && nondirect)
898-
ret = firmware_fallback_platform(fw->priv);
889+
if (ret == -ENOENT && nondirect)
890+
ret = firmware_fallback_platform(fw->priv);
899891

900-
if (ret) {
901-
if (!(opt_flags & FW_OPT_NO_WARN))
902-
dev_warn(device,
903-
"Direct firmware load for %s failed with error %d\n",
904-
name, ret);
905-
if (nondirect)
906-
ret = firmware_fallback_sysfs(fw, name, device,
907-
opt_flags, ret);
908-
} else
909-
ret = assign_fw(fw, device);
910-
911-
revert_creds(old_cred);
912-
put_cred(kern_cred);
892+
if (ret) {
893+
if (!(opt_flags & FW_OPT_NO_WARN))
894+
dev_warn(device,
895+
"Direct firmware load for %s failed with error %d\n",
896+
name, ret);
897+
if (nondirect)
898+
ret = firmware_fallback_sysfs(fw, name, device,
899+
opt_flags, ret);
900+
} else {
901+
ret = assign_fw(fw, device);
902+
}
903+
}
913904

914905
out:
915906
if (ret < 0) {

drivers/block/nbd.c

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
static DEFINE_IDR(nbd_index_idr);
5353
static DEFINE_MUTEX(nbd_index_mutex);
5454
static struct workqueue_struct *nbd_del_wq;
55-
static struct cred *nbd_cred;
5655
static int nbd_total_devices = 0;
5756

5857
struct nbd_sock {
@@ -555,7 +554,6 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
555554
int result;
556555
struct msghdr msg = {} ;
557556
unsigned int noreclaim_flag;
558-
const struct cred *old_cred;
559557

560558
if (unlikely(!sock)) {
561559
dev_err_ratelimited(disk_to_dev(nbd->disk),
@@ -564,33 +562,32 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send,
564562
return -EINVAL;
565563
}
566564

567-
old_cred = override_creds(nbd_cred);
568-
569565
msg.msg_iter = *iter;
570566

571567
noreclaim_flag = memalloc_noreclaim_save();
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;
576-
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));
590568

591-
memalloc_noreclaim_restore(noreclaim_flag);
569+
scoped_with_kernel_creds() {
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;
592574

593-
revert_creds(old_cred);
575+
if (send)
576+
result = sock_sendmsg(sock, &msg);
577+
else
578+
result = sock_recvmsg(sock, &msg, msg.msg_flags);
579+
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));
588+
}
589+
590+
memalloc_noreclaim_restore(noreclaim_flag);
594591

595592
return result;
596593
}
@@ -2683,15 +2680,7 @@ static int __init nbd_init(void)
26832680
return -ENOMEM;
26842681
}
26852682

2686-
nbd_cred = prepare_kernel_cred(&init_task);
2687-
if (!nbd_cred) {
2688-
destroy_workqueue(nbd_del_wq);
2689-
unregister_blkdev(NBD_MAJOR, "nbd");
2690-
return -ENOMEM;
2691-
}
2692-
26932683
if (genl_register_family(&nbd_genl_family)) {
2694-
put_cred(nbd_cred);
26952684
destroy_workqueue(nbd_del_wq);
26962685
unregister_blkdev(NBD_MAJOR, "nbd");
26972686
return -EINVAL;
@@ -2746,7 +2735,6 @@ static void __exit nbd_cleanup(void)
27462735
/* Also wait for nbd_dev_remove_work() completes */
27472736
destroy_workqueue(nbd_del_wq);
27482737

2749-
put_cred(nbd_cred);
27502738
idr_destroy(&nbd_index_idr);
27512739
unregister_blkdev(NBD_MAJOR, "nbd");
27522740
}

drivers/target/target_core_configfs.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,8 +3670,6 @@ static int __init target_core_init_configfs(void)
36703670
{
36713671
struct configfs_subsystem *subsys = &target_core_fabrics;
36723672
struct t10_alua_lu_gp *lu_gp;
3673-
struct cred *kern_cred;
3674-
const struct cred *old_cred;
36753673
int ret;
36763674

36773675
pr_debug("TARGET_CORE[0]: Loading Generic Kernel Storage"
@@ -3748,16 +3746,8 @@ static int __init target_core_init_configfs(void)
37483746
if (ret < 0)
37493747
goto out;
37503748

3751-
/* We use the kernel credentials to access the target directory */
3752-
kern_cred = prepare_kernel_cred(&init_task);
3753-
if (!kern_cred) {
3754-
ret = -ENOMEM;
3755-
goto out;
3756-
}
3757-
old_cred = override_creds(kern_cred);
3758-
target_init_dbroot();
3759-
revert_creds(old_cred);
3760-
put_cred(kern_cred);
3749+
scoped_with_kernel_creds()
3750+
target_init_dbroot();
37613751

37623752
return 0;
37633753

include/linux/cleanup.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,16 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
290290
class_##_name##_t var __cleanup(class_##_name##_destructor) = \
291291
class_##_name##_constructor
292292

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; \
300298
} else
301299

300+
#define scoped_class(_name, var, args...) \
301+
__scoped_class(_name, var, __UNIQUE_ID(label), args)
302+
302303
/*
303304
* DEFINE_GUARD(name, type, lock, unlock):
304305
* trivial wrapper around DEFINE_CLASS() above specifically

include/linux/cred.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
struct cred;
2121
struct inode;
2222

23+
extern struct task_struct init_task;
24+
2325
/*
2426
* COW Supplementary groups list
2527
*/
@@ -156,6 +158,11 @@ extern struct cred *prepare_exec_creds(void);
156158
extern int commit_creds(struct cred *);
157159
extern void abort_creds(struct cred *);
158160
extern struct cred *prepare_kernel_cred(struct task_struct *);
161+
static inline const struct cred *kernel_cred(void)
162+
{
163+
/* shut up sparse */
164+
return rcu_dereference_raw(init_task.cred);
165+
}
159166
extern int set_security_override(struct cred *, u32);
160167
extern int set_security_override_from_ctx(struct cred *, const char *);
161168
extern int set_create_files_as(struct cred *, struct inode *);
@@ -180,6 +187,14 @@ static inline const struct cred *revert_creds(const struct cred *revert_cred)
180187
return rcu_replace_pointer(current->cred, revert_cred, 1);
181188
}
182189

190+
DEFINE_CLASS(override_creds,
191+
const struct cred *,
192+
revert_creds(_T),
193+
override_creds(override_cred), const struct cred *override_cred)
194+
195+
#define scoped_with_kernel_creds() \
196+
scoped_class(override_creds, __UNIQUE_ID(cred), kernel_cred())
197+
183198
/**
184199
* get_cred_many - Get references on a set of credentials
185200
* @cred: The credentials to reference

include/linux/init_task.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
extern struct files_struct init_files;
2626
extern struct fs_struct init_fs;
2727
extern struct nsproxy init_nsproxy;
28-
extern struct cred init_cred;
2928

3029
#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
3130
#define INIT_PREV_CPUTIME(x) .prev_cputime = { \

init/init_task.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,33 @@ unsigned long init_shadow_call_stack[SCS_SIZE / sizeof(long)] = {
6262
};
6363
#endif
6464

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+
6592
/*
6693
* Set up the first task table, touch at your own risk!. Base=0,
6794
* limit=0x1fffff (=2MB)

kernel/cred.c

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,33 +35,6 @@ do { \
3535

3636
static struct kmem_cache *cred_jar;
3737

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-
6538
/*
6639
* The RCU callback to actually dispose of a set of credentials
6740
*/

net/unix/af_unix.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,25 +1210,16 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
12101210
unix_mkname_bsd(sunaddr, addr_len);
12111211

12121212
if (flags & SOCK_COREDUMP) {
1213-
const struct cred *cred;
1214-
struct cred *kcred;
12151213
struct path root;
12161214

1217-
kcred = prepare_kernel_cred(&init_task);
1218-
if (!kcred) {
1219-
err = -ENOMEM;
1220-
goto fail;
1221-
}
1222-
12231215
task_lock(&init_task);
12241216
get_fs_root(init_task.fs, &root);
12251217
task_unlock(&init_task);
12261218

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);
12321223
path_put(&root);
12331224
if (err)
12341225
goto fail;

security/keys/process_keys.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ static struct key *get_user_register(struct user_namespace *user_ns)
5151
if (!reg_keyring) {
5252
reg_keyring = keyring_alloc(".user_reg",
5353
user_ns->owner, INVALID_GID,
54-
&init_cred,
54+
kernel_cred(),
5555
KEY_POS_WRITE | KEY_POS_SEARCH |
5656
KEY_USR_VIEW | KEY_USR_READ,
5757
0,

0 commit comments

Comments
 (0)