aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 20:27:36 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-21 20:27:36 -0700
commitcb60e3e65c1b96a4d6444a7a13dc7dd48bc15a2b (patch)
tree4322be35db678f6299348a76ad60a2023954af7d /security
parent99262a3dafa3290866512ddfb32609198f8973e9 (diff)
parentff2bb047c4bce9742e94911eeb44b4d6ff4734ab (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "New notable features: - The seccomp work from Will Drewry - PR_{GET,SET}_NO_NEW_PRIVS from Andy Lutomirski - Longer security labels for Smack from Casey Schaufler - Additional ptrace restriction modes for Yama by Kees Cook" Fix up trivial context conflicts in arch/x86/Kconfig and include/linux/filter.h * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (65 commits) apparmor: fix long path failure due to disconnected path apparmor: fix profile lookup for unconfined ima: fix filename hint to reflect script interpreter name KEYS: Don't check for NULL key pointer in key_validate() Smack: allow for significantly longer Smack labels v4 gfp flags for security_inode_alloc()? Smack: recursive tramsmute Yama: replace capable() with ns_capable() TOMOYO: Accept manager programs which do not start with / . KEYS: Add invalidation support KEYS: Do LRU discard in full keyrings KEYS: Permit in-place link replacement in keyring list KEYS: Perform RCU synchronisation on keys prior to key destruction KEYS: Announce key type (un)registration KEYS: Reorganise keys Makefile KEYS: Move the key config into security/keys/Kconfig KEYS: Use the compat keyctl() syscall wrapper on Sparc64 for Sparc32 compat Yama: remove an unused variable samples/seccomp: fix dependencies on arch macros Yama: add additional ptrace scopes ...
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig68
-rw-r--r--security/apparmor/audit.c11
-rw-r--r--security/apparmor/capability.c4
-rw-r--r--security/apparmor/domain.c35
-rw-r--r--security/apparmor/file.c2
-rw-r--r--security/apparmor/include/audit.h1
-rw-r--r--security/apparmor/ipc.c2
-rw-r--r--security/apparmor/lib.c2
-rw-r--r--security/apparmor/lsm.c6
-rw-r--r--security/apparmor/path.c2
-rw-r--r--security/apparmor/policy.c6
-rw-r--r--security/apparmor/policy_unpack.c2
-rw-r--r--security/apparmor/resource.c2
-rw-r--r--security/capability.c4
-rw-r--r--security/commoncap.c7
-rw-r--r--security/integrity/ima/ima_main.c4
-rw-r--r--security/keys/Kconfig71
-rw-r--r--security/keys/Makefile12
-rw-r--r--security/keys/compat.c3
-rw-r--r--security/keys/gc.c94
-rw-r--r--security/keys/internal.h15
-rw-r--r--security/keys/key.c25
-rw-r--r--security/keys/keyctl.c34
-rw-r--r--security/keys/keyring.c167
-rw-r--r--security/keys/permission.c43
-rw-r--r--security/keys/proc.c3
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--security/lsm_audit.c15
-rw-r--r--security/security.c4
-rw-r--r--security/selinux/avc.c130
-rw-r--r--security/selinux/hooks.c268
-rw-r--r--security/selinux/include/avc.h100
-rw-r--r--security/selinux/include/security.h4
-rw-r--r--security/selinux/netif.c6
-rw-r--r--security/selinux/netnode.c6
-rw-r--r--security/selinux/netport.c6
-rw-r--r--security/selinux/selinuxfs.c11
-rw-r--r--security/selinux/ss/context.h20
-rw-r--r--security/selinux/ss/mls.c24
-rw-r--r--security/selinux/ss/policydb.c44
-rw-r--r--security/selinux/ss/policydb.h14
-rw-r--r--security/selinux/ss/services.c56
-rw-r--r--security/smack/smack.h59
-rw-r--r--security/smack/smack_access.c233
-rw-r--r--security/smack/smack_lsm.c243
-rw-r--r--security/smack/smackfs.c993
-rw-r--r--security/tomoyo/common.c26
-rw-r--r--security/tomoyo/common.h1
-rw-r--r--security/tomoyo/tomoyo.c6
-rw-r--r--security/yama/yama_lsm.c63
50 files changed, 1857 insertions, 1102 deletions
diff --git a/security/Kconfig b/security/Kconfig
index ccc61f8006b..e9c6ac724fe 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -4,73 +4,7 @@
menu "Security options"
-config KEYS
- bool "Enable access key retention support"
- help
- This option provides support for retaining authentication tokens and
- access keys in the kernel.
-
- It also includes provision of methods by which such keys might be
- associated with a process so that network filesystems, encryption
- support and the like can find them.
-
- Furthermore, a special type of key is available that acts as keyring:
- a searchable sequence of keys. Each process is equipped with access
- to five standard keyrings: UID-specific, GID-specific, session,
- process and thread.
-
- If you are unsure as to whether this is required, answer N.
-
-config TRUSTED_KEYS
- tristate "TRUSTED KEYS"
- depends on KEYS && TCG_TPM
- select CRYPTO
- select CRYPTO_HMAC
- select CRYPTO_SHA1
- help
- This option provides support for creating, sealing, and unsealing
- keys in the kernel. Trusted keys are random number symmetric keys,
- generated and RSA-sealed by the TPM. The TPM only unseals the keys,
- if the boot PCRs and other criteria match. Userspace will only ever
- see encrypted blobs.
-
- If you are unsure as to whether this is required, answer N.
-
-config ENCRYPTED_KEYS
- tristate "ENCRYPTED KEYS"
- depends on KEYS
- select CRYPTO
- select CRYPTO_HMAC
- select CRYPTO_AES
- select CRYPTO_CBC
- select CRYPTO_SHA256
- select CRYPTO_RNG
- help
- This option provides support for create/encrypting/decrypting keys
- in the kernel. Encrypted keys are kernel generated random numbers,
- which are encrypted/decrypted with a 'master' symmetric key. The
- 'master' key can be either a trusted-key or user-key type.
- Userspace only ever sees/stores encrypted blobs.
-
- If you are unsure as to whether this is required, answer N.
-
-config KEYS_DEBUG_PROC_KEYS
- bool "Enable the /proc/keys file by which keys may be viewed"
- depends on KEYS
- help
- This option turns on support for the /proc/keys file - through which
- can be listed all the keys on the system that are viewable by the
- reading process.
-
- The only keys included in the list are those that grant View
- permission to the reading process whether or not it possesses them.
- Note that LSM security checks are still performed, and may further
- filter out keys that the current process is not authorised to view.
-
- Only key attributes are listed here; key payloads are not included in
- the resulting table.
-
- If you are unsure as to whether this is required, answer N.
+source security/keys/Kconfig
config SECURITY_DMESG_RESTRICT
bool "Restrict unprivileged access to the kernel syslog"
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index cc3520d39a7..3ae28db5a64 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -111,7 +111,7 @@ static const char *const aa_audit_type[] = {
static void audit_pre(struct audit_buffer *ab, void *ca)
{
struct common_audit_data *sa = ca;
- struct task_struct *tsk = sa->tsk ? sa->tsk : current;
+ struct task_struct *tsk = sa->aad->tsk ? sa->aad->tsk : current;
if (aa_g_audit_header) {
audit_log_format(ab, "apparmor=");
@@ -149,6 +149,12 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, sa->aad->name);
}
+
+ if (sa->aad->tsk) {
+ audit_log_format(ab, " pid=%d comm=", tsk->pid);
+ audit_log_untrustedstring(ab, tsk->comm);
+ }
+
}
/**
@@ -205,7 +211,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
aa_audit_msg(type, sa, cb);
if (sa->aad->type == AUDIT_APPARMOR_KILL)
- (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
+ (void)send_sig_info(SIGKILL, NULL,
+ sa->aad->tsk ? sa->aad->tsk : current);
if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
return complain_error(sa->aad->error);
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 088dba3bf7d..887a5e94894 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -65,10 +65,10 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task,
int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, CAP);
+ sa.type = LSM_AUDIT_DATA_CAP;
sa.aad = &aad;
- sa.tsk = task;
sa.u.cap = cap;
+ sa.aad->tsk = task;
sa.aad->op = OP_CAPABLE;
sa.aad->error = error;
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 6327685c101..b81ea10a17a 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -394,6 +394,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
new_profile = find_attach(ns, &ns->base.profiles, name);
if (!new_profile)
goto cleanup;
+ /*
+ * NOTE: Domain transitions from unconfined are allowed
+ * even when no_new_privs is set because this aways results
+ * in a further reduction of permissions.
+ */
goto apply;
}
@@ -455,6 +460,16 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
/* fail exec */
error = -EACCES;
+ /*
+ * Policy has specified a domain transition, if no_new_privs then
+ * fail the exec.
+ */
+ if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) {
+ aa_put_profile(new_profile);
+ error = -EPERM;
+ goto cleanup;
+ }
+
if (!new_profile)
goto audit;
@@ -609,6 +624,14 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
const char *target = NULL, *info = NULL;
int error = 0;
+ /*
+ * Fail explicitly requested domain transitions if no_new_privs.
+ * There is no exception for unconfined as change_hat is not
+ * available.
+ */
+ if (current->no_new_privs)
+ return -EPERM;
+
/* released below */
cred = get_current_cred();
cxt = cred->security;
@@ -750,6 +773,18 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
cxt = cred->security;
profile = aa_cred_profile(cred);
+ /*
+ * Fail explicitly requested domain transitions if no_new_privs
+ * and not unconfined.
+ * Domain transitions from unconfined are allowed even when
+ * no_new_privs is set because this aways results in a reduction
+ * of permissions.
+ */
+ if (current->no_new_privs && !unconfined(profile)) {
+ put_cred(cred);
+ return -EPERM;
+ }
+
if (ns_name) {
/* released below */
ns = aa_find_namespace(profile->ns, ns_name);
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 2f8fcba9ce4..cf19d4093ca 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -108,7 +108,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.op = op,
aad.fs.request = request;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 3868b1e5d5b..4b7e18951ae 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -110,6 +110,7 @@ struct apparmor_audit_data {
void *profile;
const char *name;
const char *info;
+ struct task_struct *tsk;
union {
void *target;
struct {
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index c3da93a5150..cf1071b1423 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -42,7 +42,7 @@ static int aa_audit_ptrace(struct aa_profile *profile,
{
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.op = OP_PTRACE;
aad.target = target;
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index e75829ba0ff..7430298116d 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -66,7 +66,7 @@ void aa_info_message(const char *str)
if (audit_enabled) {
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.info = str;
aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index ad05d391974..032daab449b 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -373,7 +373,7 @@ static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
AA_MAY_META_READ);
}
-static int apparmor_dentry_open(struct file *file, const struct cred *cred)
+static int apparmor_file_open(struct file *file, const struct cred *cred)
{
struct aa_file_cxt *fcxt = file->f_security;
struct aa_profile *profile;
@@ -589,7 +589,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
} else {
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.op = OP_SETPROCATTR;
aad.info = name;
@@ -640,9 +640,9 @@ static struct security_operations apparmor_ops = {
.path_chmod = apparmor_path_chmod,
.path_chown = apparmor_path_chown,
.path_truncate = apparmor_path_truncate,
- .dentry_open = apparmor_dentry_open,
.inode_getattr = apparmor_inode_getattr,
+ .file_open = apparmor_file_open,
.file_permission = apparmor_file_permission,
.file_alloc_security = apparmor_file_alloc_security,
.file_free_security = apparmor_file_free_security,
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index 2daeea4f926..e91ffee8016 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -94,6 +94,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
* be returned.
*/
if (!res || IS_ERR(res)) {
+ if (PTR_ERR(res) == -ENAMETOOLONG)
+ return -ENAMETOOLONG;
connected = 0;
res = dentry_path_raw(path->dentry, buf, buflen);
if (IS_ERR(res)) {
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index f1f7506a464..cf5fd220309 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -903,6 +903,10 @@ struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
profile = aa_get_profile(__lookup_profile(&ns->base, hname));
read_unlock(&ns->lock);
+ /* the unconfined profile is not in the regular profile list */
+ if (!profile && strcmp(hname, "unconfined") == 0)
+ profile = aa_get_profile(ns->unconfined);
+
/* refcount released by caller */
return profile;
}
@@ -965,7 +969,7 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
{
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.op = op;
aad.name = name;
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index deab7c7e8dc..329b1fd3074 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -95,7 +95,7 @@ static int audit_iface(struct aa_profile *new, const char *name,
struct aa_profile *profile = __aa_current_profile();
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
if (e)
aad.iface.pos = e->pos - e->start;
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index 2fe8613efe3..e1f3d7ef2c5 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -52,7 +52,7 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource,
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
- COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
aad.op = OP_SETRLIMIT,
aad.rlim.rlim = resource;
diff --git a/security/capability.c b/security/capability.c
index 5bb21b1c448..fca889676c5 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -348,7 +348,7 @@ static int cap_file_receive(struct file *file)
return 0;
}
-static int cap_dentry_open(struct file *file, const struct cred *cred)
+static int cap_file_open(struct file *file, const struct cred *cred)
{
return 0;
}
@@ -956,7 +956,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, file_set_fowner);
set_to_cap_if_null(ops, file_send_sigiotask);
set_to_cap_if_null(ops, file_receive);
- set_to_cap_if_null(ops, dentry_open);
+ set_to_cap_if_null(ops, file_open);
set_to_cap_if_null(ops, task_create);
set_to_cap_if_null(ops, task_free);
set_to_cap_if_null(ops, cred_alloc_blank);
diff --git a/security/commoncap.c b/security/commoncap.c
index 71a166a0597..f80d1160939 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -512,14 +512,17 @@ skip:
/* Don't let someone trace a set[ug]id/setpcap binary with the revised
- * credentials unless they have the appropriate permit
+ * credentials unless they have the appropriate permit.
+ *
+ * In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
*/
if ((new->euid != old->uid ||
new->egid != old->gid ||
!cap_issubset(new->cap_permitted, old->cap_permitted)) &&
bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
/* downgrade; they get no more than they had, and maybe less */
- if (!capable(CAP_SETUID)) {
+ if (!capable(CAP_SETUID) ||
+ (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) {
new->euid = new->uid;
new->egid = new->gid;
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 1eff5cb001e..b17be79b9cf 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -194,7 +194,9 @@ int ima_bprm_check(struct linux_binprm *bprm)
{
int rc;
- rc = process_measurement(bprm->file, bprm->filename,
+ rc = process_measurement(bprm->file,
+ (strcmp(bprm->filename, bprm->interp) == 0) ?
+ bprm->filename : bprm->interp,
MAY_EXEC, BPRM_CHECK);
return 0;
}
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
new file mode 100644
index 00000000000..a90d6d300db
--- /dev/null
+++ b/security/keys/Kconfig
@@ -0,0 +1,71 @@
+#
+# Key management configuration
+#
+
+config KEYS
+ bool "Enable access key retention support"
+ help
+ This option provides support for retaining authentication tokens and
+ access keys in the kernel.
+
+ It also includes provision of methods by which such keys might be
+ associated with a process so that network filesystems, encryption
+ support and the like can find them.
+
+ Furthermore, a special type of key is available that acts as keyring:
+ a searchable sequence of keys. Each process is equipped with access
+ to five standard keyrings: UID-specific, GID-specific, session,
+ process and thread.
+
+ If you are unsure as to whether this is required, answer N.
+
+config TRUSTED_KEYS
+ tristate "TRUSTED KEYS"
+ depends on KEYS && TCG_TPM
+ select CRYPTO
+ select CRYPTO_HMAC
+ select CRYPTO_SHA1
+ help
+ This option provides support for creating, sealing, and unsealing
+ keys in the kernel. Trusted keys are random number symmetric keys,
+ generated and RSA-sealed by the TPM. The TPM only unseals the keys,
+ if the boot PCRs and other criteria match. Userspace will only ever
+ see encrypted blobs.
+
+ If you are unsure as to whether this is required, answer N.
+
+config ENCRYPTED_KEYS
+ tristate "ENCRYPTED KEYS"
+ depends on KEYS
+ select CRYPTO
+ select CRYPTO_HMAC
+ select CRYPTO_AES
+ select CRYPTO_CBC
+ select CRYPTO_SHA256
+ select CRYPTO_RNG
+ help
+ This option provides support for create/encrypting/decrypting keys
+ in the kernel. Encrypted keys are kernel generated random numbers,
+ which are encrypted/decrypted with a 'master' symmetric key. The
+ 'master' key can be either a trusted-key or user-key type.
+ Userspace only ever sees/stores encrypted blobs.
+
+ If you are unsure as to whether this is required, answer N.
+
+config KEYS_DEBUG_PROC_KEYS
+ bool "Enable the /proc/keys file by which keys may be viewed"
+ depends on KEYS
+ help
+ This option turns on support for the /proc/keys file - through which
+ can be listed all the keys on the system that are viewable by the
+ reading process.
+
+ The only keys included in the list are those that grant View
+ permission to the reading process whether or not it possesses them.
+ Note that LSM security checks are still performed, and may further
+ filter out keys that the current process is not authorised to view.
+
+ Only key attributes are listed here; key payloads are not included in
+ the resulting table.
+
+ If you are unsure as to whether this is required, answer N.
diff --git a/security/keys/Makefile b/security/keys/Makefile
index a56f1ffdc64..504aaa00838 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -2,6 +2,9 @@
# Makefile for key management
#
+#
+# Core
+#
obj-y := \
gc.o \
key.o \
@@ -12,9 +15,12 @@ obj-y := \
request_key.o \
request_key_auth.o \
user_defined.o
-
-obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
+
+#
+# Key types
+#
+obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 4c48e13448f..fab4f8dda6c 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -135,6 +135,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
return compat_keyctl_instantiate_key_iov(
arg2, compat_ptr(arg3), arg4, arg5);
+ case KEYCTL_INVALIDATE:
+ return keyctl_invalidate_key(arg2);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/gc.c b/security/keys/gc.c
index a42b45531aa..61ab7c82ebb 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -72,6 +72,15 @@ void key_schedule_gc(time_t gc_at)
}
/*
+ * Schedule a dead links collection run.
+ */
+void key_schedule_gc_links(void)
+{
+ set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags);
+ queue_work(system_nrt_wq, &key_gc_work);
+}
+
+/*
* Some key's cleanup time was met after it expired, so we need to get the
* reaper to go through a cycle finding expired keys.
*/
@@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data)
{
kenter("");
key_gc_next_run = LONG_MAX;
- set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags);
- queue_work(system_nrt_wq, &key_gc_work);
+ key_schedule_gc_links();
}
/*
@@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype)
static void key_gc_keyring(struct key *keyring, time_t limit)
{
struct keyring_list *klist;
- struct key *key;
int loop;
kenter("%x", key_serial(keyring));
- if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
+ if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
+ (1 << KEY_FLAG_REVOKED)))
goto dont_gc;
/* scan the keyring looking for dead keys */
@@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit)
loop = klist->nkeys;
smp_rmb();
for (loop--; loop >= 0; loop--) {
- key = klist->keys[loop];
- if (test_bit(KEY_FLAG_DEAD, &key->flags) ||
- (key->expiry > 0 && key->expiry <= limit))
+ struct key *key = rcu_dereference(klist->keys[loop]);
+ if (key_is_dead(key, limit))
goto do_gc;
}
@@ -168,38 +175,45 @@ do_gc:
}
/*
- * Garbage collect an unreferenced, detached key
+ * Garbage collect a list of unreferenced, detached keys
*/
-static noinline void key_gc_unused_key(struct key *key)
+static noinline voi