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

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" <ebiederm@xmission.com>
Cc: David Howells <dhowells@redhat.com>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Steve French <sfrench@samba.org>
Cc: Ronnie Sahlberg <lsahlber@redhat.com>
Cc: Shyam Prasad N <sprasad@microsoft.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: Anna Schumaker <anna@kernel.org>
Cc: Chuck Lever <chuck.lever@oracle.com>
Cc: Jeff Layton <jlayton@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: "Michal Koutný" <mkoutny@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Cc: linux-nfs@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: Luis Chamberlain <mcgrof@kernel.org>
Reviewed-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Acked-by: Russ Weight <russell.h.weight@intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Link: https://lore.kernel.org/r/20221026232943.never.775-kees@kernel.org

+16 -17
+1 -1
drivers/base/firmware_loader/main.c
··· 821 821 * called by a driver when serving an unrelated request from userland, we use 822 822 * the kernel credentials to read the file. 823 823 */ 824 - kern_cred = prepare_kernel_cred(NULL); 824 + kern_cred = prepare_kernel_cred(&init_task); 825 825 if (!kern_cred) { 826 826 ret = -ENOMEM; 827 827 goto out;
+1 -1
fs/cifs/cifs_spnego.c
··· 189 189 * spnego upcalls. 190 190 */ 191 191 192 - cred = prepare_kernel_cred(NULL); 192 + cred = prepare_kernel_cred(&init_task); 193 193 if (!cred) 194 194 return -ENOMEM; 195 195
+1 -1
fs/cifs/cifsacl.c
··· 465 465 * this is used to prevent malicious redirections from being installed 466 466 * with add_key(). 467 467 */ 468 - cred = prepare_kernel_cred(NULL); 468 + cred = prepare_kernel_cred(&init_task); 469 469 if (!cred) 470 470 return -ENOMEM; 471 471
+1 -1
fs/ksmbd/smb_common.c
··· 623 623 if (share->force_gid != KSMBD_SHARE_INVALID_GID) 624 624 gid = share->force_gid; 625 625 626 - cred = prepare_kernel_cred(NULL); 626 + cred = prepare_kernel_cred(&init_task); 627 627 if (!cred) 628 628 return -ENOMEM; 629 629
+2 -2
fs/nfs/flexfilelayout/flexfilelayout.c
··· 493 493 gid = make_kgid(&init_user_ns, id); 494 494 495 495 if (gfp_flags & __GFP_FS) 496 - kcred = prepare_kernel_cred(NULL); 496 + kcred = prepare_kernel_cred(&init_task); 497 497 else { 498 498 unsigned int nofs_flags = memalloc_nofs_save(); 499 - kcred = prepare_kernel_cred(NULL); 499 + kcred = prepare_kernel_cred(&init_task); 500 500 memalloc_nofs_restore(nofs_flags); 501 501 } 502 502 rc = -ENOMEM;
+1 -1
fs/nfs/nfs4idmap.c
··· 203 203 printk(KERN_NOTICE "NFS: Registering the %s key type\n", 204 204 key_type_id_resolver.name); 205 205 206 - cred = prepare_kernel_cred(NULL); 206 + cred = prepare_kernel_cred(&init_task); 207 207 if (!cred) 208 208 return -ENOMEM; 209 209
+1 -1
fs/nfsd/nfs4callback.c
··· 870 870 } else { 871 871 struct cred *kcred; 872 872 873 - kcred = prepare_kernel_cred(NULL); 873 + kcred = prepare_kernel_cred(&init_task); 874 874 if (!kcred) 875 875 return NULL; 876 876
+7 -8
kernel/cred.c
··· 701 701 * override a task's own credentials so that work can be done on behalf of that 702 702 * task that requires a different subjective context. 703 703 * 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. 707 707 * 708 708 * The caller may change these controls afterwards if desired. 709 709 * ··· 714 714 const struct cred *old; 715 715 struct cred *new; 716 716 717 + if (WARN_ON_ONCE(!daemon)) 718 + return NULL; 719 + 717 720 new = kmem_cache_alloc(cred_jar, GFP_KERNEL); 718 721 if (!new) 719 722 return NULL; 720 723 721 724 kdebug("prepare_kernel_cred() alloc %p", new); 722 725 723 - if (daemon) 724 - old = get_task_cred(daemon); 725 - else 726 - old = get_cred(&init_cred); 727 - 726 + old = get_task_cred(daemon); 728 727 validate_creds(old); 729 728 730 729 *new = *old;
+1 -1
net/dns_resolver/dns_key.c
··· 337 337 * this is used to prevent malicious redirections from being installed 338 338 * with add_key(). 339 339 */ 340 - cred = prepare_kernel_cred(NULL); 340 + cred = prepare_kernel_cred(&init_task); 341 341 if (!cred) 342 342 return -ENOMEM; 343 343