Skip to content

Commit 5a17f04

Browse files
committed
cred: Do not default to init_cred in prepare_kernel_cred()
A common exploit pattern for ROP attacks is to abuse prepare_kernel_cred() in order to construct escalated privileges[1]. Instead of providing a short-hand argument (NULL) to the "daemon" argument to indicate using init_cred as the base cred, require that "daemon" is always set to an actual task. Replace all existing callers that were passing NULL with &init_task. Future attacks will need to have sufficiently powerful read/write primitives to have found an appropriately privileged task and written it to the ROP stack as an argument to succeed, which is similarly difficult to the prior effort needed to escalate privileges before struct cred existed: locate the current cred and overwrite the uid member. This has the added benefit of meaning that prepare_kernel_cred() can no longer exceed the privileges of the init task, which may have changed from the original init_cred (e.g. dropping capabilities from the bounding set). [1] https://google.com/search?q=commit_creds(prepare_kernel_cred(0)) Cc: "Eric W. Biederman" <[email protected]> Cc: David Howells <[email protected]> Cc: "Rafael J. Wysocki" <[email protected]> Cc: Steve French <[email protected]> Cc: Ronnie Sahlberg <[email protected]> Cc: Shyam Prasad N <[email protected]> Cc: Tom Talpey <[email protected]> Cc: Namjae Jeon <[email protected]> Cc: Trond Myklebust <[email protected]> Cc: Anna Schumaker <[email protected]> Cc: Chuck Lever <[email protected]> Cc: Jeff Layton <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Eric Dumazet <[email protected]> Cc: Jakub Kicinski <[email protected]> Cc: Paolo Abeni <[email protected]> Cc: "Michal Koutný" <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Kees Cook <[email protected]> Acked-by: Luis Chamberlain <[email protected]> Reviewed-by: Sergey Senozhatsky <[email protected]> Acked-by: Russ Weight <[email protected]> Acked-by: Greg Kroah-Hartman <[email protected]> Acked-by: Paulo Alcantara (SUSE) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e9a40e1 commit 5a17f04

File tree

9 files changed

+16
-17
lines changed

9 files changed

+16
-17
lines changed

drivers/base/firmware_loader/main.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
821821
* called by a driver when serving an unrelated request from userland, we use
822822
* the kernel credentials to read the file.
823823
*/
824-
kern_cred = prepare_kernel_cred(NULL);
824+
kern_cred = prepare_kernel_cred(&init_task);
825825
if (!kern_cred) {
826826
ret = -ENOMEM;
827827
goto out;

fs/cifs/cifs_spnego.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ init_cifs_spnego(void)
189189
* spnego upcalls.
190190
*/
191191

192-
cred = prepare_kernel_cred(NULL);
192+
cred = prepare_kernel_cred(&init_task);
193193
if (!cred)
194194
return -ENOMEM;
195195

fs/cifs/cifsacl.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ init_cifs_idmap(void)
465465
* this is used to prevent malicious redirections from being installed
466466
* with add_key().
467467
*/
468-
cred = prepare_kernel_cred(NULL);
468+
cred = prepare_kernel_cred(&init_task);
469469
if (!cred)
470470
return -ENOMEM;
471471

fs/ksmbd/smb_common.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ int ksmbd_override_fsids(struct ksmbd_work *work)
623623
if (share->force_gid != KSMBD_SHARE_INVALID_GID)
624624
gid = share->force_gid;
625625

626-
cred = prepare_kernel_cred(NULL);
626+
cred = prepare_kernel_cred(&init_task);
627627
if (!cred)
628628
return -ENOMEM;
629629

fs/nfs/flexfilelayout/flexfilelayout.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
493493
gid = make_kgid(&init_user_ns, id);
494494

495495
if (gfp_flags & __GFP_FS)
496-
kcred = prepare_kernel_cred(NULL);
496+
kcred = prepare_kernel_cred(&init_task);
497497
else {
498498
unsigned int nofs_flags = memalloc_nofs_save();
499-
kcred = prepare_kernel_cred(NULL);
499+
kcred = prepare_kernel_cred(&init_task);
500500
memalloc_nofs_restore(nofs_flags);
501501
}
502502
rc = -ENOMEM;

fs/nfs/nfs4idmap.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ int nfs_idmap_init(void)
203203
printk(KERN_NOTICE "NFS: Registering the %s key type\n",
204204
key_type_id_resolver.name);
205205

206-
cred = prepare_kernel_cred(NULL);
206+
cred = prepare_kernel_cred(&init_task);
207207
if (!cred)
208208
return -ENOMEM;
209209

fs/nfsd/nfs4callback.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ static const struct cred *get_backchannel_cred(struct nfs4_client *clp, struct r
870870
} else {
871871
struct cred *kcred;
872872

873-
kcred = prepare_kernel_cred(NULL);
873+
kcred = prepare_kernel_cred(&init_task);
874874
if (!kcred)
875875
return NULL;
876876

kernel/cred.c

+7-8
Original file line numberDiff line numberDiff line change
@@ -701,9 +701,9 @@ void __init cred_init(void)
701701
* override a task's own credentials so that work can be done on behalf of that
702702
* task that requires a different subjective context.
703703
*
704-
* @daemon is used to provide a base for the security record, but can be NULL.
705-
* If @daemon is supplied, then the security data will be derived from that;
706-
* otherwise they'll be set to 0 and no groups, full capabilities and no keys.
704+
* @daemon is used to provide a base cred, with the security data derived from
705+
* that; if this is "&init_task", they'll be set to 0, no groups, full
706+
* capabilities, and no keys.
707707
*
708708
* The caller may change these controls afterwards if desired.
709709
*
@@ -714,17 +714,16 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
714714
const struct cred *old;
715715
struct cred *new;
716716

717+
if (WARN_ON_ONCE(!daemon))
718+
return NULL;
719+
717720
new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
718721
if (!new)
719722
return NULL;
720723

721724
kdebug("prepare_kernel_cred() alloc %p", new);
722725

723-
if (daemon)
724-
old = get_task_cred(daemon);
725-
else
726-
old = get_cred(&init_cred);
727-
726+
old = get_task_cred(daemon);
728727
validate_creds(old);
729728

730729
*new = *old;

net/dns_resolver/dns_key.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ static int __init init_dns_resolver(void)
337337
* this is used to prevent malicious redirections from being installed
338338
* with add_key().
339339
*/
340-
cred = prepare_kernel_cred(NULL);
340+
cred = prepare_kernel_cred(&init_task);
341341
if (!cred)
342342
return -ENOMEM;
343343

0 commit comments

Comments
 (0)