From 2aff9d20d50ac45dd13a013ef5231f4fb8912356 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 10 Jul 2024 14:32:25 -0700 Subject: lsm: infrastructure management of the sock security Move management of the sock->sk_security blob out of the individual security modules and into the security infrastructure. Instead of allocating the blobs from within the modules the modules tell the infrastructure how much space is required, and the space is allocated there. Acked-by: Paul Moore Reviewed-by: Kees Cook Reviewed-by: John Johansen Acked-by: Stephen Smalley Signed-off-by: Casey Schaufler [PM: subject tweak] Signed-off-by: Paul Moore --- security/security.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 8cee5b6c6e6d..9c3fb2f60e2a 100644 --- a/security/security.c +++ b/security/security.c @@ -29,6 +29,7 @@ #include #include #include +#include /* How many LSMs were built into the kernel? */ #define LSM_COUNT (__end_lsm_info - __start_lsm_info) @@ -227,6 +228,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode); lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc); lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg); + lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock); lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock); lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task); lsm_set_blob_size(&needed->lbs_xattr_count, @@ -401,6 +403,7 @@ static void __init ordered_lsm_init(void) init_debug("inode blob size = %d\n", blob_sizes.lbs_inode); init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc); init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg); + init_debug("sock blob size = %d\n", blob_sizes.lbs_sock); init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock); init_debug("task blob size = %d\n", blob_sizes.lbs_task); init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); @@ -4673,6 +4676,28 @@ int security_socket_getpeersec_dgram(struct socket *sock, } EXPORT_SYMBOL(security_socket_getpeersec_dgram); +/** + * lsm_sock_alloc - allocate a composite sock blob + * @sock: the sock that needs a blob + * @priority: allocation mode + * + * Allocate the sock blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_sock_alloc(struct sock *sock, gfp_t priority) +{ + if (blob_sizes.lbs_sock == 0) { + sock->sk_security = NULL; + return 0; + } + + sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority); + if (sock->sk_security == NULL) + return -ENOMEM; + return 0; +} + /** * security_sk_alloc() - Allocate and initialize a sock's LSM blob * @sk: sock @@ -4686,7 +4711,14 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram); */ int security_sk_alloc(struct sock *sk, int family, gfp_t priority) { - return call_int_hook(sk_alloc_security, sk, family, priority); + int rc = lsm_sock_alloc(sk, priority); + + if (unlikely(rc)) + return rc; + rc = call_int_hook(sk_alloc_security, sk, family, priority); + if (unlikely(rc)) + security_sk_free(sk); + return rc; } /** @@ -4698,6 +4730,8 @@ int security_sk_alloc(struct sock *sk, int family, gfp_t priority) void security_sk_free(struct sock *sk) { call_void_hook(sk_free_security, sk); + kfree(sk->sk_security); + sk->sk_security = NULL; } /** -- cgit v1.2.3 From 5f8d28f6d7d568dbbc8c5bce94894474c07afd4f Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 10 Jul 2024 14:32:26 -0700 Subject: lsm: infrastructure management of the key security blob Move management of the key->security blob out of the individual security modules and into the security infrastructure. Instead of allocating the blobs from within the modules the modules tell the infrastructure how much space is required, and the space is allocated there. There are no existing modules that require a key_free hook, so the call to it and the definition for it have been removed. Signed-off-by: Casey Schaufler Reviewed-by: John Johansen [PM: subject tweak] Signed-off-by: Paul Moore --- security/security.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 9c3fb2f60e2a..dfb7fea6080c 100644 --- a/security/security.c +++ b/security/security.c @@ -227,6 +227,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) blob_sizes.lbs_inode = sizeof(struct rcu_head); lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode); lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc); + lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key); lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg); lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock); lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock); @@ -402,6 +403,9 @@ static void __init ordered_lsm_init(void) init_debug("file blob size = %d\n", blob_sizes.lbs_file); init_debug("inode blob size = %d\n", blob_sizes.lbs_inode); init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc); +#ifdef CONFIG_KEYS + init_debug("key blob size = %d\n", blob_sizes.lbs_key); +#endif /* CONFIG_KEYS */ init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg); init_debug("sock blob size = %d\n", blob_sizes.lbs_sock); init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock); @@ -718,6 +722,29 @@ static int lsm_ipc_alloc(struct kern_ipc_perm *kip) return 0; } +#ifdef CONFIG_KEYS +/** + * lsm_key_alloc - allocate a composite key blob + * @key: the key that needs a blob + * + * Allocate the key blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_key_alloc(struct key *key) +{ + if (blob_sizes.lbs_key == 0) { + key->security = NULL; + return 0; + } + + key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL); + if (key->security == NULL) + return -ENOMEM; + return 0; +} +#endif /* CONFIG_KEYS */ + /** * lsm_msg_msg_alloc - allocate a composite msg_msg blob * @mp: the msg_msg that needs a blob @@ -5316,7 +5343,14 @@ EXPORT_SYMBOL(security_skb_classify_flow); int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { - return call_int_hook(key_alloc, key, cred, flags); + int rc = lsm_key_alloc(key); + + if (unlikely(rc)) + return rc; + rc = call_int_hook(key_alloc, key, cred, flags); + if (unlikely(rc)) + security_key_free(key); + return rc; } /** @@ -5327,7 +5361,8 @@ int security_key_alloc(struct key *key, const struct cred *cred, */ void security_key_free(struct key *key) { - call_void_hook(key_free, key); + kfree(key->security); + key->security = NULL; } /** -- cgit v1.2.3 From 09001284eebfc1b684e81d1db0f006787d35f3e1 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 10 Jul 2024 14:32:27 -0700 Subject: lsm: add helper for blob allocations Create a helper function lsm_blob_alloc() for general use in the hook specific functions that allocate LSM blobs. Change the hook specific functions to use this helper. This reduces the code size by a small amount and will make adding new instances of infrastructure managed security blobs easier. Signed-off-by: Casey Schaufler Reviewed-by: John Johansen [PM: subject tweak] Signed-off-by: Paul Moore --- security/security.c | 97 ++++++++++++++++++----------------------------------- 1 file changed, 33 insertions(+), 64 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index dfb7fea6080c..15efcf43e168 100644 --- a/security/security.c +++ b/security/security.c @@ -603,27 +603,42 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb) EXPORT_SYMBOL(unregister_blocking_lsm_notifier); /** - * lsm_cred_alloc - allocate a composite cred blob - * @cred: the cred that needs a blob + * lsm_blob_alloc - allocate a composite blob + * @dest: the destination for the blob + * @size: the size of the blob * @gfp: allocation type * - * Allocate the cred blob for all the modules + * Allocate a blob for all the modules * * Returns 0, or -ENOMEM if memory can't be allocated. */ -static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) +static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp) { - if (blob_sizes.lbs_cred == 0) { - cred->security = NULL; + if (size == 0) { + *dest = NULL; return 0; } - cred->security = kzalloc(blob_sizes.lbs_cred, gfp); - if (cred->security == NULL) + *dest = kzalloc(size, gfp); + if (*dest == NULL) return -ENOMEM; return 0; } +/** + * lsm_cred_alloc - allocate a composite cred blob + * @cred: the cred that needs a blob + * @gfp: allocation type + * + * Allocate the cred blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) +{ + return lsm_blob_alloc(&cred->security, blob_sizes.lbs_cred, gfp); +} + /** * lsm_early_cred - during initialization allocate a composite cred blob * @cred: the cred that needs a blob @@ -690,15 +705,7 @@ int lsm_inode_alloc(struct inode *inode) */ static int lsm_task_alloc(struct task_struct *task) { - if (blob_sizes.lbs_task == 0) { - task->security = NULL; - return 0; - } - - task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL); - if (task->security == NULL) - return -ENOMEM; - return 0; + return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL); } /** @@ -711,15 +718,7 @@ static int lsm_task_alloc(struct task_struct *task) */ static int lsm_ipc_alloc(struct kern_ipc_perm *kip) { - if (blob_sizes.lbs_ipc == 0) { - kip->security = NULL; - return 0; - } - - kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL); - if (kip->security == NULL) - return -ENOMEM; - return 0; + return lsm_blob_alloc(&kip->security, blob_sizes.lbs_ipc, GFP_KERNEL); } #ifdef CONFIG_KEYS @@ -733,15 +732,7 @@ static int lsm_ipc_alloc(struct kern_ipc_perm *kip) */ static int lsm_key_alloc(struct key *key) { - if (blob_sizes.lbs_key == 0) { - key->security = NULL; - return 0; - } - - key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL); - if (key->security == NULL) - return -ENOMEM; - return 0; + return lsm_blob_alloc(&key->security, blob_sizes.lbs_key, GFP_KERNEL); } #endif /* CONFIG_KEYS */ @@ -755,15 +746,8 @@ static int lsm_key_alloc(struct key *key) */ static int lsm_msg_msg_alloc(struct msg_msg *mp) { - if (blob_sizes.lbs_msg_msg == 0) { - mp->security = NULL; - return 0; - } - - mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL); - if (mp->security == NULL) - return -ENOMEM; - return 0; + return lsm_blob_alloc(&mp->security, blob_sizes.lbs_msg_msg, + GFP_KERNEL); } /** @@ -790,15 +774,8 @@ static void __init lsm_early_task(struct task_struct *task) */ static int lsm_superblock_alloc(struct super_block *sb) { - if (blob_sizes.lbs_superblock == 0) { - sb->s_security = NULL; - return 0; - } - - sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL); - if (sb->s_security == NULL) - return -ENOMEM; - return 0; + return lsm_blob_alloc(&sb->s_security, blob_sizes.lbs_superblock, + GFP_KERNEL); } /** @@ -4706,23 +4683,15 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram); /** * lsm_sock_alloc - allocate a composite sock blob * @sock: the sock that needs a blob - * @priority: allocation mode + * @gfp: allocation mode * * Allocate the sock blob for all the modules * * Returns 0, or -ENOMEM if memory can't be allocated. */ -static int lsm_sock_alloc(struct sock *sock, gfp_t priority) +static int lsm_sock_alloc(struct sock *sock, gfp_t gfp) { - if (blob_sizes.lbs_sock == 0) { - sock->sk_security = NULL; - return 0; - } - - sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority); - if (sock->sk_security == NULL) - return -ENOMEM; - return 0; + return lsm_blob_alloc(&sock->sk_security, blob_sizes.lbs_sock, gfp); } /** -- cgit v1.2.3 From a39c0f77dbbe083f3eec6c3b32d90f168f7575eb Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 10 Jul 2024 14:32:28 -0700 Subject: lsm: infrastructure management of the dev_tun blob Move management of the dev_tun security blob out of the individual security modules and into the LSM infrastructure. The security modules tell the infrastructure how much space they require at initialization. There are no longer any modules that require the dev_tun_free hook. The hook definition has been removed. Signed-off-by: Casey Schaufler Reviewed-by: John Johansen [PM: subject tweak, selinux style fixes] Signed-off-by: Paul Moore --- security/security.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 15efcf43e168..137a1f7e0e8b 100644 --- a/security/security.c +++ b/security/security.c @@ -232,6 +232,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock); lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock); lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task); + lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev); lsm_set_blob_size(&needed->lbs_xattr_count, &blob_sizes.lbs_xattr_count); } @@ -410,6 +411,7 @@ static void __init ordered_lsm_init(void) init_debug("sock blob size = %d\n", blob_sizes.lbs_sock); init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock); init_debug("task blob size = %d\n", blob_sizes.lbs_task); + init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev); init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); /* @@ -4875,7 +4877,18 @@ EXPORT_SYMBOL(security_secmark_refcount_dec); */ int security_tun_dev_alloc_security(void **security) { - return call_int_hook(tun_dev_alloc_security, security); + int rc; + + rc = lsm_blob_alloc(security, blob_sizes.lbs_tun_dev, GFP_KERNEL); + if (rc) + return rc; + + rc = call_int_hook(tun_dev_alloc_security, *security); + if (rc) { + kfree(*security); + *security = NULL; + } + return rc; } EXPORT_SYMBOL(security_tun_dev_alloc_security); @@ -4887,7 +4900,7 @@ EXPORT_SYMBOL(security_tun_dev_alloc_security); */ void security_tun_dev_free_security(void *security) { - call_void_hook(tun_dev_free_security, security); + kfree(security); } EXPORT_SYMBOL(security_tun_dev_free_security); -- cgit v1.2.3 From 66de33a0bbb59ef3909d2c65dbbb7fc503d573bd Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 10 Jul 2024 14:32:29 -0700 Subject: lsm: infrastructure management of the infiniband blob Move management of the infiniband security blob out of the individual security modules and into the LSM infrastructure. The security modules tell the infrastructure how much space they require at initialization. There are no longer any modules that require the ib_free() hook. The hook definition has been removed. Signed-off-by: Casey Schaufler Reviewed-by: John Johansen [PM: subject tweak, selinux style fixes] Signed-off-by: Paul Moore --- security/security.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 137a1f7e0e8b..80dc58d60aab 100644 --- a/security/security.c +++ b/security/security.c @@ -219,6 +219,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred); lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file); + lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib); /* * The inode blob gets an rcu_head in addition to * what the modules might need. @@ -402,6 +403,7 @@ static void __init ordered_lsm_init(void) init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); init_debug("file blob size = %d\n", blob_sizes.lbs_file); + init_debug("ib blob size = %d\n", blob_sizes.lbs_ib); init_debug("inode blob size = %d\n", blob_sizes.lbs_inode); init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc); #ifdef CONFIG_KEYS @@ -5096,7 +5098,18 @@ EXPORT_SYMBOL(security_ib_endport_manage_subnet); */ int security_ib_alloc_security(void **sec) { - return call_int_hook(ib_alloc_security, sec); + int rc; + + rc = lsm_blob_alloc(sec, blob_sizes.lbs_ib, GFP_KERNEL); + if (rc) + return rc; + + rc = call_int_hook(ib_alloc_security, *sec); + if (rc) { + kfree(*sec); + *sec = NULL; + } + return rc; } EXPORT_SYMBOL(security_ib_alloc_security); @@ -5108,7 +5121,7 @@ EXPORT_SYMBOL(security_ib_alloc_security); */ void security_ib_free_security(void *sec) { - call_void_hook(ib_free_security, sec); + kfree(sec); } EXPORT_SYMBOL(security_ib_free_security); #endif /* CONFIG_SECURITY_INFINIBAND */ -- cgit v1.2.3 From 61a1dcdceb44d79e5ab511295791b88ea178c045 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 10 Jul 2024 14:32:30 -0700 Subject: lsm: infrastructure management of the perf_event security blob Move management of the perf_event->security blob out of the individual security modules and into the security infrastructure. Instead of allocating the blobs from within the modules the modules tell the infrastructure how much space is required, and the space is allocated there. There are no longer any modules that require the perf_event_free() hook. The hook definition has been removed. Signed-off-by: Casey Schaufler Reviewed-by: John Johansen [PM: subject tweak] Signed-off-by: Paul Moore --- security/security.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 80dc58d60aab..93ed7670fbc9 100644 --- a/security/security.c +++ b/security/security.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -230,6 +231,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc); lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key); lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg); + lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event); lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock); lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock); lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task); @@ -412,6 +414,7 @@ static void __init ordered_lsm_init(void) init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg); init_debug("sock blob size = %d\n", blob_sizes.lbs_sock); init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock); + init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event); init_debug("task blob size = %d\n", blob_sizes.lbs_task); init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev); init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); @@ -5685,7 +5688,19 @@ int security_perf_event_open(struct perf_event_attr *attr, int type) */ int security_perf_event_alloc(struct perf_event *event) { - return call_int_hook(perf_event_alloc, event); + int rc; + + rc = lsm_blob_alloc(&event->security, blob_sizes.lbs_perf_event, + GFP_KERNEL); + if (rc) + return rc; + + rc = call_int_hook(perf_event_alloc, event); + if (rc) { + kfree(event->security); + event->security = NULL; + } + return rc; } /** @@ -5696,7 +5711,8 @@ int security_perf_event_alloc(struct perf_event *event) */ void security_perf_event_free(struct perf_event *event) { - call_void_hook(perf_event_free, event); + kfree(event->security); + event->security = NULL; } /** -- cgit v1.2.3 From be72a57527fde6c80061c5f9d0e28762eb817b03 Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Wed, 24 Jul 2024 10:06:58 +0800 Subject: lsm: Refactor return value of LSM hook vm_enough_memory To be consistent with most LSM hooks, convert the return value of hook vm_enough_memory to 0 or a negative error code. Before: - Hook vm_enough_memory returns 1 if permission is granted, 0 if not. - LSM_RET_DEFAULT(vm_enough_memory_mm) is 1. After: - Hook vm_enough_memory reutrns 0 if permission is granted, negative error code if not. - LSM_RET_DEFAULT(vm_enough_memory_mm) is 0. Signed-off-by: Xu Kuohai Reviewed-by: Casey Schaufler Signed-off-by: Paul Moore --- security/security.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 93ed7670fbc9..b2f0e9a57864 100644 --- a/security/security.c +++ b/security/security.c @@ -1129,15 +1129,14 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) int rc; /* - * The module will respond with a positive value if - * it thinks the __vm_enough_memory() call should be - * made with the cap_sys_admin set. If all of the modules - * agree that it should be set it will. If any module - * thinks it should not be set it won't. + * The module will respond with 0 if it thinks the __vm_enough_memory() + * call should be made with the cap_sys_admin set. If all of the modules + * agree that it should be set it will. If any module thinks it should + * not be set it won't. */ hlist_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) { rc = hp->hook.vm_enough_memory(mm, pages); - if (rc <= 0) { + if (rc < 0) { cap_sys_admin = 0; break; } -- cgit v1.2.3 From 924e19c39e8f0bbd581ab8a049f95a0ed02235b1 Mon Sep 17 00:00:00 2001 From: Xu Kuohai Date: Wed, 24 Jul 2024 10:06:59 +0800 Subject: lsm: Refactor return value of LSM hook inode_copy_up_xattr To be consistent with most LSM hooks, convert the return value of hook inode_copy_up_xattr to 0 or a negative error code. Before: - Hook inode_copy_up_xattr returns 0 when accepting xattr, 1 when discarding xattr, -EOPNOTSUPP if it does not know xattr, or any other negative error code otherwise. After: - Hook inode_copy_up_xattr returns 0 when accepting xattr, *-ECANCELED* when discarding xattr, -EOPNOTSUPP if it does not know xattr, or any other negative error code otherwise. Signed-off-by: Xu Kuohai Reviewed-by: Casey Schaufler Signed-off-by: Paul Moore --- security/security.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index b2f0e9a57864..338e0d243a3c 100644 --- a/security/security.c +++ b/security/security.c @@ -2674,19 +2674,14 @@ EXPORT_SYMBOL(security_inode_copy_up); * lower layer to the union/overlay layer. The caller is responsible for * reading and writing the xattrs, this hook is merely a filter. * - * Return: Returns 0 to accept the xattr, 1 to discard the xattr, -EOPNOTSUPP - * if the security module does not know about attribute, or a negative - * error code to abort the copy up. + * Return: Returns 0 to accept the xattr, -ECANCELED to discard the xattr, + * -EOPNOTSUPP if the security module does not know about attribute, + * or a negative error code to abort the copy up. */ int security_inode_copy_up_xattr(struct dentry *src, const char *name) { int rc; - /* - * The implementation can return 0 (accept the xattr), 1 (discard the - * xattr), -EOPNOTSUPP if it does not know anything about the xattr or - * any other error code in case of an error. - */ rc = call_int_hook(inode_copy_up_xattr, src, name); if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr)) return rc; -- cgit v1.2.3 From 711f5c5ce6c2c640c1b3b569ab2a8847be5ab21f Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 15 Jul 2024 21:22:51 -0400 Subject: lsm: cleanup lsm_hooks.h Some cleanup and style corrections for lsm_hooks.h. * Drop the lsm_inode_alloc() extern declaration, it is not needed. * Relocate lsm_get_xattr_slot() and extern variables in the file to improve grouping of related objects. * Don't use tabs to needlessly align structure fields. Reviewed-by: Casey Schaufler Signed-off-by: Paul Moore --- security/security.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 338e0d243a3c..b316e6586be2 100644 --- a/security/security.c +++ b/security/security.c @@ -689,7 +689,7 @@ static int lsm_file_alloc(struct file *file) * * Returns 0, or -ENOMEM if memory can't be allocated. */ -int lsm_inode_alloc(struct inode *inode) +static int lsm_inode_alloc(struct inode *inode) { if (!lsm_inode_cache) { inode->i_security = NULL; -- cgit v1.2.3 From 63dff3e48871b0583be5032ff8fb7260c349a18c Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Tue, 9 Jul 2024 19:43:06 -0400 Subject: lsm: add the inode_free_security_rcu() LSM implementation hook The LSM framework has an existing inode_free_security() hook which is used by LSMs that manage state associated with an inode, but due to the use of RCU to protect the inode, special care must be taken to ensure that the LSMs do not fully release the inode state until it is safe from a RCU perspective. This patch implements a new inode_free_security_rcu() implementation hook which is called when it is safe to free the LSM's internal inode state. Unfortunately, this new hook does not have access to the inode itself as it may already be released, so the existing inode_free_security() hook is retained for those LSMs which require access to the inode. Cc: stable@vger.kernel.org Reported-by: syzbot+5446fbf332b0602ede0b@syzkaller.appspotmail.com Closes: https://lore.kernel.org/r/00000000000076ba3b0617f65cc8@google.com Signed-off-by: Paul Moore --- security/security.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index b316e6586be2..611d3c124ba6 100644 --- a/security/security.c +++ b/security/security.c @@ -1609,9 +1609,8 @@ int security_inode_alloc(struct inode *inode) static void inode_free_by_rcu(struct rcu_head *head) { - /* - * The rcu head is at the start of the inode blob - */ + /* The rcu head is at the start of the inode blob */ + call_void_hook(inode_free_security_rcu, head); kmem_cache_free(lsm_inode_cache, head); } @@ -1619,23 +1618,24 @@ static void inode_free_by_rcu(struct rcu_head *head) * security_inode_free() - Free an inode's LSM blob * @inode: the inode * - * Deallocate the inode security structure and set @inode->i_security to NULL. + * Release any LSM resources associated with @inode, although due to the + * inode's RCU protections it is possible that the resources will not be + * fully released until after the current RCU grace period has elapsed. + * + * It is important for LSMs to note that despite being present in a call to + * security_inode_free(), @inode may still be referenced in a VFS path walk + * and calls to security_inode_permission() may be made during, or after, + * a call to security_inode_free(). For this reason the inode->i_security + * field is released via a call_rcu() callback and any LSMs which need to + * retain inode state for use in security_inode_permission() should only + * release that state in the inode_free_security_rcu() LSM hook callback. */ void security_inode_free(struct inode *inode) { call_void_hook(inode_free_security, inode); - /* - * The inode may still be referenced in a path walk and - * a call to security_inode_permission() can be made - * after inode_free_security() is called. Ideally, the VFS - * wouldn't do this, but fixing that is a much harder - * job. For now, simply free the i_security via RCU, and - * leave the current inode->i_security pointer intact. - * The inode will be freed after the RCU grace period too. - */ - if (inode->i_security) - call_rcu((struct rcu_head *)inode->i_security, - inode_free_by_rcu); + if (!inode->i_security) + return; + call_rcu((struct rcu_head *)inode->i_security, inode_free_by_rcu); } /** -- cgit v1.2.3 From 0311507792b54069ac72e0a6c6b35c5d40aadad8 Mon Sep 17 00:00:00 2001 From: Deven Bowers Date: Fri, 2 Aug 2024 23:08:15 -0700 Subject: lsm: add IPE lsm Integrity Policy Enforcement (IPE) is an LSM that provides an complimentary approach to Mandatory Access Control than existing LSMs today. Existing LSMs have centered around the concept of access to a resource should be controlled by the current user's credentials. IPE's approach, is that access to a resource should be controlled by the system's trust of a current resource. The basis of this approach is defining a global policy to specify which resource can be trusted. Signed-off-by: Deven Bowers Signed-off-by: Fan Wu [PM: subject line tweak] Signed-off-by: Paul Moore --- security/security.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 611d3c124ba6..645a660320cb 100644 --- a/security/security.c +++ b/security/security.c @@ -53,7 +53,8 @@ (IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \ (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \ (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_EVM) ? 1 : 0)) + (IS_ENABLED(CONFIG_EVM) ? 1 : 0) + \ + (IS_ENABLED(CONFIG_SECURITY_IPE) ? 1 : 0)) /* * These are descriptions of the reasons that can be passed to the -- cgit v1.2.3 From 2fea0c26b82f304f43b3905e56d954cf98a6d0e9 Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Fri, 2 Aug 2024 23:08:19 -0700 Subject: initramfs,lsm: add a security hook to do_populate_rootfs() This patch introduces a new hook to notify security system that the content of initramfs has been unpacked into the rootfs. Upon receiving this notification, the security system can activate a policy to allow only files that originated from the initramfs to execute or load into kernel during the early stages of booting. This approach is crucial for minimizing the attack surface by ensuring that only trusted files from the initramfs are operational in the critical boot phase. Signed-off-by: Fan Wu [PM: subject line tweak] Signed-off-by: Paul Moore --- security/security.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 645a660320cb..fafd2d43cba0 100644 --- a/security/security.c +++ b/security/security.c @@ -5778,3 +5778,13 @@ int security_uring_cmd(struct io_uring_cmd *ioucmd) return call_int_hook(uring_cmd, ioucmd); } #endif /* CONFIG_IO_URING */ + +/** + * security_initramfs_populated() - Notify LSMs that initramfs has been loaded + * + * Tells the LSMs the initramfs has been unpacked into the rootfs. + */ +void security_initramfs_populated(void) +{ + call_void_hook(initramfs_populated); +} -- cgit v1.2.3 From b55d26bd1891423a3cdccf816b386aec8bbefc87 Mon Sep 17 00:00:00 2001 From: Deven Bowers Date: Fri, 2 Aug 2024 23:08:25 -0700 Subject: block,lsm: add LSM blob and new LSM hooks for block devices This patch introduces a new LSM blob to the block_device structure, enabling the security subsystem to store security-sensitive data related to block devices. Currently, for a device mapper's mapped device containing a dm-verity target, critical security information such as the roothash and its signing state are not readily accessible. Specifically, while the dm-verity volume creation process passes the dm-verity roothash and its signature from userspace to the kernel, the roothash is stored privately within the dm-verity target, and its signature is discarded post-verification. This makes it extremely hard for the security subsystem to utilize these data. With the addition of the LSM blob to the block_device structure, the security subsystem can now retain and manage important security metadata such as the roothash and the signing state of a dm-verity by storing them inside the blob. Access decisions can then be based on these stored data. The implementation follows the same approach used for security blobs in other structures like struct file, struct inode, and struct superblock. The initialization of the security blob occurs after the creation of the struct block_device, performed by the security subsystem. Similarly, the security blob is freed by the security subsystem before the struct block_device is deallocated or freed. This patch also introduces a new hook security_bdev_setintegrity() to save block device's integrity data to the new LSM blob. For example, for dm-verity, it can use this hook to expose its roothash and signing state to LSMs, then LSMs can save these data into the LSM blob. Please note that the new hook should be invoked every time the security information is updated to keep these data current. For example, in dm-verity, if the mapping table is reloaded and configured to use a different dm-verity target with a new roothash and signing information, the previously stored data in the LSM blob will become obsolete. It is crucial to re-invoke the hook to refresh these data and ensure they are up to date. This necessity arises from the design of device-mapper, where a device-mapper device is first created, and then targets are subsequently loaded into it. These targets can be modified multiple times during the device's lifetime. Therefore, while the LSM blob is allocated during the creation of the block device, its actual contents are not initialized at this stage and can change substantially over time. This includes alterations from data that the LSM 'trusts' to those it does not, making it essential to handle these changes correctly. Failure to address this dynamic aspect could potentially allow for bypassing LSM checks. Signed-off-by: Deven Bowers Signed-off-by: Fan Wu [PM: merge fuzz, subject line tweaks] Signed-off-by: Paul Moore --- security/security.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index fafd2d43cba0..c7feaa885a0e 100644 --- a/security/security.c +++ b/security/security.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -239,6 +240,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev); lsm_set_blob_size(&needed->lbs_xattr_count, &blob_sizes.lbs_xattr_count); + lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev); } /* Prepare LSM for initialization. */ @@ -419,6 +421,7 @@ static void __init ordered_lsm_init(void) init_debug("task blob size = %d\n", blob_sizes.lbs_task); init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev); init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count); + init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev); /* * Create any kmem_caches needed for blobs @@ -758,6 +761,28 @@ static int lsm_msg_msg_alloc(struct msg_msg *mp) GFP_KERNEL); } +/** + * lsm_bdev_alloc - allocate a composite block_device blob + * @bdev: the block_device that needs a blob + * + * Allocate the block_device blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_bdev_alloc(struct block_device *bdev) +{ + if (blob_sizes.lbs_bdev == 0) { + bdev->bd_security = NULL; + return 0; + } + + bdev->bd_security = kzalloc(blob_sizes.lbs_bdev, GFP_KERNEL); + if (!bdev->bd_security) + return -ENOMEM; + + return 0; +} + /** * lsm_early_task - during initialization allocate a composite task blob * @task: the task that needs a blob @@ -5658,6 +5683,84 @@ int security_locked_down(enum lockdown_reason what) } EXPORT_SYMBOL(security_locked_down); +/** + * security_bdev_alloc() - Allocate a block device LSM blob + * @bdev: block device + * + * Allocate and attach a security structure to @bdev->bd_security. The + * security field is initialized to NULL when the bdev structure is + * allocated. + * + * Return: Return 0 if operation was successful. + */ +int security_bdev_alloc(struct block_device *bdev) +{ + int rc = 0; + + rc = lsm_bdev_alloc(bdev); + if (unlikely(rc)) + return rc; + + rc = call_int_hook(bdev_alloc_security, bdev); + if (unlikely(rc)) + security_bdev_free(bdev); + + return rc; +} +EXPORT_SYMBOL(security_bdev_alloc); + +/** + * security_bdev_free() - Free a block device's LSM blob + * @bdev: block device + * + * Deallocate the bdev security structure and set @bdev->bd_security to NULL. + */ +void security_bdev_free(struct block_device *bdev) +{ + if (!bdev->bd_security) + return; + + call_void_hook(bdev_free_security, bdev); + + kfree(bdev->bd_security); + bdev->bd_security = NULL; +} +EXPORT_SYMBOL(security_bdev_free); + +/** + * security_bdev_setintegrity() - Set the device's integrity data + * @bdev: block device + * @type: type of integrity, e.g. hash digest, signature, etc + * @value: the integrity value + * @size: size of the integrity value + * + * Register a verified integrity measurement of a bdev with LSMs. + * LSMs should free the previously saved data if @value is NULL. + * Please note that the new hook should be invoked every time the security + * information is updated to keep these data current. For example, in dm-verity, + * if the mapping table is reloaded and configured to use a different dm-verity + * target with a new roothash and signing information, the previously stored data + * in the LSM blob will become obsolete. It is crucial to re-invoke the hook to + * refresh these data and ensure they are up to date. This necessity arises from + * the design of device-mapper, where a device-mapper device is first created, and + * then targets are subsequently loaded into it. These targets can be modified + * multiple times during the device's lifetime. Therefore, while the LSM blob is + * allocated during the creation of the block device, its actual contents are + * not initialized at this stage and can change substantially over time. This + * includes alterations from data that the LSMs 'trusts' to those they do not, + * making it essential to handle these changes correctly. Failure to address + * this dynamic aspect could potentially allow for bypassing LSM checks. + * + * Return: Returns 0 on success, negative values on failure. + */ +int security_bdev_setintegrity(struct block_device *bdev, + enum lsm_integrity_type type, const void *value, + size_t size) +{ + return call_int_hook(bdev_setintegrity, bdev, type, value, size); +} +EXPORT_SYMBOL(security_bdev_setintegrity); + #ifdef CONFIG_PERF_EVENTS /** * security_perf_event_open() - Check if a perf event open is allowed -- cgit v1.2.3 From e155858dd99523d4afe0f74e9c26e4f4499eb5af Mon Sep 17 00:00:00 2001 From: Deven Bowers Date: Fri, 2 Aug 2024 23:08:27 -0700 Subject: ipe: add support for dm-verity as a trust provider Allows author of IPE policy to indicate trust for a singular dm-verity volume, identified by roothash, through "dmverity_roothash" and all signed and validated dm-verity volumes, through "dmverity_signature". Signed-off-by: Deven Bowers Signed-off-by: Fan Wu [PM: fixed some line length issues in the comments] Signed-off-by: Paul Moore --- security/security.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index c7feaa885a0e..3160a0173581 100644 --- a/security/security.c +++ b/security/security.c @@ -5739,17 +5739,18 @@ EXPORT_SYMBOL(security_bdev_free); * Please note that the new hook should be invoked every time the security * information is updated to keep these data current. For example, in dm-verity, * if the mapping table is reloaded and configured to use a different dm-verity - * target with a new roothash and signing information, the previously stored data - * in the LSM blob will become obsolete. It is crucial to re-invoke the hook to - * refresh these data and ensure they are up to date. This necessity arises from - * the design of device-mapper, where a device-mapper device is first created, and - * then targets are subsequently loaded into it. These targets can be modified - * multiple times during the device's lifetime. Therefore, while the LSM blob is - * allocated during the creation of the block device, its actual contents are - * not initialized at this stage and can change substantially over time. This - * includes alterations from data that the LSMs 'trusts' to those they do not, - * making it essential to handle these changes correctly. Failure to address - * this dynamic aspect could potentially allow for bypassing LSM checks. + * target with a new roothash and signing information, the previously stored + * data in the LSM blob will become obsolete. It is crucial to re-invoke the + * hook to refresh these data and ensure they are up to date. This necessity + * arises from the design of device-mapper, where a device-mapper device is + * first created, and then targets are subsequently loaded into it. These + * targets can be modified multiple times during the device's lifetime. + * Therefore, while the LSM blob is allocated during the creation of the block + * device, its actual contents are not initialized at this stage and can change + * substantially over time. This includes alterations from data that the LSMs + * 'trusts' to those they do not, making it essential to handle these changes + * correctly. Failure to address this dynamic aspect could potentially allow + * for bypassing LSM checks. * * Return: Returns 0 on success, negative values on failure. */ -- cgit v1.2.3 From fb55e177d5936fb80fb2586036d195c57e7f6892 Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Fri, 2 Aug 2024 23:08:28 -0700 Subject: lsm: add security_inode_setintegrity() hook This patch introduces a new hook to save inode's integrity data. For example, for fsverity enabled files, LSMs can use this hook to save the existence of verified fsverity builtin signature into the inode's security blob, and LSMs can make access decisions based on this data. Signed-off-by: Fan Wu [PM: subject line tweak, removed changelog] Signed-off-by: Paul Moore --- security/security.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 3160a0173581..bb43ad444f1f 100644 --- a/security/security.c +++ b/security/security.c @@ -2716,6 +2716,26 @@ int security_inode_copy_up_xattr(struct dentry *src, const char *name) } EXPORT_SYMBOL(security_inode_copy_up_xattr); +/** + * security_inode_setintegrity() - Set the inode's integrity data + * @inode: inode + * @type: type of integrity, e.g. hash digest, signature, etc + * @value: the integrity value + * @size: size of the integrity value + * + * Register a verified integrity measurement of a inode with LSMs. + * LSMs should free the previously saved data if @value is NULL. + * + * Return: Returns 0 on success, negative values on failure. + */ +int security_inode_setintegrity(const struct inode *inode, + enum lsm_integrity_type type, const void *value, + size_t size) +{ + return call_int_hook(inode_setintegrity, inode, type, value, size); +} +EXPORT_SYMBOL(security_inode_setintegrity); + /** * security_kernfs_init_security() - Init LSM context for a kernfs node * @kn_dir: parent kernfs node -- cgit v1.2.3 From 417c5643cd67a55f424b203b492082035d0236c3 Mon Sep 17 00:00:00 2001 From: KP Singh Date: Fri, 16 Aug 2024 17:43:07 +0200 Subject: lsm: replace indirect LSM hook calls with static calls LSM hooks are currently invoked from a linked list as indirect calls which are invoked using retpolines as a mitigation for speculative attacks (Branch History / Target injection) and add extra overhead which is especially bad in kernel hot paths: security_file_ioctl: 0xff...0320 <+0>: endbr64 0xff...0324 <+4>: push %rbp 0xff...0325 <+5>: push %r15 0xff...0327 <+7>: push %r14 0xff...0329 <+9>: push %rbx 0xff...032a <+10>: mov %rdx,%rbx 0xff...032d <+13>: mov %esi,%ebp 0xff...032f <+15>: mov %rdi,%r14 0xff...0332 <+18>: mov $0xff...7030,%r15 0xff...0339 <+25>: mov (%r15),%r15 0xff...033c <+28>: test %r15,%r15 0xff...033f <+31>: je 0xff...0358 0xff...0341 <+33>: mov 0x18(%r15),%r11 0xff...0345 <+37>: mov %r14,%rdi 0xff...0348 <+40>: mov %ebp,%esi 0xff...034a <+42>: mov %rbx,%rdx 0xff...034d <+45>: call 0xff...2e0 <__x86_indirect_thunk_array+352> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Indirect calls that use retpolines leading to overhead, not just due to extra instruction but also branch misses. 0xff...0352 <+50>: test %eax,%eax 0xff...0354 <+52>: je 0xff...0339 0xff...0356 <+54>: jmp 0xff...035a 0xff...0358 <+56>: xor %eax,%eax 0xff...035a <+58>: pop %rbx 0xff...035b <+59>: pop %r14 0xff...035d <+61>: pop %r15 0xff...035f <+63>: pop %rbp 0xff...0360 <+64>: jmp 0xff...47c4 <__x86_return_thunk> The indirect calls are not really needed as one knows the addresses of enabled LSM callbacks at boot time and only the order can possibly change at boot time with the lsm= kernel command line parameter. An array of static calls is defined per LSM hook and the static calls are updated at boot time once the order has been determined. With the hook now exposed as a static call, one can see that the retpolines are no longer there and the LSM callbacks are invoked directly: security_file_ioctl: 0xff...0ca0 <+0>: endbr64 0xff...0ca4 <+4>: nopl 0x0(%rax,%rax,1) 0xff...0ca9 <+9>: push %rbp 0xff...0caa <+10>: push %r14 0xff...0cac <+12>: push %rbx 0xff...0cad <+13>: mov %rdx,%rbx 0xff...0cb0 <+16>: mov %esi,%ebp 0xff...0cb2 <+18>: mov %rdi,%r14 0xff...0cb5 <+21>: jmp 0xff...0cc7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Static key enabled for SELinux 0xffffffff818f0cb7 <+23>: jmp 0xff...0cde ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Static key enabled for BPF LSM. This is something that is changed to default to false to avoid the existing side effect issues of BPF LSM [1] in a subsequent patch. 0xff...0cb9 <+25>: xor %eax,%eax 0xff...0cbb <+27>: xchg %ax,%ax 0xff...0cbd <+29>: pop %rbx 0xff...0cbe <+30>: pop %r14 0xff...0cc0 <+32>: pop %rbp 0xff...0cc1 <+33>: cs jmp 0xff...0000 <__x86_return_thunk> 0xff...0cc7 <+39>: endbr64 0xff...0ccb <+43>: mov %r14,%rdi 0xff...0cce <+46>: mov %ebp,%esi 0xff...0cd0 <+48>: mov %rbx,%rdx 0xff...0cd3 <+51>: call 0xff...3230 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Direct call to SELinux. 0xff...0cd8 <+56>: test %eax,%eax 0xff...0cda <+58>: jne 0xff...0cbd 0xff...0cdc <+60>: jmp 0xff...0cb7 0xff...0cde <+62>: endbr64 0xff...0ce2 <+66>: mov %r14,%rdi 0xff...0ce5 <+69>: mov %ebp,%esi 0xff...0ce7 <+71>: mov %rbx,%rdx 0xff...0cea <+74>: call 0xff...e220 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Direct call to BPF LSM. 0xff...0cef <+79>: test %eax,%eax 0xff...0cf1 <+81>: jne 0xff...0cbd 0xff...0cf3 <+83>: jmp 0xff...0cb9 0xff...0cf5 <+85>: endbr64 0xff...0cf9 <+89>: mov %r14,%rdi 0xff...0cfc <+92>: mov %ebp,%esi 0xff...0cfe <+94>: mov %rbx,%rdx 0xff...0d01 <+97>: pop %rbx 0xff...0d02 <+98>: pop %r14 0xff...0d04 <+100>: pop %rbp 0xff...0d05 <+101>: ret 0xff...0d06 <+102>: int3 0xff...0d07 <+103>: int3 0xff...0d08 <+104>: int3 0xff...0d09 <+105>: int3 While this patch uses static_branch_unlikely indicating that an LSM hook is likely to be not present. In most cases this is still a better choice as even when an LSM with one hook is added, empty slots are created for all LSM hooks (especially when many LSMs that do not initialize most hooks are present on the system). There are some hooks that don't use the call_int_hook or call_void_hook. These hooks are updated to use a new macro called lsm_for_each_hook where the lsm_callback is directly invoked as an indirect call. Below are results of the relevant Unixbench system benchmarks with BPF LSM and SELinux enabled with default policies enabled with and without these patches. Benchmark Delta(%): (+ is better) ========================================================================== Execl Throughput +1.9356 File Write 1024 bufsize 2000 maxblocks +6.5953 Pipe Throughput +9.5499 Pipe-based Context Switching +3.0209 Process Creation +2.3246 Shell Scripts (1 concurrent) +1.4975 System Call Overhead +2.7815 System Benchmarks Index Score (Partial Only): +3.4859 In the best case, some syscalls like eventfd_create benefitted to about ~10%. Tested-by: Guenter Roeck Reviewed-by: Casey Schaufler Reviewed-by: Kees Cook Acked-by: Song Liu Acked-by: Andrii Nakryiko Signed-off-by: KP Singh Signed-off-by: Paul Moore --- security/security.c | 219 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 155 insertions(+), 64 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index bb43ad444f1f..3b888d5caf47 100644 --- a/security/security.c +++ b/security/security.c @@ -57,6 +57,25 @@ (IS_ENABLED(CONFIG_EVM) ? 1 : 0) + \ (IS_ENABLED(CONFIG_SECURITY_IPE) ? 1 : 0)) +#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX + +/* + * Identifier for the LSM static calls. + * HOOK is an LSM hook as defined in linux/lsm_hookdefs.h + * IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT + */ +#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX + +/* + * Call the macro M for each LSM hook MAX_LSM_COUNT times. + */ +#define LSM_LOOP_UNROLL(M, ...) \ +do { \ + UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \ +} while (0) + +#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) + /* * These are descriptions of the reasons that can be passed to the * security_locked_down() LSM hook. Placing this array here allows @@ -96,7 +115,6 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = { [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", }; -struct security_hook_heads security_hook_heads __ro_after_init; static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); static struct kmem_cache *lsm_file_cache; @@ -115,6 +133,55 @@ static __initconst const char *const builtin_lsm_order = CONFIG_LSM; static __initdata struct lsm_info **ordered_lsms; static __initdata struct lsm_info *exclusive; +#ifdef CONFIG_HAVE_STATIC_CALL +#define LSM_HOOK_TRAMP(NAME, NUM) \ + &STATIC_CALL_TRAMP(LSM_STATIC_CALL(NAME, NUM)) +#else +#define LSM_HOOK_TRAMP(NAME, NUM) NULL +#endif + +/* + * Define static calls and static keys for each LSM hook. + */ +#define DEFINE_LSM_STATIC_CALL(NUM, NAME, RET, ...) \ + DEFINE_STATIC_CALL_NULL(LSM_STATIC_CALL(NAME, NUM), \ + *((RET(*)(__VA_ARGS__))NULL)); \ + DEFINE_STATIC_KEY_FALSE(SECURITY_HOOK_ACTIVE_KEY(NAME, NUM)); + +#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ + LSM_DEFINE_UNROLL(DEFINE_LSM_STATIC_CALL, NAME, RET, __VA_ARGS__) +#include +#undef LSM_HOOK +#undef DEFINE_LSM_STATIC_CALL + +/* + * Initialise a table of static calls for each LSM hook. + * DEFINE_STATIC_CALL_NULL invocation above generates a key (STATIC_CALL_KEY) + * and a trampoline (STATIC_CALL_TRAMP) which are used to call + * __static_call_update when updating the static call. + * + * The static calls table is used by early LSMs, some architectures can fault on + * unaligned accesses and the fault handling code may not be ready by then. + * Thus, the static calls table should be aligned to avoid any unhandled faults + * in early init. + */ +struct lsm_static_calls_table + static_calls_table __ro_after_init __aligned(sizeof(u64)) = { +#define INIT_LSM_STATIC_CALL(NUM, NAME) \ + (struct lsm_static_call) { \ + .key = &STATIC_CALL_KEY(LSM_STATIC_CALL(NAME, NUM)), \ + .trampoline = LSM_HOOK_TRAMP(NAME, NUM), \ + .active = &SECURITY_HOOK_ACTIVE_KEY(NAME, NUM), \ + }, +#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ + .NAME = { \ + LSM_DEFINE_UNROLL(INIT_LSM_STATIC_CALL, NAME) \ + }, +#include +#undef LSM_HOOK +#undef INIT_LSM_STATIC_CALL + }; + static __initdata bool debug; #define init_debug(...) \ do { \ @@ -175,7 +242,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from) if (exists_ordered_lsm(lsm)) return; - if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from)) + if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM static calls!?\n", from)) return; /* Enable this LSM, if it is not already set. */ @@ -360,6 +427,25 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) kfree(sep); } +static void __init lsm_static_call_init(struct security_hook_list *hl) +{ + struct lsm_static_call *scall = hl->scalls; + int i; + + for (i = 0; i < MAX_LSM_COUNT; i++) { + /* Update the first static call that is not used yet */ + if (!scall->hl) { + __static_call_update(scall->key, scall->trampoline, + hl->hook.lsm_func_addr); + scall->hl = hl; + static_branch_enable(scall->active); + return; + } + scall++; + } + panic("%s - Ran out of static slots.\n", __func__); +} + static void __init lsm_early_cred(struct cred *cred); static void __init lsm_early_task(struct task_struct *task); @@ -447,11 +533,6 @@ int __init early_security_init(void) { struct lsm_info *lsm; -#define LSM_HOOK(RET, DEFAULT, NAME, ...) \ - INIT_HLIST_HEAD(&security_hook_heads.NAME); -#include "linux/lsm_hook_defs.h" -#undef LSM_HOOK - for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) { if (!lsm->enabled) lsm->enabled = &lsm_enabled_true; @@ -579,7 +660,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, for (i = 0; i < count; i++) { hooks[i].lsmid = lsmid; - hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); + lsm_static_call_init(&hooks[i]); } /* @@ -893,29 +974,43 @@ out: * call_int_hook: * This is a hook that returns a value. */ +#define __CALL_STATIC_VOID(NUM, HOOK, ...) \ +do { \ + if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ + static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ + } \ +} while (0); -#define call_void_hook(FUNC, ...) \ - do { \ - struct security_hook_list *P; \ - \ - hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ - P->hook.FUNC(__VA_ARGS__); \ +#define call_void_hook(HOOK, ...) \ + do { \ + LSM_LOOP_UNROLL(__CALL_STATIC_VOID, HOOK, __VA_ARGS__); \ } while (0) -#define call_int_hook(FUNC, ...) ({ \ - int RC = LSM_RET_DEFAULT(FUNC); \ - do { \ - struct security_hook_list *P; \ - \ - hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \ - RC = P->hook.FUNC(__VA_ARGS__); \ - if (RC != LSM_RET_DEFAULT(FUNC)) \ - break; \ - } \ - } while (0); \ - RC; \ + +#define __CALL_STATIC_INT(NUM, R, HOOK, LABEL, ...) \ +do { \ + if (static_branch_unlikely(&SECURITY_HOOK_ACTIVE_KEY(HOOK, NUM))) { \ + R = static_call(LSM_STATIC_CALL(HOOK, NUM))(__VA_ARGS__); \ + if (R != LSM_RET_DEFAULT(HOOK)) \ + goto LABEL; \ + } \ +} while (0); + +#define call_int_hook(HOOK, ...) \ +({ \ + __label__ OUT; \ + int RC = LSM_RET_DEFAULT(HOOK); \ + \ + LSM_LOOP_UNROLL(__CALL_STATIC_INT, RC, HOOK, OUT, __VA_ARGS__); \ +OUT: \ + RC; \ }) +#define lsm_for_each_hook(scall, NAME) \ + for (scall = static_calls_table.NAME; \ + scall - static_calls_table.NAME < MAX_LSM_COUNT; scall++) \ + if (static_key_enabled(&scall->active->key)) + /* Security operations */ /** @@ -1150,7 +1245,7 @@ int security_settime64(const struct timespec64 *ts, const struct timezone *tz) */ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { - struct security_hook_list *hp; + struct lsm_static_call *scall; int cap_sys_admin = 1; int rc; @@ -1160,8 +1255,8 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) * agree that it should be set it will. If any module thinks it should * not be set it won't. */ - hlist_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) { - rc = hp->hook.vm_enough_memory(mm, pages); + lsm_for_each_hook(scall, vm_enough_memory) { + rc = scall->hl->hook.vm_enough_memory(mm, pages); if (rc < 0) { cap_sys_admin = 0; break; @@ -1308,13 +1403,12 @@ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { - struct security_hook_list *hp; + struct lsm_static_call *scall; int trc; int rc = -ENOPARAM; - hlist_for_each_entry(hp, &security_hook_heads.fs_context_parse_param, - list) { - trc = hp->hook.fs_context_parse_param(fc, param); + lsm_for_each_hook(scall, fs_context_parse_param) { + trc = scall->hl->hook.fs_context_parse_param(fc, param); if (trc == 0) rc = 0; else if (trc != -ENOPARAM) @@ -1544,12 +1638,11 @@ int security_sb_set_mnt_opts(struct super_block *sb, unsigned long kern_flags, unsigned long *set_kern_flags) { - struct security_hook_list *hp; + struct lsm_static_call *scall; int rc = mnt_opts ? -EOPNOTSUPP : LSM_RET_DEFAULT(sb_set_mnt_opts); - hlist_for_each_entry(hp, &security_hook_heads.sb_set_mnt_opts, - list) { - rc = hp->hook.sb_set_mnt_opts(sb, mnt_opts, kern_flags, + lsm_for_each_hook(scall, sb_set_mnt_opts) { + rc = scall->hl->hook.sb_set_mnt_opts(sb, mnt_opts, kern_flags, set_kern_flags); if (rc != LSM_RET_DEFAULT(sb_set_mnt_opts)) break; @@ -1744,7 +1837,7 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const initxattrs initxattrs, void *fs_data) { - struct security_hook_list *hp; + struct lsm_static_call *scall; struct xattr *new_xattrs = NULL; int ret = -EOPNOTSUPP, xattr_count = 0; @@ -1762,9 +1855,8 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, return -ENOMEM; } - hlist_for_each_entry(hp, &security_hook_heads.inode_init_security, - list) { - ret = hp->hook.inode_init_security(inode, dir, qstr, new_xattrs, + lsm_for_each_hook(scall, inode_init_security) { + ret = scall->hl->hook.inode_init_security(inode, dir, qstr, new_xattrs, &xattr_count); if (ret && ret != -EOPNOTSUPP) goto out; @@ -3611,10 +3703,10 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, { int thisrc; int rc = LSM_RET_DEFAULT(task_prctl); - struct security_hook_list *hp; + struct lsm_static_call *scall; - hlist_for_each_entry(hp, &security_hook_heads.task_prctl, list) { - thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5); + lsm_for_each_hook(scall, task_prctl) { + thisrc = scall->hl->hook.task_prctl(option, arg2, arg3, arg4, arg5); if (thisrc != LSM_RET_DEFAULT(task_prctl)) { rc = thisrc; if (thisrc != 0) @@ -4020,7 +4112,7 @@ EXPORT_SYMBOL(security_d_instantiate); int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, u32 __user *size, u32 flags) { - struct security_hook_list *hp; + struct lsm_static_call *scall; struct lsm_ctx lctx = { .id = LSM_ID_UNDEF, }; u8 __user *base = (u8 __user *)uctx; u32 entrysize; @@ -4058,13 +4150,13 @@ int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, * In the usual case gather all the data from the LSMs. * In the single case only get the data from the LSM specified. */ - hlist_for_each_entry(hp, &security_hook_heads.getselfattr, list) { - if (single && lctx.id != hp->lsmid->id) + lsm_for_each_hook(scall, getselfattr) { + if (single && lctx.id != scall->hl->lsmid->id) continue; entrysize = left; if (base) uctx = (struct lsm_ctx __user *)(base + total); - rc = hp->hook.getselfattr(attr, uctx, &entrysize, flags); + rc = scall->hl->hook.getselfattr(attr, uctx, &entrysize, flags); if (rc == -EOPNOTSUPP) { rc = 0; continue; @@ -4113,7 +4205,7 @@ int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, u32 size, u32 flags) { - struct security_hook_list *hp; + struct lsm_static_call *scall; struct lsm_ctx *lctx; int rc = LSM_RET_DEFAULT(setselfattr); u64 required_len; @@ -4136,9 +4228,9 @@ int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, goto free_out; } - hlist_for_each_entry(hp, &security_hook_heads.setselfattr, list) - if ((hp->lsmid->id) == lctx->id) { - rc = hp->hook.setselfattr(attr, lctx, size, flags); + lsm_for_each_hook(scall, setselfattr) + if ((scall->hl->lsmid->id) == lctx->id) { + rc = scall->hl->hook.setselfattr(attr, lctx, size, flags); break; } @@ -4161,12 +4253,12 @@ free_out: int security_getprocattr(struct task_struct *p, int lsmid, const char *name, char **value) { - struct security_hook_list *hp; + struct lsm_static_call *scall; - hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) { - if (lsmid != 0 && lsmid != hp->lsmid->id) + lsm_for_each_hook(scall, getprocattr) { + if (lsmid != 0 && lsmid != scall->hl->lsmid->id) continue; - return hp->hook.getprocattr(p, name, value); + return scall->hl->hook.getprocattr(p, name, value); } return LSM_RET_DEFAULT(getprocattr); } @@ -4185,12 +4277,12 @@ int security_getprocattr(struct task_struct *p, int lsmid, const char *name, */ int security_setprocattr(int lsmid, const char *name, void *value, size_t size) { - struct security_hook_list *hp; + struct lsm_static_call *scall; - hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) { - if (lsmid != 0 && lsmid != hp->lsmid->id) + lsm_for_each_hook(scall, setprocattr) { + if (lsmid != 0 && lsmid != scall->hl->lsmid->id) continue; - return hp->hook.setprocattr(name, value, size); + return scall->hl->hook.setprocattr(name, value, size); } return LSM_RET_DEFAULT(setprocattr); } @@ -5322,7 +5414,7 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, const struct flowi_common *flic) { - struct security_hook_list *hp; + struct lsm_static_call *scall; int rc = LSM_RET_DEFAULT(xfrm_state_pol_flow_match); /* @@ -5334,9 +5426,8 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, * For speed optimization, we explicitly break the loop rather than * using the macro */ - hlist_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match, - list) { - rc = hp->hook.xfrm_state_pol_flow_match(x, xp, flic); + lsm_for_each_hook(scall, xfrm_state_pol_flow_match) { + rc = scall->hl->hook.xfrm_state_pol_flow_match(x, xp, flic); break; } return rc; -- cgit v1.2.3 From d6bd12e80bf94b055def6ff708e76f836b4b17ad Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 25 Aug 2024 23:05:04 +0900 Subject: lsm: remove LSM_COUNT and LSM_CONFIG_COUNT Because these are equals to MAX_LSM_COUNT. Also, we can avoid dynamic memory allocation for ordered_lsms because MAX_LSM_COUNT is a constant. Signed-off-by: Tetsuo Handa Signed-off-by: Paul Moore --- security/security.c | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 3b888d5caf47..7272bbea05cb 100644 --- a/security/security.c +++ b/security/security.c @@ -33,30 +33,6 @@ #include #include -/* How many LSMs were built into the kernel? */ -#define LSM_COUNT (__end_lsm_info - __start_lsm_info) - -/* - * How many LSMs are built into the kernel as determined at - * build time. Used to determine fixed array sizes. - * The capability module is accounted for by CONFIG_SECURITY - */ -#define LSM_CONFIG_COUNT ( \ - (IS_ENABLED(CONFIG_SECURITY) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_SELINUX) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_SMACK) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_TOMOYO) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_APPARMOR) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_YAMA) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_LOADPIN) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_SAFESETID) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_LOCKDOWN_LSM) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_BPF_LSM) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_LANDLOCK) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_IMA) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_EVM) ? 1 : 0) + \ - (IS_ENABLED(CONFIG_SECURITY_IPE) ? 1 : 0)) - #define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX /* @@ -130,7 +106,7 @@ static __initdata const char *chosen_major_lsm; static __initconst const char *const builtin_lsm_order = CONFIG_LSM; /* Ordered list of LSMs to initialize. */ -static __initdata struct lsm_info **ordered_lsms; +static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1]; static __initdata struct lsm_info *exclusive; #ifdef CONFIG_HAVE_STATIC_CALL @@ -242,7 +218,7 @@ static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from) if (exists_ordered_lsm(lsm)) return; - if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM static calls!?\n", from)) + if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from)) return; /* Enable this LSM, if it is not already set. */ @@ -345,7 +321,7 @@ static void __init initialize_lsm(struct lsm_info *lsm) * Current index to use while initializing the lsm id list. */ u32 lsm_active_cnt __ro_after_init; -const struct lsm_id *lsm_idlist[LSM_CONFIG_COUNT]; +const struct lsm_id *lsm_idlist[MAX_LSM_COUNT]; /* Populate ordered LSMs list from comma-separated LSM name list. */ static void __init ordered_lsm_parse(const char *order, const char *origin) @@ -474,9 +450,6 @@ static void __init ordered_lsm_init(void) { struct lsm_info **lsm; - ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms), - GFP_KERNEL); - if (chosen_lsm_order) { if (chosen_major_lsm) { pr_warn("security=%s is ignored because it is superseded by lsm=%s\n", @@ -525,8 +498,6 @@ static void __init ordered_lsm_init(void) lsm_early_task(current); for (lsm = ordered_lsms; *lsm; lsm++) initialize_lsm(*lsm); - - kfree(ordered_lsms); } int __init early_security_init(void) @@ -653,7 +624,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, * Look at the previous entry, if there is one, for duplication. */ if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) { - if (lsm_active_cnt >= LSM_CONFIG_COUNT) + if (lsm_active_cnt >= MAX_LSM_COUNT) panic("%s Too many LSMs registered.\n", __func__); lsm_idlist[lsm_active_cnt++] = lsmid; } -- cgit v1.2.3 From 19c9d55d72a9040cf9dc8de62633e6217381106b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Wed, 21 Aug 2024 11:56:06 +0200 Subject: security: Update file_set_fowner documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Highlight that the file_set_fowner hook is now called with a lock held. Cc: Al Viro Cc: Casey Schaufler Cc: Christian Brauner Cc: James Morris Cc: Jann Horn Cc: Ondrej Mosnacek Cc: Paul Moore Cc: Serge E. Hallyn Cc: Stephen Smalley Signed-off-by: Mickaël Salaün Signed-off-by: Paul Moore --- security/security.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'security/security.c') diff --git a/security/security.c b/security/security.c index 7272bbea05cb..4564a0a1e4ef 100644 --- a/security/security.c +++ b/security/security.c @@ -3048,6 +3048,8 @@ int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) * Save owner security information (typically from current->security) in * file->f_security for later use by the send_sigiotask hook. * + * This hook is called with file->f_owner.lock held. + * * Return: Returns 0 on success. */ void security_file_set_fowner(struct file *file) -- cgit v1.2.3