diff options
Diffstat (limited to 'security')
148 files changed, 2228 insertions, 1408 deletions
diff --git a/security/Kconfig b/security/Kconfig index aeac3676dd4d..466cc1f8ffed 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Security configuration # diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening index 0a1d4ca314f4..c6cb2d9b2905 100644 --- a/security/Kconfig.hardening +++ b/security/Kconfig.hardening @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only menu "Kernel hardening options" config GCC_PLUGIN_STRUCTLEAK diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index 3de21f46c82a..d8b1a360a636 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_APPARMOR bool "AppArmor support" depends on SECURITY && NET diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 9ab5613fe07c..66d0b4245ef6 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/ctype.h> diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 5a8b9cded4f2..5a98661a8b46 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/audit.h> diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 752f73980e30..deccea8654ad 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/capability.h> diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c index baba63bc66b1..b498ed302461 100644 --- a/security/apparmor/crypto.c +++ b/security/apparmor/crypto.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright 2013 Canonical Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * Fns to provide a checksum of policy that has been loaded this can be * compared to userspace policy compiles to check loaded policy is what * it should be. diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index ca2dccf5b445..9e0492795267 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 2002-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/errno.h> diff --git a/security/apparmor/file.c b/security/apparmor/file.c index d0afed9ebd0e..4c1b05eb130c 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/tty.h> diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 73d63b58d875..6b7e6e13176e 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __APPARMOR_H diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index bd689114bf93..6e14f6cecdb9 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_APPARMORFS_H diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index ee559bc2acb8..18519a4eb67e 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_AUDIT_H diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h index 1b3663b6ab12..d420e2d10b31 100644 --- a/security/apparmor/include/capability.h +++ b/security/apparmor/include/capability.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2013 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_CAPABILITY_H diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h index b9504a05fddc..0b9ae4804ef7 100644 --- a/security/apparmor/include/cred.h +++ b/security/apparmor/include/cred.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_CONTEXT_H diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h index c1469f8db174..636a04e20d91 100644 --- a/security/apparmor/include/crypto.h +++ b/security/apparmor/include/crypto.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor policy loading interface function definitions. * * Copyright 2013 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __APPARMOR_CRYPTO_H diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h index ac9862ff7cdf..21b875fe2d37 100644 --- a/security/apparmor/include/domain.h +++ b/security/apparmor/include/domain.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/binfmts.h> diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 8be09208cf7c..a852be89a7dc 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_FILE_H diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h index 5ffc218d1e74..9cafd80f7731 100644 --- a/security/apparmor/include/ipc.h +++ b/security/apparmor/include/ipc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_IPC_H diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 7ce5fe73ae7f..47942c4ba7ca 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor label definitions * * Copyright 2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_LABEL_H diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index bbe9b384d71d..7d27db740bc2 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor lib definitions * * 2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_LIB_H diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index 958d2b52a7b7..6b0af638a18d 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2012 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_MATCH_H diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h index 25d6067fa6ef..a710683b2496 100644 --- a/security/apparmor/include/mount.h +++ b/security/apparmor/include/mount.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor file mediation function definitions. * * Copyright 2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_MOUNT_H diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h index 7334ac966d01..2431c011800d 100644 --- a/security/apparmor/include/net.h +++ b/security/apparmor/include/net.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_NET_H diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h index b6380c5f0097..35a8295e8f3a 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_PATH_H diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index b94ec114d1a4..13f20c598448 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor basic permission sets definitions. * * Copyright 2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_PERM_H diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 8e6707c837be..b5b4b8190e65 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_POLICY_H @@ -217,7 +213,16 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) return labels_profile(aa_get_newest_label(&p->label)); } -#define PROFILE_MEDIATES(P, T) ((P)->policy.start[(unsigned char) (T)]) +static inline unsigned int PROFILE_MEDIATES(struct aa_profile *profile, + unsigned char class) +{ + if (class <= AA_CLASS_LAST) + return profile->policy.start[class]; + else + return aa_dfa_match_len(profile->policy.dfa, + profile->policy.start[0], &class, 1); +} + static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, u16 AF) { unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 9605f18624e2..3df6f804922d 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_NAMESPACE_H diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index 8db4ab759e80..46aefae918f5 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __POLICY_INTERFACE_H diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h index c8fd99c9357d..31689437e0e1 100644 --- a/security/apparmor/include/procattr.h +++ b/security/apparmor/include/procattr.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_PROCATTR_H diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h index 76f1586c9adb..961d85d328ea 100644 --- a/security/apparmor/include/resource.h +++ b/security/apparmor/include/resource.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_RESOURCE_H diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index fa2062711b63..48ff1ddecad5 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor security identifier (secid) definitions * * Copyright 2009-2018 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_SECID_H diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index 311e652324e3..f13d12373b25 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AppArmor security module * * This file contains AppArmor task related definitions and mediation * * Copyright 2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #ifndef __AA_TASK_H diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index aacd1e95cb59..4ecedffbdd33 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/gfp.h> diff --git a/security/apparmor/label.c b/security/apparmor/label.c index ba11bdf9043a..59f1cc2557a7 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * * This file contains AppArmor label definitions * * Copyright 2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/audit.h> @@ -80,7 +76,7 @@ void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new) AA_BUG(!orig); AA_BUG(!new); - lockdep_assert_held_exclusive(&labels_set(orig)->lock); + lockdep_assert_held_write(&labels_set(orig)->lock); tmp = rcu_dereference_protected(orig->proxy->label, &labels_ns(orig)->lock); @@ -570,7 +566,7 @@ static bool __label_remove(struct aa_label *label, struct aa_label *new) AA_BUG(!ls); AA_BUG(!label); - lockdep_assert_held_exclusive(&ls->lock); + lockdep_assert_held_write(&ls->lock); if (new) __aa_proxy_redirect(label, new); @@ -607,7 +603,7 @@ static bool __label_replace(struct aa_label *old, struct aa_label *new) AA_BUG(!ls); AA_BUG(!old); AA_BUG(!new); - lockdep_assert_held_exclusive(&ls->lock); + lockdep_assert_held_write(&ls->lock); AA_BUG(new->flags & FLAG_IN_TREE); if (!label_is_stale(old)) @@ -644,7 +640,7 @@ static struct aa_label *__label_insert(struct aa_labelset *ls, AA_BUG(!ls); AA_BUG(!label); AA_BUG(labels_set(label) != ls); - lockdep_assert_held_exclusive(&ls->lock); + lockdep_assert_held_write(&ls->lock); AA_BUG(label->flags & FLAG_IN_TREE); /* Figure out where to put new node */ diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 76491e7f4177..30c246a9d440 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/ctype.h> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 87500bde5a92..ec3a928af829 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/lsm_hooks.h> diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 55f2ee505a01..6ccd3734a841 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2012 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/errno.h> diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 8c3787399356..17081c8dbefa 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/fs.h> diff --git a/security/apparmor/net.c b/security/apparmor/net.c index c07fde444792..d8afc39f663a 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include "include/apparmor.h" diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 9d5de1d05be4..c6da542de27b 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/magic.h> diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index df9c5890a878..ade333074c8e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -6,12 +7,6 @@ * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * * AppArmor policy is based around profiles, which contain the rules a * task is confined by. Every task in the system has a profile attached * to it determined either by matching "unconfined" tasks against the diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 1a7cec5d9cac..d7ef540027a5 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -6,11 +7,6 @@ * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2017 Canonical Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * AppArmor policy namespaces, allow for different sets of policies * to be loaded for tasks within the namespace. */ diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index f6c2bcb2ab14..8cfc9493eefc 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -7,11 +8,6 @@ * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * AppArmor uses a serialized binary format for loading policy. To find * policy format documentation see Documentation/admin-guide/LSM/apparmor.rst * All policy is validated before it is used. @@ -223,16 +219,21 @@ static void *kvmemdup(const void *src, size_t len) static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk) { size_t size = 0; + void *pos = e->pos; if (!inbounds(e, sizeof(u16))) - return 0; + goto fail; size = le16_to_cpu(get_unaligned((__le16 *) e->pos)); e->pos += sizeof(__le16); if (!inbounds(e, size)) - return 0; + goto fail; *chunk = e->pos; e->pos += size; return size; + +fail: + e->pos = pos; + return 0; } /* unpack control byte */ @@ -276,7 +277,7 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name) char *tag = NULL; size_t size = unpack_u16_chunk(e, &tag); /* if a name is specified it must match. otherwise skip tag */ - if (name && (!size || strcmp(name, tag))) + if (name && (!size || tag[size-1] != '\0' || strcmp(name, tag))) goto fail; } else if (name) { /* if a name is specified and there is no name tag fail */ @@ -294,62 +295,84 @@ fail: static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name) { + void *pos = e->pos; + if (unpack_nameX(e, AA_U8, name)) { if (!inbounds(e, sizeof(u8))) - return 0; + goto fail; if (data) *data = get_unaligned((u8 *)e->pos); e->pos += sizeof(u8); return 1; } + +fail: + e->pos = pos; return 0; } static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) { + void *pos = e->pos; + if (unpack_nameX(e, AA_U32, name)) { if (!inbounds(e, sizeof(u32))) - return 0; + goto fail; if (data) *data = le32_to_cpu(get_unaligned((__le32 *) e->pos)); e->pos += sizeof(u32); return 1; } + +fail: + e->pos = pos; return 0; } static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name) { + void *pos = e->pos; + if (unpack_nameX(e, AA_U64, name)) { if (!inbounds(e, sizeof(u64))) - return 0; + goto fail; if (data) *data = le64_to_cpu(get_unaligned((__le64 *) e->pos)); e->pos += sizeof(u64); return 1; } + +fail: + e->pos = pos; return 0; } static size_t unpack_array(struct aa_ext *e, const char *name) { + void *pos = e->pos; + if (unpack_nameX(e, AA_ARRAY, name)) { int size; if (!inbounds(e, sizeof(u16))) - return 0; + goto fail; size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos)); e->pos += sizeof(u16); return size; } + +fail: + e->pos = pos; return 0; } static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name) { + void *pos = e->pos; + if (unpack_nameX(e, AA_BLOB, name)) { u32 size; if (!inbounds(e, sizeof(u32))) - return 0; + goto fail; size = le32_to_cpu(get_unaligned((__le32 *) e->pos)); e->pos += sizeof(u32); if (inbounds(e, (size_t) size)) { @@ -358,6 +381,9 @@ static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name) return size; } } + +fail: + e->pos = pos; return 0; } @@ -374,9 +400,10 @@ static int unpack_str(struct aa_ext *e, const char **string, const char *name) if (src_str[size - 1] != 0) goto fail; *string = src_str; + + return size; } } - return size; fail: e->pos = pos; diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index 80c34ed373c3..c929bf4a3df1 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include "include/apparmor.h" diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 552ed09cb47e..1ae4874251a9 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright (C) 1998-2008 Novell/SUSE * Copyright 2009-2010 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. */ #include <linux/audit.h> diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index 05373d9a3d6a..ce545f99259e 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,12 +6,6 @@ * * Copyright 2009-2017 Canonical Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * * AppArmor allocates a unique secid for every label used. If a label * is replaced it receives the secid of the label it is replacing. */ diff --git a/security/apparmor/task.c b/security/apparmor/task.c index 4551110f0496..d17130ee6795 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * @@ -5,11 +6,6 @@ * * Copyright 2017 Canonical Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * TODO * If a task uses change_hat it currently does not return to the old * cred or task context but instead creates a new one. Ideally the task diff --git a/security/commoncap.c b/security/commoncap.c index c477fb673701..c0b9664ee49e 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1,10 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Common capabilities, needed by capability.o. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #include <linux/capability.h> diff --git a/security/device_cgroup.c b/security/device_cgroup.c index dc28914fa72e..c07196502577 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -509,7 +509,7 @@ static inline int may_allow_all(struct dev_cgroup *parent) * This is one of the three key functions for hierarchy implementation. * This function is responsible for re-evaluating all the cgroup's active * exceptions due to a parent's exception change. - * Refer to Documentation/cgroup-v1/devices.txt for more details. + * Refer to Documentation/cgroup-v1/devices.rst for more details. */ static void revalidate_active_exceptions(struct dev_cgroup *devcg) { diff --git a/security/inode.c b/security/inode.c index aacc4dabba7d..fcff7f08bb1c 100644 --- a/security/inode.c +++ b/security/inode.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * inode.c - securityfs * * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * * Based on fs/debugfs/inode.c which had the following copyright notice: * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2004 IBM Inc. diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig index 3ba1168b1756..c352532b8f84 100644 --- a/security/integrity/Kconfig +++ b/security/integrity/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # config INTEGRITY bool "Integrity subsystem" diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index e19c2eb72c51..f9f3c8ffe786 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 Intel Corporation * * Author: * Dmitry Kasatkin <dmitry.kasatkin@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -51,7 +47,8 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, if (!keyring[id]) { keyring[id] = - request_key(&key_type_keyring, keyring_name[id], NULL); + request_key(&key_type_keyring, keyring_name[id], + NULL, NULL); if (IS_ERR(keyring[id])) { int err = PTR_ERR(keyring[id]); pr_err("no %s keyring: %d\n", keyring_name[id], err); @@ -73,14 +70,15 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, return -EOPNOTSUPP; } -static int __integrity_init_keyring(const unsigned int id, key_perm_t perm, - struct key_restriction *restriction) +static int __init __integrity_init_keyring(const unsigned int id, + struct key_acl *acl, + struct key_restriction *restriction) { const struct cred *cred = current_cred(); int err = 0; keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), - KGIDT_INIT(0), cred, perm, + KGIDT_INIT(0), cred, acl, KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL); if (IS_ERR(keyring[id])) { err = PTR_ERR(keyring[id]); @@ -98,10 +96,7 @@ static int __integrity_init_keyring(const unsigned int id, key_perm_t perm, int __init integrity_init_keyring(const unsigned int id) { struct key_restriction *restriction; - key_perm_t perm; - - perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW - | KEY_USR_READ | KEY_USR_SEARCH; + struct key_acl *acl = &internal_keyring_acl; if (id == INTEGRITY_KEYRING_PLATFORM) { restriction = NULL; @@ -116,14 +111,14 @@ int __init integrity_init_keyring(const unsigned int id) return -ENOMEM; restriction->check = restrict_link_to_ima; - perm |= KEY_USR_WRITE; + acl = &internal_writable_keyring_acl; out: - return __integrity_init_keyring(id, perm, restriction); + return __integrity_init_keyring(id, acl, restriction); } -int __init integrity_add_key(const unsigned int id, const void *data, - off_t size, key_perm_t perm) +static int __init integrity_add_key(const unsigned int id, const void *data, + off_t size, struct key_acl *acl) { key_ref_t key; int rc = 0; @@ -132,7 +127,7 @@ int __init integrity_add_key(const unsigned int id, const void *data, return -EINVAL; key = key_create_or_update(make_key_ref(keyring[id], 1), "asymmetric", - NULL, data, size, perm, + NULL, data, size, acl ?: &internal_key_acl, KEY_ALLOC_NOT_IN_QUOTA); if (IS_ERR(key)) { rc = PTR_ERR(key); @@ -152,7 +147,6 @@ int __init integrity_load_x509(const unsigned int id, const char *path) void *data; loff_t size; int rc; - key_perm_t perm; rc = kernel_read_file_from_path(path, &data, &size, 0, READING_X509_CERTIFICATE); @@ -161,21 +155,19 @@ int __init integrity_load_x509(const unsigned int id, const char *path) return rc; } - perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ; - pr_info("Loading X.509 certificate: %s\n", path); - rc = integrity_add_key(id, (const void *)data, size, perm); + rc = integrity_add_key(id, data, size, NULL); vfree(data); return rc; } int __init integrity_load_cert(const unsigned int id, const char *source, - const void *data, size_t len, key_perm_t perm) + const void *data, size_t len, struct key_acl *acl) { if (!data) return -EINVAL; pr_info("Loading X.509 certificate: %s\n", source); - return integrity_add_key(id, data, len, perm); + return integrity_add_key(id, data, len, acl); } diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 99080871eb9f..a29df775fdd8 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Intel Corporation * * Author: * Dmitry Kasatkin <dmitry.kasatkin@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -39,7 +35,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) key_ref_t kref; kref = keyring_search(make_key_ref(key, 1), - &key_type_asymmetric, name); + &key_type_asymmetric, name, true); if (!IS_ERR(kref)) { pr_err("Key '%s' is in ima_blacklist_keyring\n", name); return ERR_PTR(-EKEYREJECTED); @@ -51,13 +47,13 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) key_ref_t kref; kref = keyring_search(make_key_ref(keyring, 1), - &key_type_asymmetric, name); + &key_type_asymmetric, name, true); if (IS_ERR(kref)) key = ERR_CAST(kref); else key = key_ref_to_ptr(kref); } else { - key = request_key(&key_type_asymmetric, name, NULL); + key = request_key(&key_type_asymmetric, name, NULL, NULL); } if (IS_ERR(key)) { diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index 60221852b26a..a6e19d23e700 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config EVM bool "EVM support" select KEYS diff --git a/security/integrity/evm/Makefile b/security/integrity/evm/Makefile index 7393c415a066..a56f5613be79 100644 --- a/security/integrity/evm/Makefile +++ b/security/integrity/evm/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for building the Extended Verification Module(EVM) # diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index c3f437f5db10..f2fef2b5ed51 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2005-2010 IBM Corporation * @@ -5,12 +6,7 @@ * Mimi Zohar <zohar@us.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * File: evm.h - * */ #ifndef __INTEGRITY_EVM_H diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index e11564eb645b..466eebd3b4aa 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005-2010 IBM Corporation * @@ -5,10 +6,6 @@ * Mimi Zohar <zohar@us.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * File: evm_crypto.c * Using root's kernel master key (kmk), calculate the HMAC */ @@ -89,6 +86,9 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) tfm = &hmac_tfm; algo = evm_hmac; } else { + if (hash_algo >= HASH_ALGO__LAST) + return ERR_PTR(-EINVAL); + tfm = &evm_tfm[hash_algo]; algo = hash_algo_name[hash_algo]; } @@ -356,7 +356,7 @@ int evm_init_key(void) struct encrypted_key_payload *ekp; int rc; - evm_key = request_key(&key_type_encrypted, EVMKEY, NULL); + evm_key = request_key(&key_type_encrypted, EVMKEY, NULL, NULL); if (IS_ERR(evm_key)) return -ENOENT; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index b6d9f14bc234..f9a81b187fae 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005-2010 IBM Corporation * @@ -5,10 +6,6 @@ * Mimi Zohar <zohar@us.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * File: evm_main.c * implements evm_inode_setxattr, evm_inode_post_setxattr, * evm_inode_removexattr, and evm_verifyxattr @@ -169,7 +166,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, /* check value type */ switch (xattr_data->type) { case EVM_XATTR_HMAC: - if (xattr_len != sizeof(struct evm_ima_xattr_data)) { + if (xattr_len != sizeof(struct evm_xattr)) { evm_status = INTEGRITY_FAIL; goto out; } @@ -179,7 +176,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, xattr_value_len, &digest); if (rc) break; - rc = crypto_memneq(xattr_data->digest, digest.digest, + rc = crypto_memneq(xattr_data->data, digest.digest, SHA1_DIGEST_SIZE); if (rc) rc = -EINVAL; @@ -523,7 +520,7 @@ int evm_inode_init_security(struct inode *inode, const struct xattr *lsm_xattr, struct xattr *evm_xattr) { - struct evm_ima_xattr_data *xattr_data; + struct evm_xattr *xattr_data; int rc; if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name)) @@ -533,7 +530,7 @@ int evm_inode_init_security(struct inode *inode, if (!xattr_data) return -ENOMEM; - xattr_data->type = EVM_XATTR_HMAC; + xattr_data->data.type = EVM_XATTR_HMAC; rc = evm_init_hmac(inode, lsm_xattr, xattr_data->digest); if (rc < 0) goto out; diff --git a/security/integrity/evm/evm_posix_acl.c b/security/integrity/evm/evm_posix_acl.c index 7faf98c20373..37275800c072 100644 --- a/security/integrity/evm/evm_posix_acl.c +++ b/security/integrity/evm/evm_posix_acl.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 IBM Corporation * * Author: * Mimi Zohar <zohar@us.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. */ #include <linux/xattr.h> diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 3f7cbb238923..c11c1f7b3ddd 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 IBM Corporation * * Authors: * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * File: evm_secfs.c * - Used to signal when key is on keyring * - Get the key and enable EVM diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 423876fca8b4..e12c4900510f 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 IBM Corporation * * Authors: * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: integrity_iint.c * - implements the integrity hooks: integrity_inode_alloc, * integrity_inode_free diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index a18f8c6d13b5..2ced99dde694 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # IBM Integrity Measurement Architecture # config IMA @@ -159,7 +160,8 @@ config IMA_APPRAISE config IMA_ARCH_POLICY bool "Enable loading an IMA architecture specific policy" - depends on KEXEC_VERIFY_SIG || IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS + depends on (KEXEC_VERIFY_SIG && IMA) || IMA_APPRAISE \ + && INTEGRITY_ASYMMETRIC_KEYS default n help This option enables loading an IMA architecture specific policy diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index d213e835c498..011b91c79351 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2005,2006,2007,2008 IBM Corporation * @@ -5,11 +6,6 @@ * Reiner Sailer <sailer@watson.ibm.com> * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima.h * internal Integrity Measurement Architecture (IMA) definitions */ @@ -65,6 +61,8 @@ struct ima_event_data { struct evm_ima_xattr_data *xattr_value; int xattr_len; const char *violation; + const void *buf; + int buf_len; }; /* IMA template field data definition */ @@ -146,7 +144,11 @@ void ima_add_violation(struct file *file, const unsigned char *filename, int ima_init_crypto(void); void ima_putc(struct seq_file *m, void *data, int datalen); void ima_print_digest(struct seq_file *m, u8 *digest, u32 size); +int template_desc_init_fields(const char *template_fmt, + const struct ima_template_field ***fields, + int *num_fields); struct ima_template_desc *ima_template_desc_current(void); +struct ima_template_desc *lookup_template_desc(const char *name); int ima_restore_measurement_entry(struct ima_template_entry *entry); int ima_restore_measurement_list(loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); @@ -154,6 +156,8 @@ unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); void ima_init_template_list(void); int __init ima_init_digests(void); +int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, + void *lsm_data); /* * used to protect h_table and sha_table @@ -184,6 +188,7 @@ static inline unsigned long ima_hash_key(u8 *digest) hook(KEXEC_KERNEL_CHECK) \ hook(KEXEC_INITRAMFS_CHECK) \ hook(POLICY_CHECK) \ + hook(KEXEC_CMDLINE) \ hook(MAX_CHECK) #define __ima_hook_enumify(ENUM) ENUM, @@ -193,7 +198,8 @@ enum ima_hooks { /* LIM API function definitions */ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, - int mask, enum ima_hooks func, int *pcr); + int mask, enum ima_hooks func, int *pcr, + struct ima_template_desc **template_desc); int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func); int ima_collect_measurement(struct integrity_iint_cache *iint, struct file *file, void *buf, loff_t size, @@ -201,11 +207,13 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, - int xattr_len, int pcr); + int xattr_len, int pcr, + struct ima_template_desc *template_desc); void ima_audit_measurement(struct integrity_iint_cache *iint, const unsigned char *filename); int ima_alloc_init_template(struct ima_event_data *event_data, - struct ima_template_entry **entry); + struct ima_template_entry **entry, + struct ima_template_desc *template_desc); int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, int pcr); @@ -214,7 +222,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); /* IMA policy related functions */ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, - enum ima_hooks func, int mask, int flags, int *pcr); + enum ima_hooks func, int mask, int flags, int *pcr, + struct ima_template_desc **template_desc); void ima_init_policy(void); void ima_update_policy(void); void ima_update_policy_flag(void); diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c7505fb122d4..f614e22bf39f 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 IBM Corporation * * Author: Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_api.c * Implements must_appraise_or_measure, collect_measurement, * appraise_measurement, store_measurement and store_template. @@ -38,11 +34,17 @@ void ima_free_template_entry(struct ima_template_entry *entry) * ima_alloc_init_template - create and initialize a new template entry */ int ima_alloc_init_template(struct ima_event_data *event_data, - struct ima_template_entry **entry) + struct ima_template_entry **entry, + struct ima_template_desc *desc) { - struct ima_template_desc *template_desc = ima_template_desc_current(); + struct ima_template_desc *template_desc; int i, result = 0; + if (desc) + template_desc = desc; + else + template_desc = ima_template_desc_current(); + *entry = kzalloc(sizeof(**entry) + template_desc->num_fields * sizeof(struct ima_field_data), GFP_NOFS); if (!*entry) @@ -133,15 +135,17 @@ void ima_add_violation(struct file *file, const unsigned char *filename, { struct ima_template_entry *entry; struct inode *inode = file_inode(file); - struct ima_event_data event_data = {iint, file, filename, NULL, 0, - cause}; + struct ima_event_data event_data = { .iint = iint, + .file = file, + .filename = filename, + .violation = cause }; int violation = 1; int result; /* can overflow, only indicator */ atomic_long_inc(&ima_htable.violations); - result = ima_alloc_init_template(&event_data, &entry); + result = ima_alloc_init_template(&event_data, &entry, NULL); if (result < 0) { result = -ENOMEM; goto err_out; @@ -164,11 +168,13 @@ err_out: * MAY_APPEND) * @func: caller identifier * @pcr: pointer filled in if matched measure policy sets pcr= + * @template_desc: pointer filled in if matched measure policy sets template= * * The policy is defined in terms of keypairs: * subj=, obj=, type=, func=, mask=, fsmagic= * subj,obj, and type: are LSM specific. * func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK + * | KEXEC_CMDLINE * mask: contains the permission mask * fsmagic: hex value * @@ -176,13 +182,15 @@ err_out: * */ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, - int mask, enum ima_hooks func, int *pcr) + int mask, enum ima_hooks func, int *pcr, + struct ima_template_desc **template_desc) { int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH; flags &= ima_policy_flag; - return ima_match_policy(inode, cred, secid, func, mask, flags, pcr); + return ima_match_policy(inode, cred, secid, func, mask, flags, pcr, + template_desc); } /* @@ -277,21 +285,25 @@ out: void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, - int xattr_len, int pcr) + int xattr_len, int pcr, + struct ima_template_desc *template_desc) { static const char op[] = "add_template_measure"; static const char audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); struct ima_template_entry *entry; - struct ima_event_data event_data = {iint, file, filename, xattr_value, - xattr_len, NULL}; + struct ima_event_data event_data = { .iint = iint, + .file = file, + .filename = filename, + .xattr_value = xattr_value, + .xattr_len = xattr_len }; int violation = 0; if (iint->measured_pcrs & (0x1 << pcr)) return; - result = ima_alloc_init_template(&event_data, &entry); + result = ima_alloc_init_template(&event_data, &entry, template_desc); if (result < 0) { integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, op, audit_cause, result, 0); diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 5fb7127bbe68..89b83194d1dc 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011 IBM Corporation * * Author: * Mimi Zohar <zohar@us.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. */ #include <linux/init.h> #include <linux/file.h> @@ -57,7 +54,7 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) security_task_getsecid(current, &secid); return ima_match_policy(inode, current_cred(), secid, func, mask, - IMA_APPRAISE | IMA_HASH, NULL); + IMA_APPRAISE | IMA_HASH, NULL, NULL); } static int ima_fix_xattr(struct dentry *dentry, @@ -168,7 +165,8 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, return sig->hash_algo; break; case IMA_XATTR_DIGEST_NG: - ret = xattr_value->digest[0]; + /* first byte contains algorithm id */ + ret = xattr_value->data[0]; if (ret < HASH_ALGO__LAST) return ret; break; @@ -176,7 +174,7 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, /* this is for backward compatibility */ if (xattr_len == 21) { unsigned int zero = 0; - if (!memcmp(&xattr_value->digest[16], &zero, 4)) + if (!memcmp(&xattr_value->data[16], &zero, 4)) return HASH_ALGO_MD5; else return HASH_ALGO_SHA1; @@ -275,7 +273,7 @@ int ima_appraise_measurement(enum ima_hooks func, /* xattr length may be longer. md5 hash in previous version occupied 20 bytes in xattr, instead of 16 */ - rc = memcmp(&xattr_value->digest[hash_start], + rc = memcmp(&xattr_value->data[hash_start], iint->ima_hash->digest, iint->ima_hash->length); else diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index a32878e10ebc..d4c7b8e1b083 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005,2006,2007,2008 IBM Corporation * @@ -5,10 +6,6 @@ * Mimi Zohar <zohar@us.ibm.com> * Kylene Hall <kjhall@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * File: ima_crypto.c * Calculates md5/sha1 file hash, template hash, boot-aggreate hash */ diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 0af792833f42..2000e8df0301 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005,2006,2007,2008 IBM Corporation * @@ -6,11 +7,6 @@ * Reiner Sailer <sailer@us.ibm.com> * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_fs.c * implemenents security file system for reporting * current measurement list and IMA statistics diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 6c9295449751..5d55ade5f3b9 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005,2006,2007,2008 IBM Corporation * @@ -6,11 +7,6 @@ * Leendert van Doorn <leendert@watson.ibm.com> * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_init.c * initialization and cleanup functions */ @@ -49,8 +45,8 @@ static int __init ima_add_boot_aggregate(void) const char *audit_cause = "ENOMEM"; struct ima_template_entry *entry; struct integrity_iint_cache tmp_iint, *iint = &tmp_iint; - struct ima_event_data event_data = {iint, NULL, boot_aggregate_name, - NULL, 0, NULL}; + struct ima_event_data event_data = { .iint = iint, + .filename = boot_aggregate_name }; int result = -ENOMEM; int violation = 0; struct { @@ -72,7 +68,7 @@ static int __init ima_add_boot_aggregate(void) } } - result = ima_alloc_init_template(&event_data, &entry); + result = ima_alloc_init_template(&event_data, &entry, NULL); if (result < 0) { audit_cause = "alloc_entry"; goto err_out; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index d6f32807b347..9e94eca48b89 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 IBM Corporation * * Authors: * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com> * Mimi Zohar <zohar@linux.vnet.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 357edd140c09..584019728660 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Integrity Measurement Architecture * @@ -9,11 +10,6 @@ * Kylene Hall <kylene@us.ibm.com> * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_main.c * implements the IMA hooks: ima_bprm_check, ima_file_mmap, * and ima_file_check. @@ -43,6 +39,10 @@ int ima_appraise; int ima_hash_algo = HASH_ALGO_SHA1; static int hash_setup_done; +static struct notifier_block ima_lsm_policy_notifier = { + .notifier_call = ima_lsm_policy_change, +}; + static int __init hash_setup(char *str) { struct ima_template_desc *template_desc = ima_template_desc_current(); @@ -72,6 +72,27 @@ out: } __setup("ima_hash=", hash_setup); +/* Prevent mmap'ing a file execute that is already mmap'ed write */ +static int mmap_violation_check(enum ima_hooks func, struct file *file, + char **pathbuf, const char **pathname, + char *filename) +{ + struct inode *inode; + int rc = 0; + + if ((func == MMAP_CHECK) && mapping_writably_mapped(file->f_mapping)) { + rc = -ETXTBSY; + inode = file_inode(file); + + if (!*pathbuf) /* ima_rdwr_violation possibly pre-fetched */ + *pathname = ima_d_path(&file->f_path, pathbuf, + filename); + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, *pathname, + "mmap_file", "mmapped_writers", rc, 0); + } + return rc; +} + /* * ima_rdwr_violation_check * @@ -174,7 +195,7 @@ static int process_measurement(struct file *file, const struct cred *cred, { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint = NULL; - struct ima_template_desc *template_desc; + struct ima_template_desc *template_desc = NULL; char *pathbuf = NULL; char filename[NAME_MAX]; const char *pathname = NULL; @@ -192,7 +213,8 @@ static int process_measurement(struct file *file, const struct cred *cred, * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action = ima_get_action(inode, cred, secid, mask, func, &pcr); + action = ima_get_action(inode, cred, secid, mask, func, &pcr, + &template_desc); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) && (ima_policy_flag & IMA_MEASURE)); if (!action && !violation_check) @@ -270,12 +292,15 @@ static int process_measurement(struct file *file, const struct cred *cred, /* Nothing to do, just return existing appraised status */ if (!action) { - if (must_appraise) - rc = ima_get_cache_status(iint, func); + if (must_appraise) { + rc = mmap_violation_check(func, file, &pathbuf, + &pathname, filename); + if (!rc) + rc = ima_get_cache_status(iint, func); + } goto out_locked; } - template_desc = ima_template_desc_current(); if ((action & IMA_APPRAISE_SUBMASK) || strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) /* read 'security.ima' */ @@ -292,12 +317,16 @@ static int process_measurement(struct file *file, const struct cred *cred, if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, - xattr_value, xattr_len, pcr); + xattr_value, xattr_len, pcr, + template_desc); if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { inode_lock(inode); rc = ima_appraise_measurement(func, iint, file, pathname, xattr_value, xattr_len); inode_unlock(inode); + if (!rc) + rc = mmap_violation_check(func, file, &pathbuf, + &pathname, filename); } if (action & IMA_AUDIT) ima_audit_measurement(iint, pathname); @@ -576,6 +605,80 @@ int ima_load_data(enum kernel_load_data_id id) return 0; } +/* + * process_buffer_measurement - Measure the buffer to ima log. + * @buf: pointer to the buffer that needs to be added to the log. + * @size: size of buffer(in bytes). + * @eventname: event name to be used for the buffer entry. + * @cred: a pointer to a credentials structure for user validation. + * @secid: the secid of the task to be validated. + * + * Based on policy, the buffer is measured into the ima log. + */ +static void process_buffer_measurement(const void *buf, int size, + const char *eventname, + const struct cred *cred, u32 secid) +{ + int ret = 0; + struct ima_template_entry *entry = NULL; + struct integrity_iint_cache iint = {}; + struct ima_event_data event_data = {.iint = &iint, + .filename = eventname, + .buf = buf, + .buf_len = size}; + struct ima_template_desc *template_desc = NULL; + struct { + struct ima_digest_data hdr; + char digest[IMA_MAX_DIGEST_SIZE]; + } hash = {}; + int violation = 0; + int pcr = CONFIG_IMA_MEASURE_PCR_IDX; + int action = 0; + + action = ima_get_action(NULL, cred, secid, 0, KEXEC_CMDLINE, &pcr, + &template_desc); + if (!(action & IMA_MEASURE)) + return; + + iint.ima_hash = &hash.hdr; + iint.ima_hash->algo = ima_hash_algo; + iint.ima_hash->length = hash_digest_size[ima_hash_algo]; + + ret = ima_calc_buffer_hash(buf, size, iint.ima_hash); + if (ret < 0) + goto out; + + ret = ima_alloc_init_template(&event_data, &entry, template_desc); + if (ret < 0) + goto out; + + ret = ima_store_template(entry, violation, NULL, buf, pcr); + + if (ret < 0) + ima_free_template_entry(entry); + +out: + return; +} + +/** + * ima_kexec_cmdline - measure kexec cmdline boot args + * @buf: pointer to buffer + * @size: size of buffer + * + * Buffers can only be measured, not appraised. + */ +void ima_kexec_cmdline(const void *buf, int size) +{ + u32 secid; + + if (buf && size != 0) { + security_task_getsecid(current, &secid); + process_buffer_measurement(buf, size, "kexec-cmdline", + current_cred(), secid); + } +} + static int __init init_ima(void) { int error; @@ -593,6 +696,10 @@ static int __init init_ima(void) error = ima_init(); } + error = register_blocking_lsm_notifier(&ima_lsm_policy_notifier); + if (error) + pr_warn("Couldn't register LSM notifier, error %d\n", error); + if (!error) ima_update_policy_flag(); diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c index 073ddc9bce5b..b52ae1476ec3 100644 --- a/security/integrity/ima/ima_mok.c +++ b/security/integrity/ima/ima_mok.c @@ -1,14 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Juniper Networks, Inc. * * Author: * Petko Manolov <petko.manolov@konsulko.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * */ #include <linux/export.h> @@ -21,6 +16,15 @@ #include <keys/system_keyring.h> +static struct key_acl integrity_blacklist_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH), + } +}; + struct key *ima_blacklist_keyring; /* @@ -40,9 +44,7 @@ __init int ima_mok_init(void) ima_blacklist_keyring = keyring_alloc(".ima_blacklist", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - (KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ | - KEY_USR_WRITE | KEY_USR_SEARCH, + &integrity_blacklist_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, restriction, NULL); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index e0cc323f948f..6df7f641ff66 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 IBM Corporation * Author: Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * ima_policy.c * - initialize default measure policy rules - * */ #include <linux/init.h> #include <linux/list.h> @@ -80,6 +76,7 @@ struct ima_rule_entry { int type; /* audit type */ } lsm[MAX_LSM_RULES]; char *fsname; + struct ima_template_desc *template; }; /* @@ -199,7 +196,7 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { }; /* An array of architecture specific rules */ -struct ima_rule_entry *arch_policy_entry __ro_after_init; +static struct ima_rule_entry *arch_policy_entry __ro_after_init; static LIST_HEAD(ima_default_rules); static LIST_HEAD(ima_policy_rules); @@ -249,31 +246,113 @@ static int __init default_appraise_policy_setup(char *str) } __setup("ima_appraise_tcb", default_appraise_policy_setup); +static void ima_lsm_free_rule(struct ima_rule_entry *entry) +{ + int i; + + for (i = 0; i < MAX_LSM_RULES; i++) { + kfree(entry->lsm[i].rule); + kfree(entry->lsm[i].args_p); + } + kfree(entry); +} + +static struct ima_rule_entry *ima_lsm_copy_rule(struct ima_rule_entry *entry) +{ + struct ima_rule_entry *nentry; + int i, result; + + nentry = kmalloc(sizeof(*nentry), GFP_KERNEL); + if (!nentry) + return NULL; + + /* + * Immutable elements are copied over as pointers and data; only + * lsm rules can change + */ + memcpy(nentry, entry, sizeof(*nentry)); + memset(nentry->lsm, 0, FIELD_SIZEOF(struct ima_rule_entry, lsm)); + + for (i = 0; i < MAX_LSM_RULES; i++) { + if (!entry->lsm[i].rule) + continue; + + nentry->lsm[i].type = entry->lsm[i].type; + nentry->lsm[i].args_p = kstrdup(entry->lsm[i].args_p, + GFP_KERNEL); + if (!nentry->lsm[i].args_p) + goto out_err; + + result = security_filter_rule_init(nentry->lsm[i].type, + Audit_equal, + nentry->lsm[i].args_p, + &nentry->lsm[i].rule); + if (result == -EINVAL) + pr_warn("ima: rule for LSM \'%d\' is undefined\n", + entry->lsm[i].type); + } + return nentry; + +out_err: + ima_lsm_free_rule(nentry); + return NULL; +} + +static int ima_lsm_update_rule(struct ima_rule_entry *entry) +{ + struct ima_rule_entry *nentry; + + nentry = ima_lsm_copy_rule(entry); + if (!nentry) + return -ENOMEM; + + list_replace_rcu(&entry->list, &nentry->list); + synchronize_rcu(); + ima_lsm_free_rule(entry); + + return 0; +} + /* * The LSM policy can be reloaded, leaving the IMA LSM based rules referring * to the old, stale LSM policy. Update the IMA LSM based rules to reflect - * the reloaded LSM policy. We assume the rules still exist; and BUG_ON() if - * they don't. + * the reloaded LSM policy. */ static void ima_lsm_update_rules(void) { - struct ima_rule_entry *entry; - int result; - int i; + struct ima_rule_entry *entry, *e; + int i, result, needs_update; - list_for_each_entry(entry, &ima_policy_rules, list) { + list_for_each_entry_safe(entry, e, &ima_policy_rules, list) { + needs_update = 0; for (i = 0; i < MAX_LSM_RULES; i++) { - if (!entry->lsm[i].rule) - continue; - result = security_filter_rule_init(entry->lsm[i].type, - Audit_equal, - entry->lsm[i].args_p, - &entry->lsm[i].rule); - BUG_ON(!entry->lsm[i].rule); + if (entry->lsm[i].rule) { + needs_update = 1; + break; + } + } + if (!needs_update) + continue; + + result = ima_lsm_update_rule(entry); + if (result) { + pr_err("ima: lsm rule update error %d\n", + result); + return; } } } +int ima_lsm_policy_change(struct notifier_block *nb, unsigned long event, + void *lsm_data) +{ + if (event != LSM_POLICY_CHANGE) + return NOTIFY_DONE; + + ima_lsm_update_rules(); + return NOTIFY_OK; +} + /** * ima_match_rules - determine whether an inode matches the measure rule. * @rule: a pointer to a rule @@ -291,6 +370,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, { int i; + if (func == KEXEC_CMDLINE) { + if ((rule->flags & IMA_FUNC) && (rule->func == func)) + return true; + return false; + } if ((rule->flags & IMA_FUNC) && (rule->func != func && func != POST_SETATTR)) return false; @@ -327,11 +411,10 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; u32 osid; - int retried = 0; if (!rule->lsm[i].rule) continue; -retry: + switch (i) { case LSM_OBJ_USER: case LSM_OBJ_ROLE: @@ -352,11 +435,6 @@ retry: default: break; } - if ((rc < 0) && (!retried)) { - retried = 1; - ima_lsm_update_rules(); - goto retry; - } if (!rc) return false; } @@ -397,6 +475,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * @func: IMA hook identifier * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * @pcr: set the pcr to extend + * @template_desc: the template that should be used for this rule * * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) * conditions. @@ -406,7 +485,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * than writes so ima_match_policy() is classical RCU candidate. */ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, - enum ima_hooks func, int mask, int flags, int *pcr) + enum ima_hooks func, int mask, int flags, int *pcr, + struct ima_template_desc **template_desc) { struct ima_rule_entry *entry; int action = 0, actmask = flags | (flags << 1); @@ -438,6 +518,11 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, if ((pcr) && (entry->flags & IMA_PCR)) *pcr = entry->pcr; + if (template_desc && entry->template) + *template_desc = entry->template; + else if (template_desc) + *template_desc = ima_template_desc_current(); + if (!actmask) break; } @@ -498,10 +583,11 @@ static void add_rules(struct ima_rule_entry *entries, int count, list_add_tail(&entry->list, &ima_policy_rules); } - if (entries[i].action == APPRAISE) + if (entries[i].action == APPRAISE) { temp_ima_appraise |= ima_appraise_flag(entries[i].func); - if (entries[i].func == POLICY_CHECK) - temp_ima_appraise |= IMA_APPRAISE_POLICY; + if (entries[i].func == POLICY_CHECK) + temp_ima_appraise |= IMA_APPRAISE_POLICY; + } } } @@ -675,7 +761,7 @@ enum { Opt_uid_gt, Opt_euid_gt, Opt_fowner_gt, Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_appraise_type, Opt_permit_directio, - Opt_pcr, Opt_err + Opt_pcr, Opt_template, Opt_err }; static const match_table_t policy_tokens = { @@ -709,6 +795,7 @@ static const match_table_t policy_tokens = { {Opt_appraise_type, "appraise_type=%s"}, {Opt_permit_directio, "permit_directio"}, {Opt_pcr, "pcr=%s"}, + {Opt_template, "template=%s"}, {Opt_err, NULL} }; @@ -762,6 +849,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) char *from; char *p; bool uid_token; + struct ima_template_desc *template_desc; int result = 0; ab = integrity_audit_log_start(audit_context(), GFP_KERNEL, @@ -869,6 +957,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->func = KEXEC_INITRAMFS_CHECK; else if (strcmp(args[0].from, "POLICY_CHECK") == 0) entry->func = POLICY_CHECK; + else if (strcmp(args[0].from, "KEXEC_CMDLINE") == 0) + entry->func = KEXEC_CMDLINE; else result = -EINVAL; if (!result) @@ -1058,6 +1148,28 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->flags |= IMA_PCR; break; + case Opt_template: + ima_log_string(ab, "template", args[0].from); + if (entry->action != MEASURE) { + result = -EINVAL; + break; + } + template_desc = lookup_template_desc(args[0].from); + if (!template_desc || entry->template) { + result = -EINVAL; + break; + } + + /* + * template_desc_init_fields() does nothing if + * the template is already initialised, so + * it's safe to do this unconditionally + */ + template_desc_init_fields(template_desc->fmt, + &(template_desc->fields), + &(template_desc->num_fields)); + entry->template = template_desc; + break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); result = -EINVAL; @@ -1146,10 +1258,10 @@ enum { }; static const char *const mask_tokens[] = { - "MAY_EXEC", - "MAY_WRITE", - "MAY_READ", - "MAY_APPEND" + "^MAY_EXEC", + "^MAY_WRITE", + "^MAY_READ", + "^MAY_APPEND" }; #define __ima_hook_stringify(str) (#str), @@ -1209,6 +1321,7 @@ int ima_policy_show(struct seq_file *m, void *v) struct ima_rule_entry *entry = v; int i; char tbuf[64] = {0,}; + int offset = 0; rcu_read_lock(); @@ -1232,15 +1345,17 @@ int ima_policy_show(struct seq_file *m, void *v) if (entry->flags & IMA_FUNC) policy_func_show(m, entry->func); - if (entry->flags & IMA_MASK) { + if ((entry->flags & IMA_MASK) || (entry->flags & IMA_INMASK)) { + if (entry->flags & IMA_MASK) + offset = 1; if (entry->mask & MAY_EXEC) - seq_printf(m, pt(Opt_mask), mt(mask_exec)); + seq_printf(m, pt(Opt_mask), mt(mask_exec) + offset); if (entry->mask & MAY_WRITE) - seq_printf(m, pt(Opt_mask), mt(mask_write)); + seq_printf(m, pt(Opt_mask), mt(mask_write) + offset); if (entry->mask & MAY_READ) - seq_printf(m, pt(Opt_mask), mt(mask_read)); + seq_printf(m, pt(Opt_mask), mt(mask_read) + offset); if (entry->mask & MAY_APPEND) - seq_printf(m, pt(Opt_mask), mt(mask_append)); + seq_printf(m, pt(Opt_mask), mt(mask_append) + offset); seq_puts(m, " "); } @@ -1330,6 +1445,8 @@ int ima_policy_show(struct seq_file *m, void *v) } } } + if (entry->template) + seq_printf(m, "template=%s ", entry->template->name); if (entry->flags & IMA_DIGSIG_REQUIRED) seq_puts(m, "appraise_type=imasig "); if (entry->flags & IMA_PERMIT_DIRECTIO) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 6b6d044e0440..1ce8b1701566 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2005,2006,2007,2008 IBM Corporation * @@ -6,11 +7,6 @@ * Reiner Sailer <sailer@watson.ibm.com> * Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_queue.c * Implements queues that store template measurements and * maintains aggregate over the stored measurements diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index b631b8bc7624..cb349d7b2601 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Politecnico di Torino, Italy * TORSEC group -- http://security.polito.it * * Author: Roberto Sassu <roberto.sassu@polito.it> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_template.c * Helpers to manage template descriptors. */ @@ -26,6 +22,7 @@ static struct ima_template_desc builtin_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, + {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"}, {.name = "", .fmt = ""}, /* placeholder for a custom format */ }; @@ -43,14 +40,18 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_string}, {.field_id = "sig", .field_init = ima_eventsig_init, .field_show = ima_show_template_sig}, + {.field_id = "buf", .field_init = ima_eventbuf_init, + .field_show = ima_show_template_buf}, }; -#define MAX_TEMPLATE_NAME_LEN 15 + +/* + * Used when restoring measurements carried over from a kexec. 'd' and 'n' don't + * need to be accounted for since they shouldn't be defined in the same template + * description as 'd-ng' and 'n-ng' respectively. + */ +#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf") static struct ima_template_desc *ima_template; -static struct ima_template_desc *lookup_template_desc(const char *name); -static int template_desc_init_fields(const char *template_fmt, - const struct ima_template_field ***fields, - int *num_fields); static int __init ima_template_setup(char *str) { @@ -108,7 +109,7 @@ static int __init ima_template_fmt_setup(char *str) } __setup("ima_template_fmt=", ima_template_fmt_setup); -static struct ima_template_desc *lookup_template_desc(const char *name) +struct ima_template_desc *lookup_template_desc(const char *name) { struct ima_template_desc *template_desc; int found = 0; @@ -153,9 +154,9 @@ static int template_fmt_size(const char *template_fmt) return j + 1; } -static int template_desc_init_fields(const char *template_fmt, - const struct ima_template_field ***fields, - int *num_fields) +int template_desc_init_fields(const char *template_fmt, + const struct ima_template_field ***fields, + int *num_fields) { const char *template_fmt_ptr; const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 513b457ae900..2fb9a10bc6b7 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Politecnico di Torino, Italy * TORSEC group -- http://security.polito.it * * Author: Roberto Sassu <roberto.sassu@polito.it> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_template_lib.c * Library of supported template fields. */ @@ -162,6 +158,12 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data); } +void ima_show_template_buf(struct seq_file *m, enum ima_show_type show, + struct ima_field_data *field_data) +{ + ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data); +} + /** * ima_parse_buf() - Parses lengths and data from an input buffer * @bufstartp: Buffer start address. @@ -389,3 +391,18 @@ int ima_eventsig_init(struct ima_event_data *event_data, return ima_write_template_field_data(xattr_value, event_data->xattr_len, DATA_FMT_HEX, field_data); } + +/* + * ima_eventbuf_init - include the buffer(kexec-cmldine) as part of the + * template data. + */ +int ima_eventbuf_init(struct ima_event_data *event_data, + struct ima_field_data *field_data) +{ + if ((!event_data->buf) || (event_data->buf_len == 0)) + return 0; + + return ima_write_template_field_data(event_data->buf, + event_data->buf_len, DATA_FMT_HEX, + field_data); +} diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index 6a3d8b831deb..652aa5de81ef 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Politecnico di Torino, Italy * TORSEC group -- http://security.polito.it * * Author: Roberto Sassu <roberto.sassu@polito.it> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * * File: ima_template_lib.h * Header for the library of supported template fields. */ @@ -29,6 +25,8 @@ void ima_show_template_string(struct seq_file *m, enum ima_show_type show, struct ima_field_data *field_data); void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, struct ima_field_data *field_data); +void ima_show_template_buf(struct seq_file *m, enum ima_show_type show, + struct ima_field_data *field_data); int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp, int maxfields, struct ima_field_data *fields, int *curfields, unsigned long *len_mask, int enforce_mask, char *bufname); @@ -42,4 +40,6 @@ int ima_eventname_ng_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +int ima_eventbuf_init(struct ima_event_data *event_data, + struct ima_field_data *field_data); #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 7de59f44cba3..875c6a7a5af1 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -1,14 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2009-2010 IBM Corporation * * Authors: * Mimi Zohar <zohar@us.ibm.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * */ #include <linux/types.h> @@ -17,6 +12,8 @@ #include <linux/key.h> #include <linux/audit.h> +struct key_acl; + /* iint action cache flags */ #define IMA_MEASURE 0x00000001 #define IMA_MEASURED 0x00000002 @@ -79,6 +76,12 @@ enum evm_ima_xattr_type { struct evm_ima_xattr_data { u8 type; + u8 data[]; +} __packed; + +/* Only used in the EVM HMAC code. */ +struct evm_xattr { + struct evm_ima_xattr_data data; u8 digest[SHA1_DIGEST_SIZE]; } __packed; @@ -154,7 +157,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, int __init integrity_init_keyring(const unsigned int id); int __init integrity_load_x509(const unsigned int id, const char *path); int __init integrity_load_cert(const unsigned int id, const char *source, - const void *data, size_t len, key_perm_t perm); + const void *data, size_t len, struct key_acl *acl); #else static inline int integrity_digsig_verify(const unsigned int id, @@ -172,7 +175,7 @@ static inline int integrity_init_keyring(const unsigned int id) static inline int __init integrity_load_cert(const unsigned int id, const char *source, const void *data, size_t len, - key_perm_t perm) + struct key_acl *acl) { return 0; } diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c index 82c98f7d217e..5109173839cc 100644 --- a/security/integrity/integrity_audit.c +++ b/security/integrity/integrity_audit.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2008 IBM Corporation * Author: Mimi Zohar <zohar@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * File: integrity_audit.c * Audit calls for the integrity subsystem */ diff --git a/security/integrity/platform_certs/platform_keyring.c b/security/integrity/platform_certs/platform_keyring.c index bcafd7387729..7646e35f2d91 100644 --- a/security/integrity/platform_certs/platform_keyring.c +++ b/security/integrity/platform_certs/platform_keyring.c @@ -14,6 +14,15 @@ #include <linux/slab.h> #include "../integrity.h" +static struct key_acl platform_key_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_READ), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; + /** * add_to_platform_keyring - Add to platform keyring without validation. * @source: Source of key @@ -26,13 +35,10 @@ void __init add_to_platform_keyring(const char *source, const void *data, size_t len) { - key_perm_t perm; int rc; - perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW; - rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source, data, len, - perm); + &platform_key_acl); if (rc) pr_info("Error adding keys to platform keyring %s\n", source); } diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 6462e6654ccf..dd313438fecf 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Key management configuration # @@ -24,6 +25,24 @@ config KEYS_COMPAT def_bool y depends on COMPAT && KEYS +config KEYS_REQUEST_CACHE + bool "Enable temporary caching of the last request_key() result" + depends on KEYS + help + This option causes the result of the last successful request_key() + call that didn't upcall to the kernel to be cached temporarily in the + task_struct. The cache is cleared by exit and just prior to the + resumption of userspace. + + This allows the key used for multiple step processes where each step + wants to request a key that is likely the same as the one requested + by the last step to save on the searching. + + An example of such a process is a pathwalk through a network + filesystem in which each method needs to request an authentication + key. Pathwalk will call multiple methods for each dentry traversed + (permission, d_revalidate, lookup, getxattr, getacl, ...). + config PERSISTENT_KEYRINGS bool "Enable register of persistent per-UID keyrings" depends on KEYS diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 2806e70d7f8f..001abe530a0d 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Large capacity key type * * Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #define pr_fmt(fmt) "big_key: "fmt diff --git a/security/keys/compat.c b/security/keys/compat.c index 9482df601dc3..b0e59546e7bd 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* 32-bit compatibility syscall for 64-bit systems * * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/syscalls.h> @@ -159,6 +155,14 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, return keyctl_pkey_verify(compat_ptr(arg2), compat_ptr(arg3), compat_ptr(arg4), compat_ptr(arg5)); + case KEYCTL_MOVE: + return keyctl_keyring_move(arg2, arg3, arg4, arg5); + case KEYCTL_GRANT_PERMISSION: + return keyctl_grant_permission(arg2, arg3, arg4, arg5); + + case KEYCTL_CAPABILITIES: + return keyctl_capabilities(compat_ptr(arg2), arg3); + default: return -EOPNOTSUPP; } diff --git a/security/keys/compat_dh.c b/security/keys/compat_dh.c index aa6b34cafe5f..19384e7e976c 100644 --- a/security/keys/compat_dh.c +++ b/security/keys/compat_dh.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* 32-bit compatibility syscall for 64-bit systems for DH operations * * Copyright (C) 2016 Stephan Mueller <smueller@chronox.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/uaccess.h> diff --git a/security/keys/dh.c b/security/keys/dh.c index 23f95dec771b..c4c629bb1c03 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -1,11 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Crypto operations using stored keys * * Copyright (c) 2016, Intel Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/slab.h> diff --git a/security/keys/encrypted-keys/ecryptfs_format.c b/security/keys/encrypted-keys/ecryptfs_format.c index efac03047919..a7339d4de811 100644 --- a/security/keys/encrypted-keys/ecryptfs_format.c +++ b/security/keys/encrypted-keys/ecryptfs_format.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ecryptfs_format.c: helper functions for the encrypted key type * @@ -9,10 +10,6 @@ * Michael A. Halcrow <mahalcro@us.ibm.com> * Tyler Hicks <tyhicks@ou.edu> * Roberto Sassu <roberto.sassu@polito.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. */ #include <linux/export.h> diff --git a/security/keys/encrypted-keys/ecryptfs_format.h b/security/keys/encrypted-keys/ecryptfs_format.h index 40294de238bb..939621d870e4 100644 --- a/security/keys/encrypted-keys/ecryptfs_format.h +++ b/security/keys/encrypted-keys/ecryptfs_format.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ecryptfs_format.h: helper functions for the encrypted key type * @@ -9,10 +10,6 @@ * Michael A. Halcrow <mahalcro@us.ibm.com> * Tyler Hicks <tyhicks@ou.edu> * Roberto Sassu <roberto.sassu@polito.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. */ #ifndef __KEYS_ECRYPTFS_H diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 1b1456b21a93..9df560e477c2 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 IBM Corporation * Copyright (C) 2010 Politecnico di Torino, Italy @@ -7,10 +8,6 @@ * Mimi Zohar <zohar@us.ibm.com> * Roberto Sassu <roberto.sassu@polito.it> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * See Documentation/security/keys/trusted-encrypted.rst */ @@ -307,7 +304,7 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k const struct user_key_payload *upayload; struct key *ukey; - ukey = request_key(&key_type_user, master_desc, NULL); + ukey = request_key(&key_type_user, master_desc, NULL, NULL); if (IS_ERR(ukey)) goto error; diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c index dc3d18cae642..d649f2f29475 100644 --- a/security/keys/encrypted-keys/masterkey_trusted.c +++ b/security/keys/encrypted-keys/masterkey_trusted.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 IBM Corporation * Copyright (C) 2010 Politecnico di Torino, Italy @@ -7,10 +8,6 @@ * Mimi Zohar <zohar@us.ibm.com> * Roberto Sassu <roberto.sassu@polito.it> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * See Documentation/security/keys/trusted-encrypted.rst */ @@ -33,7 +30,7 @@ struct key *request_trusted_key(const char *trusted_desc, struct trusted_key_payload *tpayload; struct key *tkey; - tkey = request_key(&key_type_trusted, trusted_desc, NULL); + tkey = request_key(&key_type_trusted, trusted_desc, NULL, NULL); if (IS_ERR(tkey)) goto error; diff --git a/security/keys/gc.c b/security/keys/gc.c index 634e96b380e8..48c3e124c272 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Key garbage collector * * Copyright (C) 2009-2011 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #include <linux/slab.h> @@ -154,7 +150,8 @@ static noinline void key_gc_unused_keys(struct list_head *keys) atomic_dec(&key->user->nikeys); key_user_put(key->user); - + key_put_tag(key->domain_tag); + key_put_acl(rcu_access_pointer(key->acl)); kfree(key->description); memzero_explicit(key, sizeof(*key)); @@ -224,7 +221,6 @@ continue_scanning: if (key->type == key_gc_dead_keytype) { gc_state |= KEY_GC_FOUND_DEAD_KEY; set_bit(KEY_FLAG_DEAD, &key->flags); - key->perm = 0; goto skip_dead_key; } else if (key->type == &key_type_keyring && key->restrict_link) { diff --git a/security/keys/internal.h b/security/keys/internal.h index 8f533c81aa8d..e0c5bb8b1685 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -1,12 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* Authentication token and access key management internal defs * * Copyright (C) 2003-5, 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #ifndef _INTERNAL_H @@ -88,11 +84,18 @@ extern struct rb_root key_serial_tree; extern spinlock_t key_serial_lock; extern struct mutex key_construction_mutex; extern wait_queue_head_t request_key_conswq; +extern struct key_acl default_key_acl; +extern struct key_acl joinable_keyring_acl; +extern void key_set_index_key(struct keyring_index_key *index_key); extern struct key_type *key_type_lookup(const char *type); extern void key_type_put(struct key_type *ktype); +extern int __key_link_lock(struct key *keyring, + const struct keyring_index_key *index_key); +extern int __key_move_lock(struct key *l_keyring, struct key *u_keyring, + const struct keyring_index_key *index_key); extern int __key_link_begin(struct key *keyring, const struct keyring_index_key *index_key, struct assoc_array_edit **_edit); @@ -123,6 +126,7 @@ struct keyring_search_context { #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ #define KEYRING_SEARCH_SKIP_EXPIRED 0x0020 /* Ignore expired keys (intention to replace) */ +#define KEYRING_SEARCH_RECURSE 0x0040 /* Search child keyrings also */ int (*iterator)(const void *object, void *iterator_data); @@ -135,24 +139,27 @@ struct keyring_search_context { extern bool key_default_cmp(const struct key *key, const struct key_match_data *match_data); -extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, +extern key_ref_t keyring_search_rcu(key_ref_t keyring_ref, struct keyring_search_context *ctx); -extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx); -extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx); +extern key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx); +extern key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx); extern struct key *find_keyring_by_name(const char *name, bool uid_keyring); -extern int install_user_keyrings(void); +extern int look_up_user_keyrings(struct key **, struct key **); +extern struct key *get_user_session_keyring_rcu(const struct cred *); extern int install_thread_keyring_to_cred(struct cred *); extern int install_process_keyring_to_cred(struct cred *); extern int install_session_keyring_to_cred(struct cred *, struct key *); extern struct key *request_key_and_link(struct key_type *type, const char *description, + struct key_tag *domain_tag, const void *callout_info, size_t callout_len, void *aux, + struct key_acl *acl, struct key *dest_keyring, unsigned long flags); @@ -176,7 +183,10 @@ extern void key_gc_keytype(struct key_type *ktype); extern int key_task_permission(const key_ref_t key_ref, const struct cred *cred, - key_perm_t perm); + u32 desired_perm); +extern unsigned int key_acl_to_perm(const struct key_acl *acl); +extern long key_set_acl(struct key *key, struct key_acl *acl); +extern void key_put_acl(struct key_acl *acl); /* * Check to see whether permission is granted to use a key in the desired way. @@ -203,7 +213,8 @@ static inline bool key_is_dead(const struct key *key, time64_t limit) return key->flags & ((1 << KEY_FLAG_DEAD) | (1 << KEY_FLAG_INVALIDATED)) || - (key->expiry > 0 && key->expiry <= limit); + (key->expiry > 0 && key->expiry <= limit) || + key->domain_tag->removed; } /* @@ -215,13 +226,14 @@ extern long keyctl_update_key(key_serial_t, const void __user *, size_t); extern long keyctl_revoke_key(key_serial_t); extern long keyctl_keyring_clear(key_serial_t); extern long keyctl_keyring_link(key_serial_t, key_serial_t); +extern long keyctl_keyring_move(key_serial_t, key_serial_t, key_serial_t, unsigned int); extern long keyctl_keyring_unlink(key_serial_t, key_serial_t); extern long keyctl_describe_key(key_serial_t, char __user *, size_t); extern long keyctl_keyring_search(key_serial_t, const char __user *, const char __user *, key_serial_t); extern long keyctl_read_key(key_serial_t, char __user *, size_t); extern long keyctl_chown_key(key_serial_t, uid_t, gid_t); -extern long keyctl_setperm_key(key_serial_t, key_perm_t); +extern long keyctl_setperm_key(key_serial_t, unsigned int); extern long keyctl_instantiate_key(key_serial_t, const void __user *, size_t, key_serial_t); extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); @@ -324,6 +336,13 @@ static inline long keyctl_pkey_e_d_s(int op, } #endif +extern long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen); + +extern long keyctl_grant_permission(key_serial_t keyid, + enum key_ace_subject_type type, + unsigned int subject, + unsigned int perm); + /* * Debugging key validation */ diff --git a/security/keys/key.c b/security/keys/key.c index 696f1c092c50..519211a996e7 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Basic authentication token and access key management * * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/export.h> @@ -199,7 +195,7 @@ serial_exists: * @uid: The owner of the new key. * @gid: The group ID for the new key's group permissions. * @cred: The credentials specifying UID namespace. - * @perm: The permissions mask of the new key. + * @acl: The ACL to attach to the new key. * @flags: Flags specifying quota properties. * @restrict_link: Optional link restriction for new keyrings. * @@ -227,7 +223,7 @@ serial_exists: */ struct key *key_alloc(struct key_type *type, const char *desc, kuid_t uid, kgid_t gid, const struct cred *cred, - key_perm_t perm, unsigned long flags, + struct key_acl *acl, unsigned long flags, struct key_restriction *restrict_link) { struct key_user *user = NULL; @@ -250,6 +246,9 @@ struct key *key_alloc(struct key_type *type, const char *desc, desclen = strlen(desc); quotalen = desclen + 1 + type->def_datalen; + if (!acl) + acl = &default_key_acl; + /* get hold of the key tracking for this user */ user = key_user_lookup(uid); if (!user) @@ -285,17 +284,19 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL); if (!key->index_key.description) goto no_memory_3; + key->index_key.type = type; + key_set_index_key(&key->index_key); refcount_set(&key->usage, 1); init_rwsem(&key->sem); lockdep_set_class(&key->sem, &type->lock_class); - key->index_key.type = type; key->user = user; key->quotalen = quotalen; key->datalen = type->def_datalen; key->uid = uid; key->gid = gid; - key->perm = perm; + refcount_inc(&acl->usage); + rcu_assign_pointer(key->acl, acl); key->restrict_link = restrict_link; key->last_used_at = ktime_get_real_seconds(); @@ -316,6 +317,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, goto security_error; /* publish the key by giving it a serial number */ + refcount_inc(&key->domain_tag->usage); atomic_inc(&user->nkeys); key_alloc_serial(key); @@ -459,7 +461,7 @@ static int __key_instantiate_and_link(struct key *key, /* disable the authorisation key */ if (authkey) - key_revoke(authkey); + key_invalidate(authkey); if (prep->expiry != TIME64_MAX) { key->expiry = prep->expiry; @@ -500,7 +502,7 @@ int key_instantiate_and_link(struct key *key, struct key *authkey) { struct key_preparsed_payload prep; - struct assoc_array_edit *edit; + struct assoc_array_edit *edit = NULL; int ret; memset(&prep, 0, sizeof(prep)); @@ -515,10 +517,14 @@ int key_instantiate_and_link(struct key *key, } if (keyring) { - ret = __key_link_begin(keyring, &key->index_key, &edit); + ret = __key_link_lock(keyring, &key->index_key); if (ret < 0) goto error; + ret = __key_link_begin(keyring, &key->index_key, &edit); + if (ret < 0) + goto error_link_end; + if (keyring->restrict_link && keyring->restrict_link->check) { struct key_restriction *keyres = keyring->restrict_link; @@ -570,7 +576,7 @@ int key_reject_and_link(struct key *key, struct key *keyring, struct key *authkey) { - struct assoc_array_edit *edit; + struct assoc_array_edit *edit = NULL; int ret, awaken, link_ret = 0; key_check(key); @@ -583,7 +589,12 @@ int key_reject_and_link(struct key *key, if (keyring->restrict_link) return -EPERM; - link_ret = __key_link_begin(keyring, &key->index_key, &edit); + link_ret = __key_link_lock(keyring, &key->index_key); + if (link_ret == 0) { + link_ret = __key_link_begin(keyring, &key->index_key, &edit); + if (link_ret < 0) + __key_link_end(keyring, &key->index_key, edit); + } } mutex_lock(&key_construction_mutex); @@ -607,7 +618,7 @@ int key_reject_and_link(struct key *key, /* disable the authorisation key */ if (authkey) - key_revoke(authkey); + key_invalidate(authkey); } mutex_unlock(&key_construction_mutex); @@ -780,7 +791,7 @@ error: * @description: The searchable description for the key. * @payload: The data to use to instantiate or update the key. * @plen: The length of @payload. - * @perm: The permissions mask for a new key. + * @acl: The ACL to attach if a key is created. * @flags: The quota flags for a new key. * * Search the destination keyring for a key of the same description and if one @@ -803,14 +814,14 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, const char *description, const void *payload, size_t plen, - key_perm_t perm, + struct key_acl *acl, unsigned long flags) { struct keyring_index_key index_key = { .description = description, }; struct key_preparsed_payload prep; - struct assoc_array_edit *edit; + struct assoc_array_edit *edit = NULL; const struct cred *cred = current_cred(); struct key *keyring, *key = NULL; key_ref_t key_ref; @@ -859,13 +870,20 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, goto error_free_prep; } index_key.desc_len = strlen(index_key.description); + key_set_index_key(&index_key); - ret = __key_link_begin(keyring, &index_key, &edit); + ret = __key_link_lock(keyring, &index_key); if (ret < 0) { key_ref = ERR_PTR(ret); goto error_free_prep; } + ret = __key_link_begin(keyring, &index_key, &edit); + if (ret < 0) { + key_ref = ERR_PTR(ret); + goto error_link_end; + } + if (restrict_link && restrict_link->check) { ret = restrict_link->check(keyring, index_key.type, &prep.payload, restrict_link->key); @@ -893,22 +911,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, goto found_matching_key; } - /* if the client doesn't provide, decide on the permissions we want */ - if (perm == KEY_PERM_UNDEF) { - perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; - perm |= KEY_USR_VIEW; - - if (index_key.type->read) - perm |= KEY_POS_READ; - - if (index_key.type == &key_type_keyring || - index_key.type->update) - perm |= KEY_POS_WRITE; - } - /* allocate a new key */ key = key_alloc(index_key.type, index_key.description, - cred->fsuid, cred->fsgid, cred, perm, flags, NULL); + cred->fsuid, cred->fsgid, cred, acl, flags, NULL); if (IS_ERR(key)) { key_ref = ERR_CAST(key); goto error_link_end; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 3e4053a217c3..c2dd66d556d4 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Userspace key control operations * * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/init.h> @@ -30,6 +26,21 @@ #define KEY_MAX_DESC_SIZE 4096 +static const unsigned char keyrings_capabilities[2] = { + [0] = (KEYCTL_CAPS0_CAPABILITIES | + (IS_ENABLED(CONFIG_PERSISTENT_KEYRINGS) ? KEYCTL_CAPS0_PERSISTENT_KEYRINGS : 0) | + (IS_ENABLED(CONFIG_KEY_DH_OPERATIONS) ? KEYCTL_CAPS0_DIFFIE_HELLMAN : 0) | + (IS_ENABLED(CONFIG_ASYMMETRIC_KEY_TYPE) ? KEYCTL_CAPS0_PUBLIC_KEY : 0) | + (IS_ENABLED(CONFIG_BIG_KEYS) ? KEYCTL_CAPS0_BIG_KEY : 0) | + KEYCTL_CAPS0_INVALIDATE | + KEYCTL_CAPS0_RESTRICT_KEYRING | + KEYCTL_CAPS0_MOVE + ), + [1] = (KEYCTL_CAPS1_NS_KEYRING_NAME | + KEYCTL_CAPS1_NS_KEY_TAG | + KEYCTL_CAPS1_ACL_ALTERABLE), +}; + static int key_get_type_from_user(char *type, const char __user *_type, unsigned len) @@ -120,8 +131,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, /* create or update the requested key and add it to the target * keyring */ key_ref = key_create_or_update(keyring_ref, type, description, - payload, plen, KEY_PERM_UNDEF, - KEY_ALLOC_IN_QUOTA); + payload, plen, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key_ref)) { ret = key_ref_to_ptr(key_ref)->serial; key_ref_put(key_ref); @@ -210,8 +220,9 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, } /* do the search */ - key = request_key_and_link(ktype, description, callout_info, - callout_len, NULL, key_ref_to_ptr(dest_ref), + key = request_key_and_link(ktype, description, NULL, callout_info, + callout_len, NULL, NULL, + key_ref_to_ptr(dest_ref), KEY_ALLOC_IN_QUOTA); if (IS_ERR(key)) { ret = PTR_ERR(key); @@ -373,16 +384,10 @@ long keyctl_revoke_key(key_serial_t id) struct key *key; long ret; - key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE); + key_ref = lookup_user_key(id, 0, KEY_NEED_REVOKE); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); - if (ret != -EACCES) - goto error; - key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); - if (IS_ERR(key_ref)) { - ret = PTR_ERR(key_ref); - goto error; - } + goto error; } key = key_ref_to_ptr(key_ref); @@ -416,7 +421,7 @@ long keyctl_invalidate_key(key_serial_t id) kenter("%d", id); - key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); + key_ref = lookup_user_key(id, 0, KEY_NEED_INVAL); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); @@ -461,7 +466,7 @@ long keyctl_keyring_clear(key_serial_t ringid) struct key *keyring; long ret; - keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); + keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_CLEAR); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); @@ -573,6 +578,52 @@ error: } /* + * Move a link to a key from one keyring to another, displacing any matching + * key from the destination keyring. + * + * The key must grant the caller Link permission and both keyrings must grant + * the caller Write permission. There must also be a link in the from keyring + * to the key. If both keyrings are the same, nothing is done. + * + * If successful, 0 will be returned. + */ +long keyctl_keyring_move(key_serial_t id, key_serial_t from_ringid, + key_serial_t to_ringid, unsigned int flags) +{ + key_ref_t key_ref, from_ref, to_ref; + long ret; + + if (flags & ~KEYCTL_MOVE_EXCL) + return -EINVAL; + + key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK); + if (IS_ERR(key_ref)) + return PTR_ERR(key_ref); + + from_ref = lookup_user_key(from_ringid, 0, KEY_NEED_WRITE); + if (IS_ERR(from_ref)) { + ret = PTR_ERR(from_ref); + goto error2; + } + + to_ref = lookup_user_key(to_ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); + if (IS_ERR(to_ref)) { + ret = PTR_ERR(to_ref); + goto error3; + } + + ret = key_move(key_ref_to_ptr(key_ref), key_ref_to_ptr(from_ref), + key_ref_to_ptr(to_ref), flags); + + key_ref_put(to_ref); +error3: + key_ref_put(from_ref); +error2: + key_ref_put(key_ref); + return ret; +} + +/* * Return a description of a key to userspace. * * The key must grant the caller View permission for this to work. @@ -590,6 +641,7 @@ long keyctl_describe_key(key_serial_t keyid, size_t buflen) { struct key *key, *instkey; + unsigned int perm; key_ref_t key_ref; char *infobuf; long ret; @@ -619,6 +671,10 @@ okay: key = key_ref_to_ptr(key_ref); desclen = strlen(key->description); + rcu_read_lock(); + perm = key_acl_to_perm(rcu_dereference(key->acl)); + rcu_read_unlock(); + /* calculate how much information we're going to return */ ret = -ENOMEM; infobuf = kasprintf(GFP_KERNEL, @@ -626,7 +682,7 @@ okay: key->type->name, from_kuid_munged(current_user_ns(), key->uid), from_kgid_munged(current_user_ns(), key->gid), - key->perm); + perm); if (!infobuf) goto error2; infolen = strlen(infobuf); @@ -704,7 +760,7 @@ long keyctl_keyring_search(key_serial_t ringid, } /* do the search */ - key_ref = keyring_search(keyring_ref, ktype, description); + key_ref = keyring_search(keyring_ref, ktype, description, true); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); @@ -843,7 +899,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) goto error; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_NEED_SETATTR); + KEY_NEED_SETSEC); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -938,18 +994,25 @@ quota_overrun: * the key need not be fully instantiated yet. If the caller does not have * sysadmin capability, it may only change the permission on keys that it owns. */ -long keyctl_setperm_key(key_serial_t id, key_perm_t perm) +long keyctl_setperm_key(key_serial_t id, unsigned int perm) { + struct key_acl *acl; struct key *key; key_ref_t key_ref; long ret; + int nr, i, j; - ret = -EINVAL; if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) - goto error; + return -EINVAL; + + nr = 0; + if (perm & KEY_POS_ALL) nr++; + if (perm & KEY_USR_ALL) nr++; + if (perm & KEY_GRP_ALL) nr++; + if (perm & KEY_OTH_ALL) nr++; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_NEED_SETATTR); + KEY_NEED_SETSEC); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; @@ -957,17 +1020,45 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) key = key_ref_to_ptr(key_ref); - /* make the changes with the locks held to prevent chown/chmod races */ - ret = -EACCES; - down_write(&key->sem); + ret = -EOPNOTSUPP; + if (test_bit(KEY_FLAG_HAS_ACL, &key->flags)) + goto error_key; - /* if we're not the sysadmin, we can only change a key that we own */ - if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) { - key->perm = perm; - ret = 0; + ret = -ENOMEM; + acl = kzalloc(struct_size(acl, aces, nr), GFP_KERNEL); + if (!acl) + goto error_key; + + refcount_set(&acl->usage, 1); + acl->nr_ace = nr; + j = 0; + for (i = 0; i < 4; i++) { + struct key_ace *ace = &acl->aces[j]; + unsigned int subset = (perm >> (i * 8)) & KEY_OTH_ALL; + + if (!subset) + continue; + ace->type = KEY_ACE_SUBJ_STANDARD; + ace->subject_id = KEY_ACE_EVERYONE + i; + ace->perm = subset; + if (subset & (KEY_OTH_WRITE | KEY_OTH_SETATTR)) + ace->perm |= KEY_ACE_REVOKE; + if (subset & KEY_OTH_SEARCH) + ace->perm |= KEY_ACE_INVAL; + if (key->type == &key_type_keyring) { + if (subset & KEY_OTH_SEARCH) + ace->perm |= KEY_ACE_JOIN; + if (subset & KEY_OTH_WRITE) + ace->perm |= KEY_ACE_CLEAR; + } + j++; } + /* make the changes with the locks held to prevent chown/chmod races */ + down_write(&key->sem); + ret = key_set_acl(key, acl); up_write(&key->sem); +error_key: key_put(key); error: return ret; @@ -1332,7 +1423,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) long ret; key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, - KEY_NEED_SETATTR); + KEY_NEED_SETSEC); if (IS_ERR(key_ref)) { /* setting the timeout on a key under construction is permitted * if we have the authorisation token handy */ @@ -1483,7 +1574,7 @@ long keyctl_get_security(key_serial_t keyid, * Attempt to install the calling process's session keyring on the process's * parent process. * - * The keyring must exist and must grant the caller LINK permission, and the + * The keyring must exist and must grant the caller JOIN permission, and the * parent process must be single-threaded and must have the same effective * ownership as this process and mustn't be SUID/SGID. * @@ -1500,7 +1591,7 @@ long keyctl_session_to_parent(void) struct cred *cred; int ret; - keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK); + keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_JOIN); if (IS_ERR(keyring_r)) return PTR_ERR(keyring_r); @@ -1524,7 +1615,8 @@ long keyctl_session_to_parent(void) ret = -EPERM; oldwork = NULL; - parent = me->real_parent; + parent = rcu_dereference_protected(me->real_parent, + lockdep_is_held(&tasklist_lock)); /* the parent mustn't be init and mustn't be a kernel thread */ if (parent->pid <= 1 || !parent->mm) @@ -1601,7 +1693,7 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, char *restriction = NULL; long ret; - key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); + key_ref = lookup_user_key(id, 0, KEY_NEED_SETSEC); if (IS_ERR(key_ref)) return PTR_ERR(key_ref); @@ -1632,6 +1724,26 @@ error: } /* + * Get keyrings subsystem capabilities. + */ +long keyctl_capabilities(unsigned char __user *_buffer, size_t buflen) +{ + size_t size = buflen; + + if (size > 0) { + if (size > sizeof(keyrings_capabilities)) + size = sizeof(keyrings_capabilities); + if (copy_to_user(_buffer, keyrings_capabilities, size) != 0) + return -EFAULT; + if (size < buflen && + clear_user(_buffer + size, buflen - size) != 0) + return -EFAULT; + } + + return sizeof(keyrings_capabilities); +} + +/* * The key control system call */ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, @@ -1687,7 +1799,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, case KEYCTL_SETPERM: return keyctl_setperm_key((key_serial_t) arg2, - (key_perm_t) arg3); + (unsigned int)arg3); case KEYCTL_INSTANTIATE: return keyctl_instantiate_key((key_serial_t) arg2, @@ -1771,6 +1883,20 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, (const void __user *)arg4, (const void __user *)arg5); + case KEYCTL_MOVE: + return keyctl_keyring_move((key_serial_t)arg2, + (key_serial_t)arg3, + (key_serial_t)arg4, + (unsigned int)arg5); + case KEYCTL_GRANT_PERMISSION: + return keyctl_grant_permission((key_serial_t)arg2, + (enum key_ace_subject_type)arg3, + (unsigned int)arg4, + (unsigned int)arg5); + + case KEYCTL_CAPABILITIES: + return keyctl_capabilities((unsigned char __user *)arg2, (size_t)arg3); + default: return -EOPNOTSUPP; } diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c index 8bdea5abad11..931d8dfb4a7f 100644 --- a/security/keys/keyctl_pkey.c +++ b/security/keys/keyctl_pkey.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Public-key operation keyctls * * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #include <linux/slab.h> diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e14f09e3a4b0..3b5458f23a95 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Keyring handling * * Copyright (C) 2004-2005, 2008, 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/export.h> @@ -16,10 +12,13 @@ #include <linux/security.h> #include <linux/seq_file.h> #include <linux/err.h> +#include <linux/user_namespace.h> +#include <linux/nsproxy.h> #include <keys/keyring-type.h> #include <keys/user-type.h> #include <linux/assoc_array_priv.h> #include <linux/uaccess.h> +#include <net/net_namespace.h> #include "internal.h" /* @@ -29,11 +28,6 @@ #define KEYRING_SEARCH_MAX_DEPTH 6 /* - * We keep all named keyrings in a hash to speed looking them up. - */ -#define KEYRING_NAME_HASH_SIZE (1 << 5) - -/* * We mark pointers we pass to the associative array with bit 1 set if * they're keyrings and clear otherwise. */ @@ -55,17 +49,21 @@ static inline void *keyring_key_to_ptr(struct key *key) return key; } -static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; static DEFINE_RWLOCK(keyring_name_lock); -static inline unsigned keyring_hash(const char *desc) +/* + * Clean up the bits of user_namespace that belong to us. + */ +void key_free_user_ns(struct user_namespace *ns) { - unsigned bucket = 0; - - for (; *desc; desc++) - bucket += (unsigned char)*desc; - - return bucket & (KEYRING_NAME_HASH_SIZE - 1); + write_lock(&keyring_name_lock); + list_del_init(&ns->keyring_name_list); + write_unlock(&keyring_name_lock); + + key_put(ns->user_keyring_register); +#ifdef CONFIG_PERSISTENT_KEYRINGS + key_put(ns->persistent_keyring_register); +#endif } /* @@ -100,27 +98,21 @@ EXPORT_SYMBOL(key_type_keyring); * Semaphore to serialise link/link calls to prevent two link calls in parallel * introducing a cycle. */ -static DECLARE_RWSEM(keyring_serialise_link_sem); +static DEFINE_MUTEX(keyring_serialise_link_lock); /* * Publish the name of a keyring so that it can be found by name (if it has - * one). + * one and it doesn't begin with a dot). */ static void keyring_publish_name(struct key *keyring) { - int bucket; - - if (keyring->description) { - bucket = keyring_hash(keyring->description); + struct user_namespace *ns = current_user_ns(); + if (keyring->description && + keyring->description[0] && + keyring->description[0] != '.') { write_lock(&keyring_name_lock); - - if (!keyring_name_hash[bucket].next) - INIT_LIST_HEAD(&keyring_name_hash[bucket]); - - list_add_tail(&keyring->name_link, - &keyring_name_hash[bucket]); - + list_add_tail(&keyring->name_link, &ns->keyring_name_list); write_unlock(&keyring_name_lock); } } @@ -168,7 +160,7 @@ static u64 mult_64x32_and_fold(u64 x, u32 y) /* * Hash a key type and description. */ -static unsigned long hash_key_type_and_desc(const struct keyring_index_key *index_key) +static void hash_key_type_and_desc(struct keyring_index_key *index_key) { const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP; const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK; @@ -179,9 +171,12 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde int n, desc_len = index_key->desc_len; type = (unsigned long)index_key->type; - acc = mult_64x32_and_fold(type, desc_len + 13); acc = mult_64x32_and_fold(acc, 9207); + piece = (unsigned long)index_key->domain_tag; + acc = mult_64x32_and_fold(acc, piece); + acc = mult_64x32_and_fold(acc, 9207); + for (;;) { n = desc_len; if (n <= 0) @@ -206,24 +201,67 @@ static unsigned long hash_key_type_and_desc(const struct keyring_index_key *inde * zero for keyrings and non-zero otherwise. */ if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0) - return hash | (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1; - if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0) - return (hash + (hash << level_shift)) & ~fan_mask; - return hash; + hash |= (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1; + else if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0) + hash = (hash + (hash << level_shift)) & ~fan_mask; + index_key->hash = hash; } /* - * Build the next index key chunk. - * - * On 32-bit systems the index key is laid out as: - * - * 0 4 5 9... - * hash desclen typeptr desc[] + * Finalise an index key to include a part of the description actually in the + * index key, to set the domain tag and to calculate the hash. + */ +void key_set_index_key(struct keyring_index_key *index_key) +{ + static struct key_tag default_domain_tag = { .usage = REFCOUNT_INIT(1), }; + size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc)); + + memcpy(index_key->desc, index_key->description, n); + + if (!index_key->domain_tag) { + if (index_key->type->flags & KEY_TYPE_NET_DOMAIN) + index_key->domain_tag = current->nsproxy->net_ns->key_domain; + else + index_key->domain_tag = &default_domain_tag; + } + + hash_key_type_and_desc(index_key); +} + +/** + * key_put_tag - Release a ref on a tag. + * @tag: The tag to release. * - * On 64-bit systems: + * This releases a reference the given tag and returns true if that ref was the + * last one. + */ +bool key_put_tag(struct key_tag *tag) +{ + if (refcount_dec_and_test(&tag->usage)) { + kfree_rcu(tag, rcu); + return true; + } + + return false; +} + +/** + * key_remove_domain - Kill off a key domain and gc its keys + * @domain_tag: The domain tag to release. * - * 0 8 9 17... - * hash desclen typeptr desc[] + * This marks a domain tag as being dead and releases a ref on it. If that + * wasn't the last reference, the garbage collector is poked to try and delete + * all keys that were in the domain. + */ +void key_remove_domain(struct key_tag *domain_tag) +{ + domain_tag->removed = true; + if (!key_put_tag(domain_tag)) + key_schedule_gc_links(); +} + +/* + * Build the next index key chunk. * * We return it one word-sized chunk at a time. */ @@ -231,41 +269,33 @@ static unsigned long keyring_get_key_chunk(const void *data, int level) { const struct keyring_index_key *index_key = data; unsigned long chunk = 0; - long offset = 0; + const u8 *d; int desc_len = index_key->desc_len, n = sizeof(chunk); level /= ASSOC_ARRAY_KEY_CHUNK_SIZE; switch (level) { case 0: - return hash_key_type_and_desc(index_key); + return index_key->hash; case 1: - return ((unsigned long)index_key->type << 8) | desc_len; + return index_key->x; case 2: - if (desc_len == 0) - return (u8)((unsigned long)index_key->type >> - (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8)); - n--; - offset = 1; - /* fall through */ + return (unsigned long)index_key->type; + case 3: + return (unsigned long)index_key->domain_tag; default: - offset += sizeof(chunk) - 1; - offset += (level - 3) * sizeof(chunk); - if (offset >= desc_len) + level -= 4; + if (desc_len <= sizeof(index_key->desc)) return 0; - desc_len -= offset; + + d = index_key->description + sizeof(index_key->desc); + d += level * sizeof(long); + desc_len -= sizeof(index_key->desc); if (desc_len > n) desc_len = n; - offset += desc_len; do { chunk <<= 8; - chunk |= ((u8*)index_key->description)[--offset]; + chunk |= *d++; } while (--desc_len > 0); - - if (level == 2) { - chunk <<= 8; - chunk |= (u8)((unsigned long)index_key->type >> - (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8)); - } return chunk; } } @@ -282,6 +312,7 @@ static bool keyring_compare_object(const void *object, const void *data) const struct key *key = keyring_ptr_to_key(object); return key->index_key.type == index_key->type && + key->index_key.domain_tag == index_key->domain_tag && key->index_key.desc_len == index_key->desc_len && memcmp(key->index_key.description, index_key->description, index_key->desc_len) == 0; @@ -300,43 +331,38 @@ static int keyring_diff_objects(const void *object, const void *data) int level, i; level = 0; - seg_a = hash_key_type_and_desc(a); - seg_b = hash_key_type_and_desc(b); + seg_a = a->hash; + seg_b = b->hash; if ((seg_a ^ seg_b) != 0) goto differ; + level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8; /* The number of bits contributed by the hash is controlled by a * constant in the assoc_array headers. Everything else thereafter we * can deal with as being machine word-size dependent. */ - level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8; - seg_a = a->desc_len; - seg_b = b->desc_len; + seg_a = a->x; + seg_b = b->x; if ((seg_a ^ seg_b) != 0) goto differ; + level += sizeof(unsigned long); /* The next bit may not work on big endian */ - level++; seg_a = (unsigned long)a->type; seg_b = (unsigned long)b->type; if ((seg_a ^ seg_b) != 0) goto differ; + level += sizeof(unsigned long); + seg_a = (unsigned long)a->domain_tag; + seg_b = (unsigned long)b->domain_tag; + if ((seg_a ^ seg_b) != 0) + goto differ; level += sizeof(unsigned long); - if (a->desc_len == 0) - goto same; - i = 0; - if (((unsigned long)a->description | (unsigned long)b->description) & - (sizeof(unsigned long) - 1)) { - do { - seg_a = *(unsigned long *)(a->description + i); - seg_b = *(unsigned long *)(b->description + i); - if ((seg_a ^ seg_b) != 0) - goto differ_plus_i; - i += sizeof(unsigned long); - } while (i < (a->desc_len & (sizeof(unsigned long) - 1))); - } + i = sizeof(a->desc); + if (a->desc_len <= i) + goto same; for (; i < a->desc_len; i++) { seg_a = *(unsigned char *)(a->description + i); @@ -489,11 +515,19 @@ static long keyring_read(const struct key *keyring, return ret; } -/* - * Allocate a keyring and link into the destination keyring. +/** + * keyring_alloc - Allocate a keyring and link into the destination + * @description: The key description to allow the key to be searched out. + * @uid: The owner of the new key. + * @gid: The group ID for the new key's group permissions. + * @cred: The credentials specifying UID namespace. + * @acl: The ACL to attach to the new key. + * @flags: Flags specifying quota properties. + * @restrict_link: Optional link restriction for new keyrings. + * @dest: Destination keyring. */ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, - const struct cred *cred, key_perm_t perm, + const struct cred *cred, struct key_acl *acl, unsigned long flags, struct key_restriction *restrict_link, struct key *dest) @@ -502,7 +536,7 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, int ret; keyring = key_alloc(&key_type_keyring, description, - uid, gid, cred, perm, flags, restrict_link); + uid, gid, cred, acl, flags, restrict_link); if (!IS_ERR(keyring)) { ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); if (ret < 0) { @@ -520,7 +554,7 @@ EXPORT_SYMBOL(keyring_alloc); * @keyring: The keyring being added to. * @type: The type of key being added. * @payload: The payload of the key intended to be added. - * @data: Additional data for evaluating restriction. + * @restriction_key: Keys providing additional data for evaluating restriction. * * Reject the addition of any links to a keyring. It can be overridden by * passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when @@ -662,6 +696,9 @@ static bool search_nested_keyrings(struct key *keyring, BUG_ON((ctx->flags & STATE_CHECKS) == 0 || (ctx->flags & STATE_CHECKS) == STATE_CHECKS); + if (ctx->index_key.description) + key_set_index_key(&ctx->index_key); + /* Check to see if this top-level keyring is what we are looking for * and whether it is valid or not. */ @@ -701,6 +738,9 @@ descend_to_keyring: * Non-keyrings avoid the leftmost branch of the root entirely (root * slots 1-15). */ + if (!(ctx->flags & KEYRING_SEARCH_RECURSE)) + goto not_this_keyring; + ptr = READ_ONCE(keyring->keys.root); if (!ptr) goto not_this_keyring; @@ -835,7 +875,7 @@ found: } /** - * keyring_search_aux - Search a keyring tree for a key matching some criteria + * keyring_search_rcu - Search a keyring tree for a matching key under RCU * @keyring_ref: A pointer to the keyring with possession indicator. * @ctx: The keyring search context. * @@ -847,7 +887,9 @@ found: * addition, the LSM gets to forbid keyring searches and key matches. * * The search is performed as a breadth-then-depth search up to the prescribed - * limit (KEYRING_SEARCH_MAX_DEPTH). + * limit (KEYRING_SEARCH_MAX_DEPTH). The caller must hold the RCU read lock to + * prevent keyrings from being destroyed or rearranged whilst they are being + * searched. * * Keys are matched to the type provided and are then filtered by the match * function, which is given the description to use in any way it sees fit. The @@ -866,7 +908,7 @@ found: * In the case of a successful return, the possession attribute from * @keyring_ref is propagated to the returned key reference. */ -key_ref_t keyring_search_aux(key_ref_t keyring_ref, +key_ref_t keyring_search_rcu(key_ref_t keyring_ref, struct keyring_search_context *ctx) { struct key *keyring; @@ -888,11 +930,9 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, return ERR_PTR(err); } - rcu_read_lock(); ctx->now = ktime_get_real_seconds(); if (search_nested_keyrings(keyring, ctx)) __key_get(key_ref_to_ptr(ctx->result)); - rcu_read_unlock(); return ctx->result; } @@ -901,13 +941,15 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, * @keyring: The root of the keyring tree to be searched. * @type: The type of keyring we want to find. * @description: The name of the keyring we want to find. + * @recurse: True to search the children of @keyring also * - * As keyring_search_aux() above, but using the current task's credentials and + * As keyring_search_rcu() above, but using the current task's credentials and * type's default matching function and preferred search method. */ key_ref_t keyring_search(key_ref_t keyring, struct key_type *type, - const char *description) + const char *description, + bool recurse) { struct keyring_search_context ctx = { .index_key.type = type, @@ -922,13 +964,17 @@ key_ref_t keyring_search(key_ref_t keyring, key_ref_t key; int ret; + if (recurse) + ctx.flags |= KEYRING_SEARCH_RECURSE; if (type->match_preparse) { ret = type->match_preparse(&ctx.match_data); if (ret < 0) return ERR_PTR(ret); } - key = keyring_search_aux(keyring, &ctx); + rcu_read_lock(); + key = keyring_search_rcu(keyring, &ctx); + rcu_read_unlock(); if (type->match_free) type->match_free(&ctx.match_data); @@ -976,9 +1022,13 @@ static bool keyring_detect_restriction_cycle(const struct key *dest_keyring, /** * keyring_restrict - Look up and apply a restriction to a keyring - * - * @keyring: The keyring to be restricted + * @keyring_ref: The keyring to be restricted + * @type: The key type that will provide the restriction checker. * @restriction: The restriction options to apply to the keyring + * + * Look up a keyring and apply a restriction to it. The restriction is managed + * by the specific key type, but can be configured by the options specified in + * the restriction string. */ int keyring_restrict(key_ref_t keyring_ref, const char *type, const char *restriction) @@ -1090,60 +1140,55 @@ found: /* * Find a keyring with the specified name. * - * Only keyrings that have nonzero refcount, are not revoked, and are owned by a - * user in the current user namespace are considered. If @uid_keyring is %true, - * the keyring additionally must have been allocated as a user or user session - * keyring; otherwise, it must grant Search permission directly to the caller. + * Only keyrings that have nonzero refcount, are not revoked, and are owned by + * a user in the current user namespace are considered. If @uid_keyring is + * %true, the keyring additionally must have been allocated as a user or user + * session keyring; otherwise, it must grant JOIN permission directly to the + * caller (ie. not through possession). * * Returns a pointer to the keyring with the keyring's refcount having being * incremented on success. -ENOKEY is returned if a key could not be found. */ struct key *find_keyring_by_name(const char *name, bool uid_keyring) { + struct user_namespace *ns = current_user_ns(); struct key *keyring; - int bucket; if (!name) return ERR_PTR(-EINVAL); - bucket = keyring_hash(name); - read_lock(&keyring_name_lock); - if (keyring_name_hash[bucket].next) { - /* search this hash bucket for a keyring with a matching name - * that's readable and that hasn't been revoked */ - list_for_each_entry(keyring, - &keyring_name_hash[bucket], - name_link - ) { - if (!kuid_has_mapping(current_user_ns(), keyring->user->uid)) - continue; - - if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) - continue; + /* Search this hash bucket for a keyring with a matching name that + * grants Search permission and that hasn't been revoked + */ + list_for_each_entry(keyring, &ns->keyring_name_list, name_link) { + if (!kuid_has_mapping(ns, keyring->user->uid)) + continue; - if (strcmp(keyring->description, name) != 0) - continue; + if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) + continue; - if (uid_keyring) { - if (!test_bit(KEY_FLAG_UID_KEYRING, - &keyring->flags)) - continue; - } else { - if (key_permission(make_key_ref(keyring, 0), - KEY_NEED_SEARCH) < 0) - continue; - } + if (strcmp(keyring->description, name) != 0) + continue; - /* we've got a match but we might end up racing with - * key_cleanup() if the keyring is currently 'dead' - * (ie. it has a zero usage count) */ - if (!refcount_inc_not_zero(&keyring->usage)) + if (uid_keyring) { + if (!test_bit(KEY_FLAG_UID_KEYRING, + &keyring->flags)) + continue; + } else { + if (key_permission(make_key_ref(keyring, 0), + KEY_NEED_JOIN) < 0) continue; - keyring->last_used_at = ktime_get_real_seconds(); - goto out; } + + /* we've got a match but we might end up racing with + * key_cleanup() if the keyring is currently 'dead' + * (ie. it has a zero usage count) */ + if (!refcount_inc_not_zero(&keyring->usage)) + continue; + keyring->last_used_at = ktime_get_real_seconds(); + goto out; } keyring = ERR_PTR(-ENOKEY); @@ -1186,7 +1231,8 @@ static int keyring_detect_cycle(struct key *A, struct key *B) .flags = (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_NO_UPDATE_TIME | KEYRING_SEARCH_NO_CHECK_PERM | - KEYRING_SEARCH_DETECT_TOO_DEEP), + KEYRING_SEARCH_DETECT_TOO_DEEP | + KEYRING_SEARCH_RECURSE), }; rcu_read_lock(); @@ -1196,13 +1242,67 @@ static int keyring_detect_cycle(struct key *A, struct key *B) } /* + * Lock keyring for link. + */ +int __key_link_lock(struct key *keyring, + const struct keyring_index_key *index_key) + __acquires(&keyring->sem) + __acquires(&keyring_serialise_link_lock) +{ + if (keyring->type != &key_type_keyring) + return -ENOTDIR; + + down_write(&keyring->sem); + + /* Serialise link/link calls to prevent parallel calls causing a cycle + * when linking two keyring in opposite orders. + */ + if (index_key->type == &key_type_keyring) + mutex_lock(&keyring_serialise_link_lock); + + return 0; +} + +/* + * Lock keyrings for move (link/unlink combination). + */ +int __key_move_lock(struct key *l_keyring, struct key *u_keyring, + const struct keyring_index_key *index_key) + __acquires(&l_keyring->sem) + __acquires(&u_keyring->sem) + __acquires(&keyring_serialise_link_lock) +{ + if (l_keyring->type != &key_type_keyring || + u_keyring->type != &key_type_keyring) + return -ENOTDIR; + + /* We have to be very careful here to take the keyring locks in the + * right order, lest we open ourselves to deadlocking against another + * move operation. + */ + if (l_keyring < u_keyring) { + down_write(&l_keyring->sem); + down_write_nested(&u_keyring->sem, 1); + } else { + down_write(&u_keyring->sem); + down_write_nested(&l_keyring->sem, 1); + } + + /* Serialise link/link calls to prevent parallel calls causing a cycle + * when linking two keyring in opposite orders. + */ + if (index_key->type == &key_type_keyring) + mutex_lock(&keyring_serialise_link_lock); + + return 0; +} + +/* * Preallocate memory so that a key can be linked into to a keyring. */ int __key_link_begin(struct key *keyring, const struct keyring_index_key *index_key, struct assoc_array_edit **_edit) - __acquires(&keyring->sem) - __acquires(&keyring_serialise_link_sem) { struct assoc_array_edit *edit; int ret; @@ -1211,20 +1311,13 @@ int __key_link_begin(struct key *keyring, keyring->serial, index_key->type->name, index_key->description); BUG_ON(index_key->desc_len == 0); + BUG_ON(*_edit != NULL); - if (keyring->type != &key_type_keyring) - return -ENOTDIR; - - down_write(&keyring->sem); + *_edit = NULL; ret = -EKEYREVOKED; if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) - goto error_krsem; - - /* serialise link/link calls to prevent parallel calls causing a cycle - * when linking two keyring in opposite orders */ - if (index_key->type == &key_type_keyring) - down_write(&keyring_serialise_link_sem); + goto error; /* Create an edit script that will insert/replace the key in the * keyring tree. @@ -1235,7 +1328,7 @@ int __key_link_begin(struct key *keyring, NULL); if (IS_ERR(edit)) { ret = PTR_ERR(edit); - goto error_sem; + goto error; } /* If we're not replacing a link in-place then we're going to need some @@ -1254,11 +1347,7 @@ int __key_link_begin(struct key *keyring, error_cancel: assoc_array_cancel_edit(edit); -error_sem: - if (index_key->type == &key_type_keyring) - up_write(&keyring_serialise_link_sem); -error_krsem: - up_write(&keyring->sem); +error: kleave(" = %d", ret); return ret; } @@ -1303,14 +1392,11 @@ void __key_link_end(struct key *keyring, const struct keyring_index_key *index_key, struct assoc_array_edit *edit) __releases(&keyring->sem) - __releases(&keyring_serialise_link_sem) + __releases(&keyring_serialise_link_lock) { BUG_ON(index_key->type == NULL); kenter("%d,%s,", keyring->serial, index_key->type->name); - if (index_key->type == &key_type_keyring) - up_write(&keyring_serialise_link_sem); - if (edit) { if (!edit->dead_leaf) { key_payload_reserve(keyring, @@ -1319,6 +1405,9 @@ void __key_link_end(struct key *keyring, assoc_array_cancel_edit(edit); } up_write(&keyring->sem); + + if (index_key->type == &key_type_keyring) + mutex_unlock(&keyring_serialise_link_lock); } /* @@ -1354,7 +1443,7 @@ static int __key_link_check_restriction(struct key *keyring, struct key *key) */ int key_link(struct key *keyring, struct key *key) { - struct assoc_array_edit *edit; + struct assoc_array_edit *edit = NULL; int ret; kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage)); @@ -1362,22 +1451,88 @@ int key_link(struct key *keyring, struct key *key) key_check(keyring); key_check(key); + ret = __key_link_lock(keyring, &key->index_key); + if (ret < 0) + goto error; + ret = __key_link_begin(keyring, &key->index_key, &edit); - if (ret == 0) { - kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage)); - ret = __key_link_check_restriction(keyring, key); - if (ret == 0) - ret = __key_link_check_live_key(keyring, key); - if (ret == 0) - __key_link(key, &edit); - __key_link_end(keyring, &key->index_key, edit); - } + if (ret < 0) + goto error_end; + kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage)); + ret = __key_link_check_restriction(keyring, key); + if (ret == 0) + ret = __key_link_check_live_key(keyring, key); + if (ret == 0) + __key_link(key, &edit); + +error_end: + __key_link_end(keyring, &key->index_key, edit); +error: kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage)); return ret; } EXPORT_SYMBOL(key_link); +/* + * Lock a keyring for unlink. + */ +static int __key_unlink_lock(struct key *keyring) + __acquires(&keyring->sem) +{ + if (keyring->type != &key_type_keyring) + return -ENOTDIR; + + down_write(&keyring->sem); + return 0; +} + +/* + * Begin the process of unlinking a key from a keyring. + */ +static int __key_unlink_begin(struct key *keyring, struct key *key, + struct assoc_array_edit **_edit) +{ + struct assoc_array_edit *edit; + + BUG_ON(*_edit != NULL); + + edit = assoc_array_delete(&keyring->keys, &keyring_assoc_array_ops, + &key->index_key); + if (IS_ERR(edit)) + return PTR_ERR(edit); + + if (!edit) + return -ENOENT; + + *_edit = edit; + return 0; +} + +/* + * Apply an unlink change. + */ +static void __key_unlink(struct key *keyring, struct key *key, + struct assoc_array_edit **_edit) +{ + assoc_array_apply_edit(*_edit); + *_edit = NULL; + key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES); +} + +/* + * Finish unlinking a key from to a keyring. + */ +static void __key_unlink_end(struct key *keyring, + struct key *key, + struct assoc_array_edit *edit) + __releases(&keyring->sem) +{ + if (edit) + assoc_array_cancel_edit(edit); + up_write(&keyring->sem); +} + /** * key_unlink - Unlink the first link to a key from a keyring. * @keyring: The keyring to remove the link from. @@ -1397,36 +1552,97 @@ EXPORT_SYMBOL(key_link); */ int key_unlink(struct key *keyring, struct key *key) { - struct assoc_array_edit *edit; + struct assoc_array_edit *edit = NULL; int ret; key_check(keyring); key_check(key); - if (keyring->type != &key_type_keyring) - return -ENOTDIR; + ret = __key_unlink_lock(keyring); + if (ret < 0) + return ret; - down_write(&keyring->sem); + ret = __key_unlink_begin(keyring, key, &edit); + if (ret == 0) + __key_unlink(keyring, key, &edit); + __key_unlink_end(keyring, key, edit); + return ret; +} +EXPORT_SYMBOL(key_unlink); - edit = assoc_array_delete(&keyring->keys, &keyring_assoc_array_ops, - &key->index_key); - if (IS_ERR(edit)) { - ret = PTR_ERR(edit); +/** + * key_move - Move a key from one keyring to another + * @key: The key to move + * @from_keyring: The keyring to remove the link from. + * @to_keyring: The keyring to make the link in. + * @flags: Qualifying flags, such as KEYCTL_MOVE_EXCL. + * + * Make a link in @to_keyring to a key, such that the keyring holds a reference + * on that key and the key can potentially be found by searching that keyring + * whilst simultaneously removing a link to the key from @from_keyring. + * + * This function will write-lock both keyring's semaphores and will consume + * some of the user's key data quota to hold the link on @to_keyring. + * + * Returns 0 if successful, -ENOTDIR if either keyring isn't a keyring, + * -EKEYREVOKED if either keyring has been revoked, -ENFILE if the second + * keyring is full, -EDQUOT if there is insufficient key data quota remaining + * to add another link or -ENOMEM if there's insufficient memory. If + * KEYCTL_MOVE_EXCL is set, then -EEXIST will be returned if there's already a + * matching key in @to_keyring. + * + * It is assumed that the caller has checked that it is permitted for a link to + * be made (the keyring should have Write permission and the key Link + * permission). + */ +int key_move(struct key *key, + struct key *from_keyring, + struct key *to_keyring, + unsigned int flags) +{ + struct assoc_array_edit *from_edit = NULL, *to_edit = NULL; + int ret; + + kenter("%d,%d,%d", key->serial, from_keyring->serial, to_keyring->serial); + + if (from_keyring == to_keyring) + return 0; + + key_check(key); + key_check(from_keyring); + key_check(to_keyring); + + ret = __key_move_lock(from_keyring, to_keyring, &key->index_key); + if (ret < 0) + goto out; + ret = __key_unlink_begin(from_keyring, key, &from_edit); + if (ret < 0) goto error; - } - ret = -ENOENT; - if (edit == NULL) + ret = __key_link_begin(to_keyring, &key->index_key, &to_edit); + if (ret < 0) goto error; - assoc_array_apply_edit(edit); - key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES); - ret = 0; + ret = -EEXIST; + if (to_edit->dead_leaf && (flags & KEYCTL_MOVE_EXCL)) + goto error; + ret = __key_link_check_restriction(to_keyring, key); + if (ret < 0) + goto error; + ret = __key_link_check_live_key(to_keyring, key); + if (ret < 0) + goto error; + + __key_unlink(from_keyring, key, &from_edit); + __key_link(key, &to_edit); error: - up_write(&keyring->sem); + __key_link_end(to_keyring, &key->index_key, to_edit); + __key_unlink_end(from_keyring, key, from_edit); +out: + kleave(" = %d", ret); return ret; } -EXPORT_SYMBOL(key_unlink); +EXPORT_SYMBOL(key_move); /** * keyring_clear - Clear a keyring diff --git a/security/keys/permission.c b/security/keys/permission.c index 06df9d5e7572..fd8a5dc6910a 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c @@ -1,23 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Key permission checking * * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/export.h> #include <linux/security.h> +#include <linux/user_namespace.h> +#include <linux/uaccess.h> #include "internal.h" +struct key_acl default_key_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; +EXPORT_SYMBOL(default_key_acl); + +struct key_acl joinable_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_LINK | KEY_ACE_JOIN), + } +}; +EXPORT_SYMBOL(joinable_keyring_acl); + +struct key_acl internal_key_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_SEARCH), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH), + } +}; +EXPORT_SYMBOL(internal_key_acl); + +struct key_acl internal_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_SEARCH), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH), + } +}; +EXPORT_SYMBOL(internal_keyring_acl); + +struct key_acl internal_writable_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | KEY_ACE_SEARCH), + } +}; +EXPORT_SYMBOL(internal_writable_keyring_acl); + /** * key_task_permission - Check a key can be used * @key_ref: The key to check. * @cred: The credentials to use. - * @perm: The permissions to check for. + * @desired_perm: The permission to check for. * * Check to see whether permission is granted to use a key in the desired way, * but permit the security modules to override. @@ -28,53 +78,73 @@ * permissions bits or the LSM check. */ int key_task_permission(const key_ref_t key_ref, const struct cred *cred, - unsigned perm) + unsigned int desired_perm) { - struct key *key; - key_perm_t kperm; - int ret; + const struct key_acl *acl; + const struct key *key; + unsigned int allow = 0; + int i; + + BUILD_BUG_ON(KEY_NEED_VIEW != KEY_ACE_VIEW || + KEY_NEED_READ != KEY_ACE_READ || + KEY_NEED_WRITE != KEY_ACE_WRITE || + KEY_NEED_SEARCH != KEY_ACE_SEARCH || + KEY_NEED_LINK != KEY_ACE_LINK || + KEY_NEED_SETSEC != KEY_ACE_SET_SECURITY || + KEY_NEED_INVAL != KEY_ACE_INVAL || + KEY_NEED_REVOKE != KEY_ACE_REVOKE || + KEY_NEED_JOIN != KEY_ACE_JOIN || + KEY_NEED_CLEAR != KEY_ACE_CLEAR); key = key_ref_to_ptr(key_ref); - /* use the second 8-bits of permissions for keys the caller owns */ - if (uid_eq(key->uid, cred->fsuid)) { - kperm = key->perm >> 16; - goto use_these_perms; - } + rcu_read_lock(); - /* use the third 8-bits of permissions for keys the caller has a group - * membership in common with */ - if (gid_valid(key->gid) && key->perm & KEY_GRP_ALL) { - if (gid_eq(key->gid, cred->fsgid)) { - kperm = key->perm >> 8; - goto use_these_perms; - } + acl = rcu_dereference(key->acl); + if (!acl || acl->nr_ace == 0) + goto no_access_rcu; + + for (i = 0; i < acl->nr_ace; i++) { + const struct key_ace *ace = &acl->aces[i]; - ret = groups_search(cred->group_info, key->gid); - if (ret) { - kperm = key->perm >> 8; - goto use_these_perms; + switch (ace->type) { + case KEY_ACE_SUBJ_STANDARD: + switch (ace->subject_id) { + case KEY_ACE_POSSESSOR: + if (is_key_possessed(key_ref)) + allow |= ace->perm; + break; + case KEY_ACE_OWNER: + if (uid_eq(key->uid, cred->fsuid)) + allow |= ace->perm; + break; + case KEY_ACE_GROUP: + if (gid_valid(key->gid)) { + if (gid_eq(key->gid, cred->fsgid)) + allow |= ace->perm; + else if (groups_search(cred->group_info, key->gid)) + allow |= ace->perm; + } + break; + case KEY_ACE_EVERYONE: + allow |= ace->perm; + break; + } + break; } } - /* otherwise use the least-significant 8-bits */ - kperm = key->perm; + rcu_read_unlock(); -use_these_perms: + if (!(allow & desired_perm)) + goto no_access; - /* use the top 8-bits of permissions for keys the caller possesses - * - possessor permissions are additive with other permissions - */ - if (is_key_possessed(key_ref)) - kperm |= key->perm >> 24; + return security_key_permission(key_ref, cred, desired_perm); - kperm = kperm & perm & KEY_NEED_ALL; - - if (kperm != perm) - return -EACCES; - - /* let LSM be the final arbiter */ - return security_key_permission(key_ref, cred, perm); +no_access_rcu: + rcu_read_unlock(); +no_access: + return -EACCES; } EXPORT_SYMBOL(key_task_permission); @@ -108,3 +178,218 @@ int key_validate(const struct key *key) return 0; } EXPORT_SYMBOL(key_validate); + +/* + * Roughly render an ACL to an old-style permissions mask. We cannot + * accurately render what the ACL, particularly if it has ACEs that represent + * subjects outside of { poss, user, group, other }. + */ +unsigned int key_acl_to_perm(const struct key_acl *acl) +{ + unsigned int perm = 0, tperm; + int i; + + BUILD_BUG_ON(KEY_OTH_VIEW != KEY_ACE_VIEW || + KEY_OTH_READ != KEY_ACE_READ || + KEY_OTH_WRITE != KEY_ACE_WRITE || + KEY_OTH_SEARCH != KEY_ACE_SEARCH || + KEY_OTH_LINK != KEY_ACE_LINK || + KEY_OTH_SETATTR != KEY_ACE_SET_SECURITY); + + if (!acl || acl->nr_ace == 0) + return 0; + + for (i = 0; i < acl->nr_ace; i++) { + const struct key_ace *ace = &acl->aces[i]; + + switch (ace->type) { + case KEY_ACE_SUBJ_STANDARD: + tperm = ace->perm & KEY_OTH_ALL; + + /* Invalidation and joining were allowed by SEARCH */ + if (ace->perm & (KEY_ACE_INVAL | KEY_ACE_JOIN)) + tperm |= KEY_OTH_SEARCH; + + /* Revocation was allowed by either SETATTR or WRITE */ + if ((ace->perm & KEY_ACE_REVOKE) && !(tperm & KEY_OTH_SETATTR)) + tperm |= KEY_OTH_WRITE; + + /* Clearing was allowed by WRITE */ + if (ace->perm & KEY_ACE_CLEAR) + tperm |= KEY_OTH_WRITE; + + switch (ace->subject_id) { + case KEY_ACE_POSSESSOR: + perm |= tperm << 24; + break; + case KEY_ACE_OWNER: + perm |= tperm << 16; + break; + case KEY_ACE_GROUP: + perm |= tperm << 8; + break; + case KEY_ACE_EVERYONE: + perm |= tperm << 0; + break; + } + } + } + + return perm; +} + +/* + * Destroy a key's ACL. + */ +void key_put_acl(struct key_acl *acl) +{ + if (acl && refcount_dec_and_test(&acl->usage)) + kfree_rcu(acl, rcu); +} + +/* + * Try to set the ACL. This either attaches or discards the proposed ACL. + */ +long key_set_acl(struct key *key, struct key_acl *acl) +{ + int i; + + /* If we're not the sysadmin, we can only change a key that we own. */ + if (!capable(CAP_SYS_ADMIN) && !uid_eq(key->uid, current_fsuid())) { + key_put_acl(acl); + return -EACCES; + } + + for (i = 0; i < acl->nr_ace; i++) { + const struct key_ace *ace = &acl->aces[i]; + if (ace->type == KEY_ACE_SUBJ_STANDARD && + ace->subject_id == KEY_ACE_POSSESSOR) { + if (ace->perm & KEY_ACE_VIEW) + acl->possessor_viewable = true; + break; + } + } + + rcu_swap_protected(key->acl, acl, lockdep_is_held(&key->sem)); + key_put_acl(acl); + return 0; +} + +/* + * Allocate a new ACL with an extra ACE slot. + */ +static struct key_acl *key_alloc_acl(const struct key_acl *old_acl, int nr, int skip) +{ + struct key_acl *acl; + int nr_ace, i, j = 0; + + nr_ace = old_acl->nr_ace + nr; + if (nr_ace > 16) + return ERR_PTR(-EINVAL); + + acl = kzalloc(struct_size(acl, aces, nr_ace), GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + + refcount_set(&acl->usage, 1); + acl->nr_ace = nr_ace; + for (i = 0; i < old_acl->nr_ace; i++) { + if (i == skip) + continue; + acl->aces[j] = old_acl->aces[i]; + j++; + } + return acl; +} + +/* + * Generate the revised ACL. + */ +static long key_change_acl(struct key *key, struct key_ace *new_ace) +{ + struct key_acl *acl, *old; + int i; + + old = rcu_dereference_protected(key->acl, lockdep_is_held(&key->sem)); + + for (i = 0; i < old->nr_ace; i++) + if (old->aces[i].type == new_ace->type && + old->aces[i].subject_id == new_ace->subject_id) + goto found_match; + + if (new_ace->perm == 0) + return 0; /* No permissions to remove. Add deny record? */ + + acl = key_alloc_acl(old, 1, -1); + if (IS_ERR(acl)) + return PTR_ERR(acl); + acl->aces[i] = *new_ace; + goto change; + +found_match: + if (new_ace->perm == 0) + goto delete_ace; + if (new_ace->perm == old->aces[i].perm) + return 0; + acl = key_alloc_acl(old, 0, -1); + if (IS_ERR(acl)) + return PTR_ERR(acl); + acl->aces[i].perm = new_ace->perm; + goto change; + +delete_ace: + acl = key_alloc_acl(old, -1, i); + if (IS_ERR(acl)) + return PTR_ERR(acl); + goto change; + +change: + return key_set_acl(key, acl); +} + +/* + * Add, alter or remove (if perm == 0) an ACE in a key's ACL. + */ +long keyctl_grant_permission(key_serial_t keyid, + enum key_ace_subject_type type, + unsigned int subject, + unsigned int perm) +{ + struct key_ace new_ace; + struct key *key; + key_ref_t key_ref; + long ret; + + new_ace.type = type; + new_ace.perm = perm; + + switch (type) { + case KEY_ACE_SUBJ_STANDARD: + if (subject >= nr__key_ace_standard_subject) + return -ENOENT; + new_ace.subject_id = subject; + break; + + default: + return -ENOENT; + } + + key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_SETSEC); + if (IS_ERR(key_ref)) { + ret = PTR_ERR(key_ref); + goto error; + } + + key = key_ref_to_ptr(key_ref); + + down_write(&key->sem); + + /* If we're not the sysadmin, we can only change a key that we own */ + ret = -EACCES; + if (capable(CAP_SYS_ADMIN) || uid_eq(key->uid, current_fsuid())) + ret = key_change_acl(key, &new_ace); + up_write(&key->sem); + key_put(key); +error: + return ret; +} diff --git a/security/keys/persistent.c b/security/keys/persistent.c index d0cb5b32eff7..8171c90d4c9a 100644 --- a/security/keys/persistent.c +++ b/security/keys/persistent.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* General persistent per-UID keyrings register * * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #include <linux/user_namespace.h> @@ -16,6 +12,27 @@ unsigned persistent_keyring_expiry = 3 * 24 * 3600; /* Expire after 3 days of non-use */ +static struct key_acl persistent_register_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_SEARCH | KEY_ACE_WRITE), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), + } +}; + +static struct key_acl persistent_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | + KEY_ACE_SEARCH | KEY_ACE_LINK | + KEY_ACE_CLEAR | KEY_ACE_INVAL), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), + } +}; + /* * Create the persistent keyring register for the current user namespace. * @@ -26,8 +43,7 @@ static int key_create_persistent_register(struct user_namespace *ns) struct key *reg = keyring_alloc(".persistent_register", KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ), + &persistent_register_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); if (IS_ERR(reg)) return PTR_ERR(reg); @@ -60,8 +76,7 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid, persistent = keyring_alloc(index_key->description, uid, INVALID_GID, current_cred(), - ((KEY_POS_ALL & ~KEY_POS_SETATTR) | - KEY_USR_VIEW | KEY_USR_READ), + &persistent_keyring_acl, KEY_ALLOC_NOT_IN_QUOTA, NULL, ns->persistent_keyring_register); if (IS_ERR(persistent)) @@ -84,15 +99,17 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, long ret; /* Look in the register if it exists */ + memset(&index_key, 0, sizeof(index_key)); index_key.type = &key_type_keyring; index_key.description = buf; index_key.desc_len = sprintf(buf, "_persistent.%u", from_kuid(ns, uid)); + key_set_index_key(&index_key); if (ns->persistent_keyring_register) { reg_ref = make_key_ref(ns->persistent_keyring_register, true); - down_read(&ns->persistent_keyring_register_sem); + down_read(&ns->keyring_sem); persistent_ref = find_key_to_update(reg_ref, &index_key); - up_read(&ns->persistent_keyring_register_sem); + up_read(&ns->keyring_sem); if (persistent_ref) goto found; @@ -101,9 +118,9 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, /* It wasn't in the register, so we'll need to create it. We might * also need to create the register. */ - down_write(&ns->persistent_keyring_register_sem); + down_write(&ns->keyring_sem); persistent_ref = key_create_persistent(ns, uid, &index_key); - up_write(&ns->persistent_keyring_register_sem); + up_write(&ns->keyring_sem); if (!IS_ERR(persistent_ref)) goto found; diff --git a/security/keys/proc.c b/security/keys/proc.c index 78ac305d715e..b394ad1e874b 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* procfs files for key database enumeration * * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/init.h> @@ -114,11 +110,13 @@ static struct key *find_ge_key(struct seq_file *p, key_serial_t id) } static void *proc_keys_start(struct seq_file *p, loff_t *_pos) + __acquires(rcu) __acquires(key_serial_lock) { key_serial_t pos = *_pos; struct key *key; + rcu_read_lock(); spin_lock(&key_serial_lock); if (*_pos > INT_MAX) @@ -148,12 +146,15 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) static void proc_keys_stop(struct seq_file *p, void *v) __releases(key_serial_lock) + __releases(rcu) { spin_unlock(&key_serial_lock); + rcu_read_unlock(); } static int proc_keys_show(struct seq_file *m, void *v) { + const struct key_acl *acl; struct rb_node *_p = v; struct key *key = rb_entry(_p, struct key, serial_node); unsigned long flags; @@ -161,6 +162,7 @@ static int proc_keys_show(struct seq_file *m, void *v) time64_t now, expiry; char xbuf[16]; short state; + bool check_pos; u64 timo; int rc; @@ -170,16 +172,19 @@ static int proc_keys_show(struct seq_file *m, void *v) .match_data.cmp = lookup_user_key_possessed, .match_data.raw_data = key, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .flags = KEYRING_SEARCH_NO_STATE_CHECK, + .flags = (KEYRING_SEARCH_NO_STATE_CHECK | + KEYRING_SEARCH_RECURSE), }; - key_ref = make_key_ref(key, 0); + acl = rcu_dereference(key->acl); + check_pos = acl->possessor_viewable; /* determine if the key is possessed by this process (a test we can * skip if the key does not indicate the possessor can view it */ - if (key->perm & KEY_POS_VIEW) { - skey_ref = search_my_process_keyrings(&ctx); + key_ref = make_key_ref(key, 0); + if (check_pos) { + skey_ref = search_cred_keyrings_rcu(&ctx); if (!IS_ERR(skey_ref)) { key_ref_put(skey_ref); key_ref = make_key_ref(key, 1); @@ -189,12 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v) /* check whether the current task is allowed to view the key */ rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); if (rc < 0) - return 0; + goto out; now = ktime_get_real_seconds(); - rcu_read_lock(); - /* come up with a suitable timeout value */ expiry = READ_ONCE(key->expiry); if (expiry == 0) { @@ -233,7 +236,7 @@ static int proc_keys_show(struct seq_file *m, void *v) showflag(flags, 'i', KEY_FLAG_INVALIDATED), refcount_read(&key->usage), xbuf, - key->perm, + key_acl_to_perm(acl), from_kuid_munged(seq_user_ns(m), key->uid), from_kgid_munged(seq_user_ns(m), key->gid), key->type->name); @@ -244,7 +247,7 @@ static int proc_keys_show(struct seq_file *m, void *v) key->type->describe(key, m); seq_putc(m, '\n'); - rcu_read_unlock(); +out: return 0; } diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index f05f7125a7d5..aa3bfcadbc66 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Manage a process's keyrings * * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/init.h> @@ -19,15 +15,13 @@ #include <linux/security.h> #include <linux/user_namespace.h> #include <linux/uaccess.h> +#include <linux/init_task.h> #include <keys/request_key_auth-type.h> #include "internal.h" /* Session keyring create vs join semaphore */ static DEFINE_MUTEX(key_session_mutex); -/* User keyring creation semaphore */ -static DEFINE_MUTEX(key_user_keyring_mutex); - /* The root user's tracking struct */ struct key_user root_key_user = { .usage = REFCOUNT_INIT(3), @@ -38,100 +32,222 @@ struct key_user root_key_user = { .uid = GLOBAL_ROOT_UID, }; +static struct key_acl user_reg_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .possessor_viewable = true, + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_WRITE | KEY_ACE_SEARCH), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), + } +}; + +static struct key_acl user_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .possessor_viewable = true, + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_WRITE | + KEY_ACE_SEARCH | KEY_ACE_LINK), + KEY_OWNER_ACE(KEY_ACE__PERMS & ~(KEY_ACE_JOIN | KEY_ACE_SET_SECURITY)), + } +}; + +static struct key_acl session_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .possessor_viewable = true, + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~KEY_ACE_JOIN), + KEY_OWNER_ACE(KEY_ACE_VIEW | KEY_ACE_READ), + } +}; + +static struct key_acl thread_and_process_keyring_acl = { + .usage = REFCOUNT_INIT(1), + .possessor_viewable = true, + .nr_ace = 2, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE__PERMS & ~(KEY_ACE_JOIN | KEY_ACE_SET_SECURITY)), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; + /* - * Install the user and user session keyrings for the current process's UID. + * Get or create a user register keyring. */ -int install_user_keyrings(void) +static struct key *get_user_register(struct user_namespace *user_ns) { - struct user_struct *user; - const struct cred *cred; - struct key *uid_keyring, *session_keyring; - key_perm_t user_keyring_perm; - char buf[20]; - int ret; - uid_t uid; + struct key *reg_keyring = READ_ONCE(user_ns->user_keyring_register); - user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; - cred = current_cred(); - user = cred->user; - uid = from_kuid(cred->user_ns, user->uid); + if (reg_keyring) + return reg_keyring; - kenter("%p{%u}", user, uid); + down_write(&user_ns->keyring_sem); - if (READ_ONCE(user->uid_keyring) && READ_ONCE(user->session_keyring)) { - kleave(" = 0 [exist]"); - return 0; + /* Make sure there's a register keyring. It gets owned by the + * user_namespace's owner. + */ + reg_keyring = user_ns->user_keyring_register; + if (!reg_keyring) { + reg_keyring = keyring_alloc(".user_reg", + user_ns->owner, INVALID_GID, + &init_cred, &user_reg_keyring_acl, + 0, NULL, NULL); + if (!IS_ERR(reg_keyring)) + smp_store_release(&user_ns->user_keyring_register, + reg_keyring); } - mutex_lock(&key_user_keyring_mutex); - ret = 0; + up_write(&user_ns->keyring_sem); + + /* We don't return a ref since the keyring is pinned by the user_ns */ + return reg_keyring; +} + +/* + * Look up the user and user session keyrings for the current process's UID, + * creating them if they don't exist. + */ +int look_up_user_keyrings(struct key **_user_keyring, + struct key **_user_session_keyring) +{ + const struct cred *cred = current_cred(); + struct user_namespace *user_ns = current_user_ns(); + struct key *reg_keyring, *uid_keyring, *session_keyring; + key_ref_t uid_keyring_r, session_keyring_r; + uid_t uid = from_kuid(user_ns, cred->user->uid); + char buf[20]; + int ret; + + kenter("%u", uid); + + reg_keyring = get_user_register(user_ns); + if (IS_ERR(reg_keyring)) + return PTR_ERR(reg_keyring); - if (!user->uid_keyring) { - /* get the UID-specific keyring - * - there may be one in existence already as it may have been - * pinned by a session, but the user_struct pointing to it - * may have been destroyed by setuid */ - sprintf(buf, "_uid.%u", uid); + down_write(&user_ns->keyring_sem); + ret = 0; - uid_keyring = find_keyring_by_name(buf, true); + /* Get the user keyring. Note that there may be one in existence + * already as it may have been pinned by a session, but the user_struct + * pointing to it may have been destroyed by setuid. + */ + snprintf(buf, sizeof(buf), "_uid.%u", uid); + uid_keyring_r = keyring_search(make_key_ref(reg_keyring, true), + &key_type_keyring, buf, false); + kdebug("_uid %p", uid_keyring_r); + if (uid_keyring_r == ERR_PTR(-EAGAIN)) { + uid_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID, + cred, &user_keyring_acl, + KEY_ALLOC_UID_KEYRING | + KEY_ALLOC_IN_QUOTA, + NULL, reg_keyring); if (IS_ERR(uid_keyring)) { - uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, - cred, user_keyring_perm, - KEY_ALLOC_UID_KEYRING | - KEY_ALLOC_IN_QUOTA, - NULL, NULL); - if (IS_ERR(uid_keyring)) { - ret = PTR_ERR(uid_keyring); - goto error; - } + ret = PTR_ERR(uid_keyring); + goto error; } + } else if (IS_ERR(uid_keyring_r)) { + ret = PTR_ERR(uid_keyring_r); + goto error; + } else { + uid_keyring = key_ref_to_ptr(uid_keyring_r); + } - /* get a default session keyring (which might also exist - * already) */ - sprintf(buf, "_uid_ses.%u", uid); - - session_keyring = find_keyring_by_name(buf, true); + /* Get a default session keyring (which might also exist already) */ + snprintf(buf, sizeof(buf), "_uid_ses.%u", uid); + session_keyring_r = keyring_search(make_key_ref(reg_keyring, true), + &key_type_keyring, buf, false); + kdebug("_uid_ses %p", session_keyring_r); + if (session_keyring_r == ERR_PTR(-EAGAIN)) { + session_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID, + cred, &user_keyring_acl, + KEY_ALLOC_UID_KEYRING | + KEY_ALLOC_IN_QUOTA, + NULL, NULL); if (IS_ERR(session_keyring)) { - session_keyring = - keyring_alloc(buf, user->uid, INVALID_GID, - cred, user_keyring_perm, - KEY_ALLOC_UID_KEYRING | - KEY_ALLOC_IN_QUOTA, - NULL, NULL); - if (IS_ERR(session_keyring)) { - ret = PTR_ERR(session_keyring); - goto error_release; - } - - /* we install a link from the user session keyring to - * the user keyring */ - ret = key_link(session_keyring, uid_keyring); - if (ret < 0) - goto error_release_both; + ret = PTR_ERR(session_keyring); + goto error_release; } - /* install the keyrings */ - /* paired with READ_ONCE() */ - smp_store_release(&user->uid_keyring, uid_keyring); - /* paired with READ_ONCE() */ - smp_store_release(&user->session_keyring, session_keyring); + /* We install a link from the user session keyring to + * the user keyring. + */ + ret = key_link(session_keyring, uid_keyring); + if (ret < 0) + goto error_release_session; + + /* And only then link the user-session keyring to the + * register. + */ + ret = key_link(reg_keyring, session_keyring); + if (ret < 0) + goto error_release_session; + } else if (IS_ERR(session_keyring_r)) { + ret = PTR_ERR(session_keyring_r); + goto error_release; + } else { + session_keyring = key_ref_to_ptr(session_keyring_r); } - mutex_unlock(&key_user_keyring_mutex); + up_write(&user_ns->keyring_sem); + + if (_user_session_keyring) + *_user_session_keyring = session_keyring; + else + key_put(session_keyring); + if (_user_keyring) + *_user_keyring = uid_keyring; + else + key_put(uid_keyring); kleave(" = 0"); return 0; -error_release_both: +error_release_session: key_put(session_keyring); error_release: key_put(uid_keyring); error: - mutex_unlock(&key_user_keyring_mutex); + up_write(&user_ns->keyring_sem); kleave(" = %d", ret); return ret; } /* + * Get the user session keyring if it exists, but don't create it if it + * doesn't. + */ +struct key *get_user_session_keyring_rcu(const struct cred *cred) +{ + struct key *reg_keyring = READ_ONCE(cred->user_ns->user_keyring_register); + key_ref_t session_keyring_r; + char buf[20]; + + struct keyring_search_context ctx = { + .index_key.type = &key_type_keyring, + .index_key.description = buf, + .cred = cred, + .match_data.cmp = key_default_cmp, + .match_data.raw_data = buf, + .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, + .flags = KEYRING_SEARCH_DO_STATE_CHECK, + }; + + if (!reg_keyring) + return NULL; + + ctx.index_key.desc_len = snprintf(buf, sizeof(buf), "_uid_ses.%u", + from_kuid(cred->user_ns, + cred->user->uid)); + + session_keyring_r = keyring_search_rcu(make_key_ref(reg_keyring, true), + &ctx); + if (IS_ERR(session_keyring_r)) + return NULL; + return key_ref_to_ptr(session_keyring_r); +} + +/* * Install a thread keyring to the given credentials struct if it didn't have * one already. This is allowed to overrun the quota. * @@ -145,7 +261,7 @@ int install_thread_keyring_to_cred(struct cred *new) return 0; keyring = keyring_alloc("_tid", new->uid, new->gid, new, - KEY_POS_ALL | KEY_USR_VIEW, + &thread_and_process_keyring_acl, KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); if (IS_ERR(keyring)) @@ -192,7 +308,7 @@ int install_process_keyring_to_cred(struct cred *new) return 0; keyring = keyring_alloc("_pid", new->uid, new->gid, new, - KEY_POS_ALL | KEY_USR_VIEW, + &thread_and_process_keyring_acl, KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); if (IS_ERR(keyring)) @@ -247,8 +363,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) flags = KEY_ALLOC_IN_QUOTA; keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, - KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, - flags, NULL, NULL); + &session_keyring_acl, flags, NULL, NULL); if (IS_ERR(keyring)) return PTR_ERR(keyring); } else { @@ -293,34 +408,33 @@ static int install_session_keyring(struct key *keyring) /* * Handle the fsuid changing. */ -void key_fsuid_changed(struct task_struct *tsk) +void key_fsuid_changed(struct cred *new_cred) { /* update the ownership of the thread keyring */ - BUG_ON(!tsk->cred); - if (tsk->cred->thread_keyring) { - down_write(&tsk->cred->thread_keyring->sem); - tsk->cred->thread_keyring->uid = tsk->cred->fsuid; - up_write(&tsk->cred->thread_keyring->sem); + if (new_cred->thread_keyring) { + down_write(&new_cred->thread_keyring->sem); + new_cred->thread_keyring->uid = new_cred->fsuid; + up_write(&new_cred->thread_keyring->sem); } } /* * Handle the fsgid changing. */ -void key_fsgid_changed(struct task_struct *tsk) +void key_fsgid_changed(struct cred *new_cred) { /* update the ownership of the thread keyring */ - BUG_ON(!tsk->cred); - if (tsk->cred->thread_keyring) { - down_write(&tsk->cred->thread_keyring->sem); - tsk->cred->thread_keyring->gid = tsk->cred->fsgid; - up_write(&tsk->cred->thread_keyring->sem); + if (new_cred->thread_keyring) { + down_write(&new_cred->thread_keyring->sem); + new_cred->thread_keyring->gid = new_cred->fsgid; + up_write(&new_cred->thread_keyring->sem); } } /* * Search the process keyrings attached to the supplied cred for the first - * matching key. + * matching key under RCU conditions (the caller must be holding the RCU read + * lock). * * The search criteria are the type and the match function. The description is * given to the match function as a parameter, but doesn't otherwise influence @@ -339,8 +453,9 @@ void key_fsgid_changed(struct task_struct *tsk) * In the case of a successful return, the possession attribute is set on the * returned key reference. */ -key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) +key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx) { + struct key *user_session; key_ref_t key_ref, ret, err; const struct cred *cred = ctx->cred; @@ -357,7 +472,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) /* search the thread keyring first */ if (cred->thread_keyring) { - key_ref = keyring_search_aux( + key_ref = keyring_search_rcu( make_key_ref(cred->thread_keyring, 1), ctx); if (!IS_ERR(key_ref)) goto found; @@ -375,7 +490,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) /* search the process keyring second */ if (cred->process_keyring) { - key_ref = keyring_search_aux( + key_ref = keyring_search_rcu( make_key_ref(cred->process_keyring, 1), ctx); if (!IS_ERR(key_ref)) goto found; @@ -396,7 +511,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) /* search the session keyring */ if (cred->session_keyring) { - key_ref = keyring_search_aux( + key_ref = keyring_search_rcu( make_key_ref(cred->session_keyring, 1), ctx); if (!IS_ERR(key_ref)) @@ -416,10 +531,11 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) } } /* or search the user-session keyring */ - else if (READ_ONCE(cred->user->session_keyring)) { - key_ref = keyring_search_aux( - make_key_ref(READ_ONCE(cred->user->session_keyring), 1), - ctx); + else if ((user_session = get_user_session_keyring_rcu(cred))) { + key_ref = keyring_search_rcu(make_key_ref(user_session, 1), + ctx); + key_put(user_session); + if (!IS_ERR(key_ref)) goto found; @@ -450,16 +566,16 @@ found: * the keys attached to the assumed authorisation key using its credentials if * one is available. * - * Return same as search_my_process_keyrings(). + * The caller must be holding the RCU read lock. + * + * Return same as search_cred_keyrings_rcu(). */ -key_ref_t search_process_keyrings(struct keyring_search_context *ctx) +key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx) { struct request_key_auth *rka; key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; - might_sleep(); - - key_ref = search_my_process_keyrings(ctx); + key_ref = search_cred_keyrings_rcu(ctx); if (!IS_ERR(key_ref)) goto found; err = key_ref; @@ -474,24 +590,17 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx) ) { const struct cred *cred = ctx->cred; - /* defend against the auth key being revoked */ - down_read(&cred->request_key_auth->sem); - - if (key_validate(ctx->cred->request_key_auth) == 0) { + if (key_validate(cred->request_key_auth) == 0) { rka = ctx->cred->request_key_auth->payload.data[0]; + //// was search_process_keyrings() [ie. recursive] ctx->cred = rka->cred; - key_ref = search_process_keyrings(ctx); + key_ref = search_cred_keyrings_rcu(ctx); ctx->cred = cred; - up_read(&cred->request_key_auth->sem); - if (!IS_ERR(key_ref)) goto found; - ret = key_ref; - } else { - up_read(&cred->request_key_auth->sem); } } @@ -506,7 +615,6 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx) found: return key_ref; } - /* * See if the key we're looking at is the target key. */ @@ -535,15 +643,16 @@ bool lookup_user_key_possessed(const struct key *key, * returned key reference. */ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, - key_perm_t perm) + unsigned int desired_perm) { struct keyring_search_context ctx = { .match_data.cmp = lookup_user_key_possessed, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .flags = KEYRING_SEARCH_NO_STATE_CHECK, + .flags = (KEYRING_SEARCH_NO_STATE_CHECK | + KEYRING_SEARCH_RECURSE), }; struct request_key_auth *rka; - struct key *key; + struct key *key, *user_session; key_ref_t key_ref, skey_ref; int ret; @@ -592,20 +701,20 @@ try_again: if (!ctx.cred->session_keyring) { /* always install a session keyring upon access if one * doesn't exist yet */ - ret = install_user_keyrings(); + ret = look_up_user_keyrings(NULL, &user_session); if (ret < 0) goto error; if (lflags & KEY_LOOKUP_CREATE) ret = join_session_keyring(NULL); else - ret = install_session_keyring( - ctx.cred->user->session_keyring); + ret = install_session_keyring(user_session); + key_put(user_session); if (ret < 0) goto error; goto reget_creds; - } else if (ctx.cred->session_keyring == - READ_ONCE(ctx.cred->user->session_keyring) && + } else if (test_bit(KEY_FLAG_UID_KEYRING, + &ctx.cred->session_keyring->flags) && lflags & KEY_LOOKUP_CREATE) { ret = join_session_keyring(NULL); if (ret < 0) @@ -619,26 +728,16 @@ try_again: break; case KEY_SPEC_USER_KEYRING: - if (!READ_ONCE(ctx.cred->user->uid_keyring)) { - ret = install_user_keyrings(); - if (ret < 0) - goto error; - } - - key = ctx.cred->user->uid_keyring; - __key_get(key); + ret = look_up_user_keyrings(&key, NULL); + if (ret < 0) + goto error; key_ref = make_key_ref(key, 1); break; case KEY_SPEC_USER_SESSION_KEYRING: - if (!READ_ONCE(ctx.cred->user->session_keyring)) { - ret = install_user_keyrings(); - if (ret < 0) - goto error; - } - - key = ctx.cred->user->session_keyring; - __key_get(key); + ret = look_up_user_keyrings(NULL, &key); + if (ret < 0) + goto error; key_ref = make_key_ref(key, 1); break; @@ -690,12 +789,12 @@ try_again: key_ref = make_key_ref(key, 0); /* check to see if we possess the key */ - ctx.index_key.type = key->type; - ctx.index_key.description = key->description; - ctx.index_key.desc_len = strlen(key->description); + ctx.index_key = key->index_key; ctx.match_data.raw_data = key; kdebug("check possessed"); - skey_ref = search_process_keyrings(&ctx); + rcu_read_lock(); + skey_ref = search_process_keyrings_rcu(&ctx); + rcu_read_unlock(); kdebug("possessed=%p", skey_ref); if (!IS_ERR(skey_ref)) { @@ -719,12 +818,12 @@ try_again: case -ERESTARTSYS: goto invalid_key; default: - if (perm) + if (desired_perm) goto invalid_key; case 0: break; } - } else if (perm) { + } else if (desired_perm) { ret = key_validate(key); if (ret < 0) goto invalid_key; @@ -736,9 +835,11 @@ try_again: goto invalid_key; /* check the permissions */ - ret = key_task_permission(key_ref, ctx.cred, perm); - if (ret < 0) - goto invalid_key; + if (desired_perm) { + ret = key_task_permission(key_ref, ctx.cred, desired_perm); + if (ret < 0) + goto invalid_key; + } key->last_used_at = ktime_get_real_seconds(); @@ -803,13 +904,13 @@ long join_session_keyring(const char *name) if (PTR_ERR(keyring) == -ENOKEY) { /* not found - try and create a new one */ keyring = keyring_alloc( - name, old->uid, old->gid, old, - KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, + name, old->uid, old->gid, old, &joinable_keyring_acl, KEY_ALLOC_IN_QUOTA, NULL, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; } + goto no_perm_test; } else if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error2; @@ -818,6 +919,12 @@ long join_session_keyring(const char *name) goto error3; } + ret = key_task_permission(make_key_ref(keyring, false), old, + KEY_NEED_JOIN); + if (ret < 0) + goto error3; + +no_perm_test: /* we've got a keyring - now to install it */ ret = install_session_keyring_to_cred(new, keyring); if (ret < 0) @@ -887,7 +994,7 @@ void key_change_session_keyring(struct callback_head *twork) */ static int __init init_root_keyring(void) { - return install_user_keyrings(); + return look_up_user_keyrings(NULL, NULL); } late_initcall(init_root_keyring); diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 75d87f9e0f49..46c5187ce03f 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Request a key from userspace * * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * * See Documentation/security/keys/request-key.rst */ @@ -17,14 +13,40 @@ #include <linux/err.h> #include <linux/keyctl.h> #include <linux/slab.h> +#include <net/net_namespace.h> #include "internal.h" #include <keys/request_key_auth-type.h> #define key_negative_timeout 60 /* default timeout on a negative key's existence */ +static struct key *check_cached_key(struct keyring_search_context *ctx) +{ +#ifdef CONFIG_KEYS_REQUEST_CACHE + struct key *key = current->cached_requested_key; + + if (key && + ctx->match_data.cmp(key, &ctx->match_data) && + !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | + (1 << KEY_FLAG_REVOKED)))) + return key_get(key); +#endif + return NULL; +} + +static void cache_requested_key(struct key *key) +{ +#ifdef CONFIG_KEYS_REQUEST_CACHE + struct task_struct *t = current; + + key_put(t->cached_requested_key); + t->cached_requested_key = key_get(key); + set_tsk_thread_flag(t, TIF_NOTIFY_RESUME); +#endif +} + /** * complete_request_key - Complete the construction of a key. - * @auth_key: The authorisation key. + * @authkey: The authorisation key. * @error: The success or failute of the construction. * * Complete the attempt to construct a key. The key will be negated @@ -96,7 +118,7 @@ static int call_sbin_request_key(struct key *authkey, void *aux) struct request_key_auth *rka = get_request_key_auth(authkey); const struct cred *cred = current_cred(); key_serial_t prkey, sskey; - struct key *key = rka->target_key, *keyring, *session; + struct key *key = rka->target_key, *keyring, *session, *user_session; char *argv[9], *envp[3], uid_str[12], gid_str[12]; char key_str[12], keyring_str[3][12]; char desc[20]; @@ -104,17 +126,16 @@ static int call_sbin_request_key(struct key *authkey, void *aux) kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op); - ret = install_user_keyrings(); + ret = look_up_user_keyrings(NULL, &user_session); if (ret < 0) - goto error_alloc; + goto error_us; /* allocate a new session keyring */ sprintf(desc, "_req.%u", key->serial); cred = get_current_cred(); keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, - KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, - KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); + NULL, KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL); put_cred(cred); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); @@ -144,7 +165,7 @@ static int call_sbin_request_key(struct key *authkey, void *aux) session = cred->session_keyring; if (!session) - session = cred->user->session_keyring; + session = user_session; sskey = session->serial; sprintf(keyring_str[2], "%d", sskey); @@ -186,6 +207,8 @@ error_link: key_put(keyring); error_alloc: + key_put(user_session); +error_us: complete_request_key(authkey, ret); kleave(" = %d", ret); return ret; @@ -222,7 +245,7 @@ static int construct_key(struct key *key, const void *callout_info, /* check that the actor called complete_request_key() prior to * returning an error */ WARN_ON(ret < 0 && - !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); + !test_bit(KEY_FLAG_INVALIDATED, &authkey->flags)); key_put(authkey); kleave(" = %d", ret); @@ -292,13 +315,15 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) /* fall through */ case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: - dest_keyring = - key_get(READ_ONCE(cred->user->session_keyring)); + ret = look_up_user_keyrings(NULL, &dest_keyring); + if (ret < 0) + return ret; break; case KEY_REQKEY_DEFL_USER_KEYRING: - dest_keyring = - key_get(READ_ONCE(cred->user->uid_keyring)); + ret = look_up_user_keyrings(&dest_keyring, NULL); + if (ret < 0) + return ret; break; case KEY_REQKEY_DEFL_GROUP_KEYRING: @@ -341,11 +366,11 @@ static int construct_alloc_key(struct keyring_search_context *ctx, struct key *dest_keyring, unsigned long flags, struct key_user *user, + struct key_acl *acl, struct key **_key) { - struct assoc_array_edit *edit; + struct assoc_array_edit *edit = NULL; struct key *key; - key_perm_t perm; key_ref_t key_ref; int ret; @@ -355,23 +380,18 @@ static int construct_alloc_key(struct keyring_search_context *ctx, *_key = NULL; mutex_lock(&user->cons_lock); - perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; - perm |= KEY_USR_VIEW; - if (ctx->index_key.type->read) - perm |= KEY_POS_READ; - if (ctx->index_key.type == &key_type_keyring || - ctx->index_key.type->update) - perm |= KEY_POS_WRITE; - key = key_alloc(ctx->index_key.type, ctx->index_key.description, ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, - perm, flags, NULL); + acl, flags, NULL); if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); if (dest_keyring) { + ret = __key_link_lock(dest_keyring, &ctx->index_key); + if (ret < 0) + goto link_lock_failed; ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit); if (ret < 0) goto link_prealloc_failed; @@ -382,7 +402,9 @@ static int construct_alloc_key(struct keyring_search_context *ctx, * waited for locks */ mutex_lock(&key_construction_mutex); - key_ref = search_process_keyrings(ctx); + rcu_read_lock(); + key_ref = search_process_keyrings_rcu(ctx); + rcu_read_unlock(); if (!IS_ERR(key_ref)) goto key_already_present; @@ -423,6 +445,8 @@ link_check_failed: return ret; link_prealloc_failed: + __key_link_end(dest_keyring, &ctx->index_key, edit); +link_lock_failed: mutex_unlock(&user->cons_lock); key_put(key); kleave(" = %d [prelink]", ret); @@ -441,6 +465,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, const char *callout_info, size_t callout_len, void *aux, + struct key_acl *acl, struct key *dest_keyring, unsigned long flags) { @@ -463,7 +488,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, goto error_put_dest_keyring; } - ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); + ret = construct_alloc_key(ctx, dest_keyring, flags, user, acl, &key); key_user_put(user); if (ret == 0) { @@ -497,16 +522,19 @@ error: * request_key_and_link - Request a key and cache it in a keyring. * @type: The type of key we want. * @description: The searchable description of the key. + * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. + * @acl: The ACL to attach if a new key is created. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * - * A key matching the specified criteria is searched for in the process's - * keyrings and returned with its usage count incremented if found. Otherwise, - * if callout_info is not NULL, a key will be allocated and some service - * (probably in userspace) will be asked to instantiate it. + * A key matching the specified criteria (type, description, domain_tag) is + * searched for in the process's keyrings and returned with its usage count + * incremented if found. Otherwise, if callout_info is not NULL, a key will be + * allocated and some service (probably in userspace) will be asked to + * instantiate it. * * If successfully found or created, the key will be linked to the destination * keyring if one is provided. @@ -522,14 +550,17 @@ error: */ struct key *request_key_and_link(struct key_type *type, const char *description, + struct key_tag *domain_tag, const void *callout_info, size_t callout_len, void *aux, + struct key_acl *acl, struct key *dest_keyring, unsigned long flags) { struct keyring_search_context ctx = { .index_key.type = type, + .index_key.domain_tag = domain_tag, .index_key.description = description, .index_key.desc_len = strlen(description), .cred = current_cred(), @@ -537,7 +568,8 @@ struct key *request_key_and_link(struct key_type *type, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .flags = (KEYRING_SEARCH_DO_STATE_CHECK | - KEYRING_SEARCH_SKIP_EXPIRED), + KEYRING_SEARCH_SKIP_EXPIRED | + KEYRING_SEARCH_RECURSE), }; struct key *key; key_ref_t key_ref; @@ -555,10 +587,26 @@ struct key *request_key_and_link(struct key_type *type, } } + key = check_cached_key(&ctx); + if (key) + return key; + /* search all the process keyrings for a key */ - key_ref = search_process_keyrings(&ctx); + rcu_read_lock(); + key_ref = search_process_keyrings_rcu(&ctx); + rcu_read_unlock(); if (!IS_ERR(key_ref)) { + if (dest_keyring) { + ret = key_task_permission(key_ref, current_cred(), + KEY_NEED_LINK); + if (ret < 0) { + key_ref_put(key_ref); + key = ERR_PTR(ret); + goto error_free; + } + } + key = key_ref_to_ptr(key_ref); if (dest_keyring) { ret = key_link(dest_keyring, key); @@ -568,6 +616,9 @@ struct key *request_key_and_link(struct key_type *type, goto error_free; } } + + /* Only cache the key on immediate success */ + cache_requested_key(key); } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_CAST(key_ref); } else { @@ -578,7 +629,7 @@ struct key *request_key_and_link(struct key_type *type, goto error_free; key = construct_key_and_link(&ctx, callout_info, callout_len, - aux, dest_keyring, flags); + aux, acl, dest_keyring, flags); } error_free: @@ -616,10 +667,12 @@ int wait_for_key_construction(struct key *key, bool intr) EXPORT_SYMBOL(wait_for_key_construction); /** - * request_key - Request a key and wait for construction + * request_key_tag - Request a key and wait for construction * @type: Type of key. * @description: The searchable description of the key. + * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). + * @acl: The ACL to attach if a new key is created. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found, new keys are always allocated in the user's quota, @@ -629,9 +682,11 @@ EXPORT_SYMBOL(wait_for_key_construction); * Furthermore, it then works as wait_for_key_construction() to wait for the * completion of keys undergoing construction with a non-interruptible wait. */ -struct key *request_key(struct key_type *type, - const char *description, - const char *callout_info) +struct key *request_key_tag(struct key_type *type, + const char *description, + struct key_tag *domain_tag, + const char *callout_info, + struct key_acl *acl) { struct key *key; size_t callout_len = 0; @@ -639,8 +694,9 @@ struct key *request_key(struct key_type *type, if (callout_info) callout_len = strlen(callout_info); - key = request_key_and_link(type, description, callout_info, callout_len, - NULL, NULL, KEY_ALLOC_IN_QUOTA); + key = request_key_and_link(type, description, domain_tag, + callout_info, callout_len, + NULL, acl, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { @@ -650,15 +706,17 @@ struct key *request_key(struct key_type *type, } return key; } -EXPORT_SYMBOL(request_key); +EXPORT_SYMBOL(request_key_tag); /** * request_key_with_auxdata - Request a key with auxiliary data for the upcaller * @type: The type of key we want. * @description: The searchable description of the key. + * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. + * @acl: The ACL to attach if a new key is created. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found and new keys are always allocated in the user's quota. @@ -668,15 +726,18 @@ EXPORT_SYMBOL(request_key); */ struct key *request_key_with_auxdata(struct key_type *type, const char *description, + struct key_tag *domain_tag, const void *callout_info, size_t callout_len, - void *aux) + void *aux, + struct key_acl *acl) { struct key *key; int ret; - key = request_key_and_link(type, description, callout_info, callout_len, - aux, NULL, KEY_ALLOC_IN_QUOTA); + key = request_key_and_link(type, description, domain_tag, + callout_info, callout_len, + aux, acl, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { @@ -688,52 +749,55 @@ struct key *request_key_with_auxdata(struct key_type *type, } EXPORT_SYMBOL(request_key_with_auxdata); -/* - * request_key_async - Request a key (allow async construction) - * @type: Type of key. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @callout_len: The length of callout_info. +/** + * request_key_rcu - Request key from RCU-read-locked context + * @type: The type of key we want. + * @description: The name of the key we want. + * @domain_tag: The domain in which the key operates. * - * As for request_key_and_link() except that it does not add the returned key - * to a keyring if found, new keys are always allocated in the user's quota and - * no auxiliary data can be passed. + * Request a key from a context that we may not sleep in (such as RCU-mode + * pathwalk). Keys under construction are ignored. * - * The caller should call wait_for_key_construction() to wait for the - * completion of the returned key if it is still undergoing construction. + * Return a pointer to the found key if successful, -ENOKEY if we couldn't find + * a key or some other error if the key found was unsuitable or inaccessible. */ -struct key *request_key_async(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len) +struct key *request_key_rcu(struct key_type *type, + const char *description, + struct key_tag *domain_tag) { - return request_key_and_link(type, description, callout_info, - callout_len, NULL, NULL, - KEY_ALLOC_IN_QUOTA); -} -EXPORT_SYMBOL(request_key_async); + struct keyring_search_context ctx = { + .index_key.type = type, + .index_key.domain_tag = domain_tag, + .index_key.description = description, + .index_key.desc_len = strlen(description), + .cred = current_cred(), + .match_data.cmp = key_default_cmp, + .match_data.raw_data = description, + .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, + .flags = (KEYRING_SEARCH_DO_STATE_CHECK | + KEYRING_SEARCH_SKIP_EXPIRED), + }; + struct key *key; + key_ref_t key_ref; -/* - * request a key with auxiliary data for the upcaller (allow async construction) - * @type: Type of key. - * @description: The searchable description of the key. - * @callout_info: The data to pass to the instantiation upcall (or NULL). - * @callout_len: The length of callout_info. - * @aux: Auxiliary data for the upcall. - * - * As for request_key_and_link() except that it does not add the returned key - * to a keyring if found and new keys are always allocated in the user's quota. - * - * The caller should call wait_for_key_construction() to wait for the - * completion of the returned key if it is still undergoing construction. - */ -struct key *request_key_async_with_auxdata(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux) -{ - return request_key_and_link(type, description, callout_info, - callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); + kenter("%s,%s", type->name, description); + + key = check_cached_key(&ctx); + if (key) + return key; + + /* search all the process keyrings for a key */ + key_ref = search_process_keyrings_rcu(&ctx); + if (IS_ERR(key_ref)) { + key = ERR_CAST(key_ref); + if (PTR_ERR(key_ref) == -EAGAIN) + key = ERR_PTR(-ENOKEY); + } else { + key = key_ref_to_ptr(key_ref); + cache_requested_key(key); + } + + kleave(" = %p", key); + return key; } -EXPORT_SYMBOL(request_key_async_with_auxdata); +EXPORT_SYMBOL(request_key_rcu); diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index bda6201c6c45..27e437d94b81 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Request key authorisation token key definition. * * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * * See Documentation/security/keys/request-key.rst */ @@ -28,6 +24,17 @@ static void request_key_auth_revoke(struct key *); static void request_key_auth_destroy(struct key *); static long request_key_auth_read(const struct key *, char __user *, size_t); +static struct key_acl request_key_auth_acl = { + .usage = REFCOUNT_INIT(1), + .nr_ace = 2, + .possessor_viewable = true, + .aces = { + KEY_POSSESSOR_ACE(KEY_ACE_VIEW | KEY_ACE_READ | KEY_ACE_SEARCH | + KEY_ACE_LINK), + KEY_OWNER_ACE(KEY_ACE_VIEW), + } +}; + /* * The request-key authorisation key type definition. */ @@ -58,7 +65,7 @@ static void request_key_auth_free_preparse(struct key_preparsed_payload *prep) static int request_key_auth_instantiate(struct key *key, struct key_preparsed_payload *prep) { - key->payload.data[0] = (struct request_key_auth *)prep->data; + rcu_assign_keypointer(key, (struct request_key_auth *)prep->data); return 0; } @@ -68,7 +75,7 @@ static int request_key_auth_instantiate(struct key *key, static void request_key_auth_describe(const struct key *key, struct seq_file *m) { - struct request_key_auth *rka = get_request_key_auth(key); + struct request_key_auth *rka = dereference_key_rcu(key); seq_puts(m, "key:"); seq_puts(m, key->description); @@ -83,7 +90,7 @@ static void request_key_auth_describe(const struct key *key, static long request_key_auth_read(const struct key *key, char __user *buffer, size_t buflen) { - struct request_key_auth *rka = get_request_key_auth(key); + struct request_key_auth *rka = dereference_key_locked(key); size_t datalen; long ret; @@ -102,23 +109,6 @@ static long request_key_auth_read(const struct key *key, return ret; } -/* - * Handle revocation of an authorisation token key. - * - * Called with the key sem write-locked. - */ -static void request_key_auth_revoke(struct key *key) -{ - struct request_key_auth *rka = get_request_key_auth(key); - - kenter("{%d}", key->serial); - - if (rka->cred) { - put_cred(rka->cred); - rka->cred = NULL; - } -} - static void free_request_key_auth(struct request_key_auth *rka) { if (!rka) @@ -132,15 +122,42 @@ static void free_request_key_auth(struct request_key_auth *rka) } /* + * Dispose of the request_key_auth record under RCU conditions + */ +static void request_key_auth_rcu_disposal(struct rcu_head *rcu) +{ + struct request_key_auth *rka = + container_of(rcu, struct request_key_auth, rcu); + + free_request_key_auth(rka); +} + +/* + * Handle revocation of an authorisation token key. + * + * Called with the key sem write-locked. + */ +static void request_key_auth_revoke(struct key *key) +{ + struct request_key_auth *rka = dereference_key_locked(key); + + kenter("{%d}", key->serial); + rcu_assign_keypointer(key, NULL); + call_rcu(&rka->rcu, request_key_auth_rcu_disposal); +} + +/* * Destroy an instantiation authorisation token key. */ static void request_key_auth_destroy(struct key *key) { - struct request_key_auth *rka = get_request_key_auth(key); + struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0); kenter("{%d}", key->serial); - - free_request_key_auth(rka); + if (rka) { + rcu_assign_keypointer(key, NULL); + call_rcu(&rka->rcu, request_key_auth_rcu_disposal); + } } /* @@ -152,7 +169,7 @@ struct key *request_key_auth_new(struct key *target, const char *op, struct key *dest_keyring) { struct request_key_auth *rka, *irka; - const struct cred *cred = current->cred; + const struct cred *cred = current_cred(); struct key *authkey = NULL; char desc[20]; int ret = -ENOMEM; @@ -204,8 +221,8 @@ struct key *request_key_auth_new(struct key *target, const char *op, authkey = key_alloc(&key_type_request_key_auth, desc, cred->fsuid, cred->fsgid, cred, - KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | - KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); + &request_key_auth_acl, + KEY_ALLOC_NOT_IN_QUOTA, NULL); if (IS_ERR(authkey)) { ret = PTR_ERR(authkey); goto error_free_rka; @@ -242,14 +259,17 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, - .flags = KEYRING_SEARCH_DO_STATE_CHECK, + .flags = (KEYRING_SEARCH_DO_STATE_CHECK | + KEYRING_SEARCH_RECURSE), }; struct key *authkey; key_ref_t authkey_ref; ctx.index_key.desc_len = sprintf(description, "%x", target_id); - authkey_ref = search_process_keyrings(&ctx); + rcu_read_lock(); + authkey_ref = search_process_keyrings_rcu(&ctx); + rcu_read_unlock(); if (IS_ERR(authkey_ref)) { authkey = ERR_CAST(authkey_ref); diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index b68faa1a5cfd..dd1e21fab827 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* Key management controls * * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #include <linux/key.h> diff --git a/security/keys/trusted.c b/security/keys/trusted.c index a75b2f0f1230..9a94672e7adc 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2010 IBM Corporation * * Author: * David Safford <safford@us.ibm.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * * See Documentation/security/keys/trusted-encrypted.rst */ diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 5666fe0352f7..6f12de4ce549 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* user_defined.c: user defined key type * * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ #include <linux/export.h> diff --git a/security/loadpin/Kconfig b/security/loadpin/Kconfig index a0d70d82b98e..91be65dec2ab 100644 --- a/security/loadpin/Kconfig +++ b/security/loadpin/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_LOADPIN bool "Pin load of kernel files (modules, fw, etc) to one filesystem" depends on SECURITY && BLOCK diff --git a/security/loadpin/Makefile b/security/loadpin/Makefile index c2d77f83037b..0ead1c3105fd 100644 --- a/security/loadpin/Makefile +++ b/security/loadpin/Makefile @@ -1 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SECURITY_LOADPIN) += loadpin.o diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 055fb0a64169..79131efa9634 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Module and Firmware Pinning Security Module * * Copyright 2011-2016 Google Inc. * * Author: Kees Cook <keescook@chromium.org> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) "LoadPin: " fmt diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 33028c098ef3..e40874373f2b 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * common LSM auditing functions * @@ -5,10 +6,6 @@ * Stephen Smalley, <sds@tycho.nsa.gov> * James Morris <jmorris@redhat.com> * Author : Etienne Basset, <etienne.basset@ensta.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/types.h> diff --git a/security/safesetid/Kconfig b/security/safesetid/Kconfig index 4f415c4e3f93..18b5fb90417b 100644 --- a/security/safesetid/Kconfig +++ b/security/safesetid/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_SAFESETID bool "Gate setid transitions to limit CAP_SET{U/G}ID capabilities" depends on SECURITY diff --git a/security/security.c b/security/security.c index 613a5c00e602..250ee2d76406 100644 --- a/security/security.c +++ b/security/security.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Security plug functions * @@ -5,11 +6,6 @@ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> * Copyright (C) 2016 Mellanox Technologies - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #define pr_fmt(fmt) "LSM: " fmt @@ -39,7 +35,7 @@ #define LSM_COUNT (__end_lsm_info - __start_lsm_info) struct security_hook_heads security_hook_heads __lsm_ro_after_init; -static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); +static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); static struct kmem_cache *lsm_file_cache; static struct kmem_cache *lsm_inode_cache; @@ -430,23 +426,26 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, panic("%s - Cannot get early memory.\n", __func__); } -int call_lsm_notifier(enum lsm_event event, void *data) +int call_blocking_lsm_notifier(enum lsm_event event, void *data) { - return atomic_notifier_call_chain(&lsm_notifier_chain, event, data); + return blocking_notifier_call_chain(&blocking_lsm_notifier_chain, + event, data); } -EXPORT_SYMBOL(call_lsm_notifier); +EXPORT_SYMBOL(call_blocking_lsm_notifier); -int register_lsm_notifier(struct notifier_block *nb) +int register_blocking_lsm_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_register(&lsm_notifier_chain, nb); + return blocking_notifier_chain_register(&blocking_lsm_notifier_chain, + nb); } -EXPORT_SYMBOL(register_lsm_notifier); +EXPORT_SYMBOL(register_blocking_lsm_notifier); -int unregister_lsm_notifier(struct notifier_block *nb) +int unregister_blocking_lsm_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_unregister(&lsm_notifier_chain, nb); + return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain, + nb); } -EXPORT_SYMBOL(unregister_lsm_notifier); +EXPORT_SYMBOL(unregister_blocking_lsm_notifier); /** * lsm_cred_alloc - allocate a composite cred blob diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 55f032f1fc2d..5711689deb6a 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_SELINUX bool "NSA SELinux Support" depends on SECURITY_NETWORK && AUDIT && NET && INET diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 8346a4f7c5d7..ecd3829996aa 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Implementation of the kernel access vector cache (AVC). * @@ -8,10 +9,6 @@ * Replaced the avc_lock spinlock by RCU. * * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/types.h> #include <linux/stddef.h> @@ -739,14 +736,20 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext, &scontext_len); if (!rc && scontext) { - audit_log_format(ab, " srawcon=%s", scontext); + if (scontext_len && scontext[scontext_len - 1] == '\0') + scontext_len--; + audit_log_format(ab, " srawcon="); + audit_log_n_untrustedstring(ab, scontext, scontext_len); kfree(scontext); } rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext, &scontext_len); if (!rc && scontext) { - audit_log_format(ab, " trawcon=%s", scontext); + if (scontext_len && scontext[scontext_len - 1] == '\0') + scontext_len--; + audit_log_format(ab, " trawcon="); + audit_log_n_untrustedstring(ab, scontext, scontext_len); kfree(scontext); } } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c61787b15f27..4bef86ed463b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NSA Security-Enhanced Linux (SELinux) security module * @@ -18,10 +19,6 @@ * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. * Yuichi Nakamura <ynakam@hitachisoft.jp> * Copyright (C) 2016 Mellanox Technologies - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/init.h> @@ -197,7 +194,7 @@ static int selinux_lsm_notifier_avc_callback(u32 event) { if (event == AVC_CALLBACK_RESET) { sel_ib_pkey_flush(); - call_lsm_notifier(LSM_POLICY_CHANGE, NULL); + call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); } return 0; @@ -1052,15 +1049,24 @@ static int selinux_add_mnt_opt(const char *option, const char *val, int len, if (token == Opt_error) return -EINVAL; - if (token != Opt_seclabel) + if (token != Opt_seclabel) { val = kmemdup_nul(val, len, GFP_KERNEL); + if (!val) { + rc = -ENOMEM; + goto free_opt; + } + } rc = selinux_add_opt(token, val, mnt_opts); if (unlikely(rc)) { kfree(val); - if (*mnt_opts) { - selinux_free_mnt_opts(*mnt_opts); - *mnt_opts = NULL; - } + goto free_opt; + } + return rc; + +free_opt: + if (*mnt_opts) { + selinux_free_mnt_opts(*mnt_opts); + *mnt_opts = NULL; } return rc; } @@ -2616,10 +2622,11 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) char *from = options; char *to = options; bool first = true; + int rc; while (1) { int len = opt_len(from); - int token, rc; + int token; char *arg = NULL; token = match_opt_prefix(from, len, &arg); @@ -2635,15 +2642,15 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) *q++ = c; } arg = kmemdup_nul(arg, q - arg, GFP_KERNEL); + if (!arg) { + rc = -ENOMEM; + goto free_opt; + } } rc = selinux_add_opt(token, arg, mnt_opts); if (unlikely(rc)) { kfree(arg); - if (*mnt_opts) { - selinux_free_mnt_opts(*mnt_opts); - *mnt_opts = NULL; - } - return rc; + goto free_opt; } } else { if (!first) { // copy with preceding comma @@ -2661,6 +2668,13 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) } *to = '\0'; return 0; + +free_opt: + if (*mnt_opts) { + selinux_free_mnt_opts(*mnt_opts); + *mnt_opts = NULL; + } + return rc; } static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) @@ -4637,6 +4651,14 @@ static int selinux_socket_connect_helper(struct socket *sock, err = sock_has_perm(sk, SOCKET__CONNECT); if (err) return err; + if (addrlen < offsetofend(struct sockaddr, sa_family)) + return -EINVAL; + + /* connect(AF_UNSPEC) has special handling, as it is a documented + * way to disconnect the socket + */ + if (address->sa_family == AF_UNSPEC) + return 0; /* * If a TCP, DCCP or SCTP socket, check name_connect permission @@ -4657,8 +4679,6 @@ static int selinux_socket_connect_helper(struct socket *sock, * need to check address->sa_family as it is possible to have * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. */ - if (addrlen < offsetofend(struct sockaddr, sa_family)) - return -EINVAL; switch (address->sa_family) { case AF_INET: addr4 = (struct sockaddr_in *)address; @@ -6331,11 +6351,12 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) } else if (!strcmp(name, "fscreate")) { tsec->create_sid = sid; } else if (!strcmp(name, "keycreate")) { - error = avc_has_perm(&selinux_state, - mysid, sid, SECCLASS_KEY, KEY__CREATE, - NULL); - if (error) - goto abort_change; + if (sid) { + error = avc_has_perm(&selinux_state, mysid, sid, + SECCLASS_KEY, KEY__CREATE, NULL); + if (error) + goto abort_change; + } tsec->keycreate_sid = sid; } else if (!strcmp(name, "sockcreate")) { tsec->sockcreate_sid = sid; @@ -6481,6 +6502,7 @@ static int selinux_key_permission(key_ref_t key_ref, { struct key *key; struct key_security_struct *ksec; + unsigned oldstyle_perm; u32 sid; /* if no specific permissions are requested, we skip the @@ -6489,13 +6511,26 @@ static int selinux_key_permission(key_ref_t key_ref, if (perm == 0) return 0; + oldstyle_perm = perm & (KEY_NEED_VIEW | KEY_NEED_READ | KEY_NEED_WRITE | + KEY_NEED_SEARCH | KEY_NEED_LINK); + if (perm & KEY_NEED_SETSEC) + oldstyle_perm |= OLD_KEY_NEED_SETATTR; + if (perm & KEY_NEED_INVAL) + oldstyle_perm |= KEY_NEED_SEARCH; + if (perm & KEY_NEED_REVOKE && !(perm & OLD_KEY_NEED_SETATTR)) + oldstyle_perm |= KEY_NEED_WRITE; + if (perm & KEY_NEED_JOIN) + oldstyle_perm |= KEY_NEED_SEARCH; + if (perm & KEY_NEED_CLEAR) + oldstyle_perm |= KEY_NEED_WRITE; + sid = cred_sid(cred); key = key_ref_to_ptr(key_ref); ksec = key->security; return avc_has_perm(&selinux_state, - sid, ksec->sid, SECCLASS_KEY, perm, NULL); + sid, ksec->sid, SECCLASS_KEY, oldstyle_perm, NULL); } static int selinux_key_getsecurity(struct key *key, char **_buffer) diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c index 0a4b89d48297..de92365e4324 100644 --- a/security/selinux/ibpkey.c +++ b/security/selinux/ibpkey.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Pkey table * @@ -11,21 +12,10 @@ * Paul Moore <paul@paul-moore.com> * (see security/selinux/netif.c and security/selinux/netport.c for more * information) - * */ /* * (c) Mellanox Technologies, 2016 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/types.h> diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 682e2b5de2a4..073a3d34a0d2 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * SELinux support for the Audit LSM hooks * @@ -6,10 +7,6 @@ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #ifndef _SELINUX_AUDIT_H diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h index 0e30eca02c48..0ab316f61da0 100644 --- a/security/selinux/include/conditional.h +++ b/security/selinux/include/conditional.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Interface to booleans in the security server. This is exported * for the selinuxfs. @@ -5,9 +6,6 @@ * Author: Karl MacMillan <kmacmillan@tresys.com> * * Copyright (C) 2003 - 2004 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #ifndef _SELINUX_CONDITIONAL_H_ diff --git a/security/selinux/include/ibpkey.h b/security/selinux/include/ibpkey.h index b17a19e348e6..a2ebe397bcb7 100644 --- a/security/selinux/include/ibpkey.h +++ b/security/selinux/include/ibpkey.h @@ -1,24 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * pkey table * * SELinux must keep a mapping of pkeys to labels/SIDs. This * mapping is maintained as part of the normal policy but a fast cache is * needed to reduce the lookup overhead. - * */ /* * (c) Mellanox Technologies, 2016 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef _SELINUX_IB_PKEY_H diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h index c72145444090..85ec30d11144 100644 --- a/security/selinux/include/netif.h +++ b/security/selinux/include/netif.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Network interface table. * @@ -9,10 +10,6 @@ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * Paul Moore <paul@paul-moore.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #ifndef _SELINUX_NETIF_H_ #define _SELINUX_NETIF_H_ diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 8671de09c363..d30d8d7cdc9c 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -1,26 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * SELinux interface to the NetLabel subsystem * * Author: Paul Moore <paul@paul-moore.com> - * */ /* * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * */ #ifndef _SELINUX_NETLABEL_H_ diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h index 937668dd3024..e3f784a85840 100644 --- a/security/selinux/include/netnode.h +++ b/security/selinux/include/netnode.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Network node table * @@ -7,21 +8,10 @@ * a per-packet basis. * * Author: Paul Moore <paul@paul-moore.com> - * */ /* * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef _SELINUX_NETNODE_H diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h index d1ce896b2cb0..31bc16e29cd1 100644 --- a/security/selinux/include/netport.h +++ b/security/selinux/include/netport.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Network port table * @@ -6,21 +7,10 @@ * needed to reduce the lookup overhead. * * Author: Paul Moore <paul@paul-moore.com> - * */ /* * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef _SELINUX_NETPORT_H diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 231262d8eac9..91c5395dd20c 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NSA Security-Enhanced Linux (SELinux) security module * @@ -11,10 +12,6 @@ * Copyright (C) 2001,2002 Networks Associates Technology, Inc. * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2016 Mellanox Technologies - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #ifndef _SELINUX_OBJSEC_H_ #define _SELINUX_OBJSEC_H_ diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 8c738c189942..9cb83eeee1d9 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Network interface table. * @@ -9,10 +10,6 @@ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * Paul Moore <paul@paul-moore.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/types.h> diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 6fd9954e1c08..abaab7683840 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * SELinux NetLabel Support * @@ -5,25 +6,10 @@ * subsystem. * * Author: Paul Moore <paul@paul-moore.com> - * */ /* * (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * */ #include <linux/spinlock.h> diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index 8a8a72507437..621e2e9cd6a1 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Netlink event notifications for SELinux. * * Author: James Morris <jmorris@redhat.com> * * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/types.h> diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index afa0d432436b..cae1fcaffd1a 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Network node table * @@ -11,21 +12,10 @@ * This code is heavily based on the "netif" concept originally developed by * James Morris <jmorris@redhat.com> * (see security/selinux/netif.c for more information) - * */ /* * (c) Copyright Hewlett-Packard Development Company, L.P., 2007 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/types.h> diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 7a141cadbffc..364b6d5b8968 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Network port table * @@ -10,21 +11,10 @@ * This code is heavily based on the "netif" concept originally developed by * James Morris <jmorris@redhat.com> * (see security/selinux/netif.c for more information) - * */ /* * (c) Copyright Hewlett-Packard Development Company, L.P., 2008 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/types.h> diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 9cec81209617..8cd7038389fd 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Netlink message type permission tables, for user generated messages. * * Author: James Morris <jmorris@redhat.com> * * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/types.h> #include <linux/kernel.h> diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 145ee62f205a..6f195c7915de 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Updated: Karl MacMillan <kmacmillan@tresys.com> * * Added conditional policy language extensions @@ -9,9 +10,6 @@ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #include <linux/kernel.h> @@ -180,7 +178,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, selnl_notify_setenforce(new_value); selinux_status_update_setenforce(state, new_value); if (!new_value) - call_lsm_notifier(LSM_POLICY_CHANGE, NULL); + call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); } length = count; out: diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index de16673b2314..837e938798ef 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * An access vector table (avtab) is a hash table * of access vectors and transition types indexed @@ -13,9 +14,6 @@ * Added conditional policy language extensions * * Copyright (C) 2003 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. * * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp> * Tuned number of hash slots for avtab to reduce memory usage diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 3bbb60345209..70c378ee1a2f 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Authors: Karl MacMillan <kmacmillan@tresys.com> * Frank Mayer <mayerf@tresys.com> * * Copyright (C) 2003 - 2004 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #include <linux/kernel.h> diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index ddb43e7e1c75..ec846e45904c 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -1,10 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* Authors: Karl MacMillan <kmacmillan@tresys.com> * Frank Mayer <mayerf@tresys.com> * * Copyright (C) 2003 - 2004 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #ifndef _CONDITIONAL_H_ diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 8f624f80055b..09929fc5ab47 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -347,7 +347,9 @@ int ebitmap_read(struct ebitmap *e, void *fp) { struct ebitmap_node *n = NULL; u32 mapunit, count, startbit, index; + __le32 ebitmap_start; u64 map; + __le64 mapbits; __le32 buf[3]; int rc, i; @@ -381,12 +383,12 @@ int ebitmap_read(struct ebitmap *e, void *fp) goto bad; for (i = 0; i < count; i++) { - rc = next_entry(&startbit, fp, sizeof(u32)); + rc = next_entry(&ebitmap_start, fp, sizeof(u32)); if (rc < 0) { pr_err("SELinux: ebitmap: truncated map\n"); goto bad; } - startbit = le32_to_cpu(startbit); + startbit = le32_to_cpu(ebitmap_start); if (startbit & (mapunit - 1)) { pr_err("SELinux: ebitmap start bit (%d) is " @@ -423,12 +425,12 @@ int ebitmap_read(struct ebitmap *e, void *fp) goto bad; } - rc = next_entry(&map, fp, sizeof(u64)); + rc = next_entry(&mapbits, fp, sizeof(u64)); if (rc < 0) { pr_err("SELinux: ebitmap: truncated map\n"); goto bad; } - map = le64_to_cpu(map); + map = le64_to_cpu(mapbits); index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE; while (map) { diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index daecdfb15a9c..624ccc6ac744 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Implementation of the policy database. * @@ -25,9 +26,6 @@ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #include <linux/kernel.h> diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 27039149ff0a..fcc6366b447f 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * A policy database (policydb) specifies the * configuration data for the security policy. @@ -16,9 +17,6 @@ * * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004 Tresys Technology, LLC - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #ifndef _SS_POLICYDB_H_ diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index cc043bc8fd4c..d61563a3695e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Implementation of the security services. * @@ -35,9 +36,6 @@ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. */ #include <linux/kernel.h> #include <linux/slab.h> @@ -651,9 +649,7 @@ static void context_struct_compute_av(struct policydb *policydb, avkey.target_class = tclass; avkey.specified = AVTAB_AV | AVTAB_XPERMS; sattr = &policydb->type_attr_map_array[scontext->type - 1]; - BUG_ON(!sattr); tattr = &policydb->type_attr_map_array[tcontext->type - 1]; - BUG_ON(!tattr); ebitmap_for_each_positive_bit(sattr, snode, i) { ebitmap_for_each_positive_bit(tattr, tnode, j) { avkey.source_type = i + 1; @@ -1059,9 +1055,7 @@ void security_compute_xperms_decision(struct selinux_state *state, avkey.target_class = tclass; avkey.specified = AVTAB_XPERMS; sattr = &policydb->type_attr_map_array[scontext->type - 1]; - BUG_ON(!sattr); tattr = &policydb->type_attr_map_array[tcontext->type - 1]; - BUG_ON(!tattr); ebitmap_for_each_positive_bit(sattr, snode, i) { ebitmap_for_each_positive_bit(tattr, tnode, j) { avkey.source_type = i + 1; @@ -1588,6 +1582,7 @@ static int compute_sid_handle_invalid_context( struct policydb *policydb = &state->ss->policydb; char *s = NULL, *t = NULL, *n = NULL; u32 slen, tlen, nlen; + struct audit_buffer *ab; if (context_struct_to_string(policydb, scontext, &s, &slen)) goto out; @@ -1595,12 +1590,14 @@ static int compute_sid_handle_invalid_context( goto out; if (context_struct_to_string(policydb, newcontext, &n, &nlen)) goto out; - audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR, - "op=security_compute_sid invalid_context=%s" - " scontext=%s" - " tcontext=%s" - " tclass=%s", - n, s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); + ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR); + audit_log_format(ab, + "op=security_compute_sid invalid_context="); + /* no need to record the NUL with untrusted strings */ + audit_log_n_untrustedstring(ab, n, nlen - 1); + audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s", + s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); + audit_log_end(ab); out: kfree(s); kfree(t); @@ -3007,10 +3004,16 @@ int security_sid_mls_copy(struct selinux_state *state, if (rc) { if (!context_struct_to_string(policydb, &newcon, &s, &len)) { - audit_log(audit_context(), - GFP_ATOMIC, AUDIT_SELINUX_ERR, - "op=security_sid_mls_copy " - "invalid_context=%s", s); + struct audit_buffer *ab; + + ab = audit_log_start(audit_context(), + GFP_ATOMIC, + AUDIT_SELINUX_ERR); + audit_log_format(ab, + "op=security_sid_mls_copy invalid_context="); + /* don't record NUL with untrusted strings */ + audit_log_n_untrustedstring(ab, s, len - 1); + audit_log_end(ab); kfree(s); } goto out_unlock; diff --git a/security/selinux/ss/status.c b/security/selinux/ss/status.c index a121de45ac0e..3c554a442467 100644 --- a/security/selinux/ss/status.c +++ b/security/selinux/ss/status.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmap based event notifications for SELinux * * Author: KaiGai Kohei <kaigai@ak.jp.nec.com> * * Copyright (C) 2010 NEC corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/kernel.h> #include <linux/gfp.h> diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 7c57cb7e4146..7314196185d1 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NSA Security-Enhanced Linux (SELinux) security module * @@ -12,10 +13,6 @@ * * Copyright (C) 2005 International Business Machines Corporation * Copyright (C) 2006 Trusted Computer Solutions, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ /* diff --git a/security/smack/Kconfig b/security/smack/Kconfig index 923b120e0fa5..5a8dfad469c3 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_SMACK bool "Simplified Mandatory Access Control Kernel Support" depends on NET diff --git a/security/smack/Makefile b/security/smack/Makefile index ee2ebd504541..6dbf6e22a68b 100644 --- a/security/smack/Makefile +++ b/security/smack/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for the SMACK LSM # diff --git a/security/smack/smack.h b/security/smack/smack.h index e41ca1d58484..62529f382942 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * * Author: * Casey Schaufler <casey@schaufler-ca.com> - * */ #ifndef _SECURITY_SMACK_H diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index fe2ce3a65822..f1c93a7be9ec 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * * Author: * Casey Schaufler <casey@schaufler-ca.com> - * */ #include <linux/types.h> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0de725f88bed..50c536cad85b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simplified MAC Kernel (smack) security module * @@ -12,10 +13,6 @@ * Paul Moore <paul@paul-moore.com> * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2011 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/xattr.h> @@ -68,6 +65,7 @@ static struct { int len; int opt; } smk_mount_opts[] = { + {"smackfsdef", sizeof("smackfsdef") - 1, Opt_fsdefault}, A(fsdefault), A(fsfloor), A(fshat), A(fsroot), A(fstransmute) }; #undef A @@ -682,11 +680,12 @@ static int smack_fs_context_dup(struct fs_context *fc, } static const struct fs_parameter_spec smack_param_specs[] = { - fsparam_string("fsdefault", Opt_fsdefault), - fsparam_string("fsfloor", Opt_fsfloor), - fsparam_string("fshat", Opt_fshat), - fsparam_string("fsroot", Opt_fsroot), - fsparam_string("fstransmute", Opt_fstransmute), + fsparam_string("smackfsdef", Opt_fsdefault), + fsparam_string("smackfsdefault", Opt_fsdefault), + fsparam_string("smackfsfloor", Opt_fsfloor), + fsparam_string("smackfshat", Opt_fshat), + fsparam_string("smackfsroot", Opt_fsroot), + fsparam_string("smackfstransmute", Opt_fstransmute), {} }; @@ -4285,7 +4284,8 @@ static int smack_key_permission(key_ref_t key_ref, #endif if (perm & (KEY_NEED_READ | KEY_NEED_SEARCH | KEY_NEED_VIEW)) request |= MAY_READ; - if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) + if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETSEC | + KEY_NEED_INVAL | KEY_NEED_REVOKE | KEY_NEED_CLEAR)) request |= MAY_WRITE; rc = smk_access(tkp, keyp->security, request, &ad); rc = smk_bu_note("key access", tkp, keyp->security, request, rc); diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index e36d17835d4f..fc7399b45373 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simplified MAC Kernel (smack) security module * @@ -8,10 +9,6 @@ * * Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com> * Copyright (C) 2014 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/netfilter_ipv4.h> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 47f73a0dabb1..ef0d8712d318 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * * Authors: * Casey Schaufler <casey@schaufler-ca.com> * Ahmed S. Darwish <darwish.07@gmail.com> @@ -13,7 +10,6 @@ * * Karl MacMillan <kmacmillan@tresys.com> * James Morris <jmorris@redhat.com> - * */ #include <linux/kernel.h> diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index a00ab7eb6181..9221ea506631 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_TOMOYO bool "TOMOYO Linux Support" depends on SECURITY diff --git a/security/yama/Kconfig b/security/yama/Kconfig index 96b27405558a..a810304123ca 100644 --- a/security/yama/Kconfig +++ b/security/yama/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config SECURITY_YAMA bool "Yama support" depends on SECURITY diff --git a/security/yama/Makefile b/security/yama/Makefile index 8b5e06588456..0fa5d0fe2cf6 100644 --- a/security/yama/Makefile +++ b/security/yama/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_SECURITY_YAMA) := yama.o yama-y := yama_lsm.o diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index efac68556b45..01c6239c4493 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Yama Linux Security Module * @@ -5,11 +6,6 @@ * * Copyright (C) 2010 Canonical, Ltd. * Copyright (C) 2011 The Chromium OS Authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * */ #include <linux/lsm_hooks.h> |