diff options
Diffstat (limited to 'security')
27 files changed, 458 insertions, 198 deletions
diff --git a/security/Kconfig b/security/Kconfig index 353cfef71d4e..aeac3676dd4d 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -287,5 +287,7 @@ config LSM If unsure, leave this as the default. +source "security/Kconfig.hardening" + endmenu diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening new file mode 100644 index 000000000000..0a1d4ca314f4 --- /dev/null +++ b/security/Kconfig.hardening @@ -0,0 +1,164 @@ +menu "Kernel hardening options" + +config GCC_PLUGIN_STRUCTLEAK + bool + help + While the kernel is built with warnings enabled for any missed + stack variable initializations, this warning is silenced for + anything passed by reference to another function, under the + occasionally misguided assumption that the function will do + the initialization. As this regularly leads to exploitable + flaws, this plugin is available to identify and zero-initialize + such variables, depending on the chosen level of coverage. + + This plugin was originally ported from grsecurity/PaX. More + information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + +menu "Memory initialization" + +config CC_HAS_AUTO_VAR_INIT + def_bool $(cc-option,-ftrivial-auto-var-init=pattern) + +choice + prompt "Initialize kernel stack variables at function entry" + default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL if COMPILE_TEST && GCC_PLUGINS + default INIT_STACK_ALL if COMPILE_TEST && CC_HAS_AUTO_VAR_INIT + default INIT_STACK_NONE + help + This option enables initialization of stack variables at + function entry time. This has the possibility to have the + greatest coverage (since all functions can have their + variables initialized), but the performance impact depends + on the function calling complexity of a given workload's + syscalls. + + This chooses the level of coverage over classes of potentially + uninitialized variables. The selected class will be + initialized before use in a function. + + config INIT_STACK_NONE + bool "no automatic initialization (weakest)" + help + Disable automatic stack variable initialization. + This leaves the kernel vulnerable to the standard + classes of uninitialized stack variable exploits + and information exposures. + + config GCC_PLUGIN_STRUCTLEAK_USER + bool "zero-init structs marked for userspace (weak)" + depends on GCC_PLUGINS + select GCC_PLUGIN_STRUCTLEAK + help + Zero-initialize any structures on the stack containing + a __user attribute. This can prevent some classes of + uninitialized stack variable exploits and information + exposures, like CVE-2013-2141: + https://git.kernel.org/linus/b9e146d8eb3b9eca + + config GCC_PLUGIN_STRUCTLEAK_BYREF + bool "zero-init structs passed by reference (strong)" + depends on GCC_PLUGINS + select GCC_PLUGIN_STRUCTLEAK + help + Zero-initialize any structures on the stack that may + be passed by reference and had not already been + explicitly initialized. This can prevent most classes + of uninitialized stack variable exploits and information + exposures, like CVE-2017-1000410: + https://git.kernel.org/linus/06e7e776ca4d3654 + + config GCC_PLUGIN_STRUCTLEAK_BYREF_ALL + bool "zero-init anything passed by reference (very strong)" + depends on GCC_PLUGINS + select GCC_PLUGIN_STRUCTLEAK + help + Zero-initialize any stack variables that may be passed + by reference and had not already been explicitly + initialized. This is intended to eliminate all classes + of uninitialized stack variable exploits and information + exposures. + + config INIT_STACK_ALL + bool "0xAA-init everything on the stack (strongest)" + depends on CC_HAS_AUTO_VAR_INIT + help + Initializes everything on the stack with a 0xAA + pattern. This is intended to eliminate all classes + of uninitialized stack variable exploits and information + exposures, even variables that were warned to have been + left uninitialized. + +endchoice + +config GCC_PLUGIN_STRUCTLEAK_VERBOSE + bool "Report forcefully initialized variables" + depends on GCC_PLUGIN_STRUCTLEAK + depends on !COMPILE_TEST # too noisy + help + This option will cause a warning to be printed each time the + structleak plugin finds a variable it thinks needs to be + initialized. Since not all existing initializers are detected + by the plugin, this can produce false positive warnings. + +config GCC_PLUGIN_STACKLEAK + bool "Poison kernel stack before returning from syscalls" + depends on GCC_PLUGINS + depends on HAVE_ARCH_STACKLEAK + help + This option makes the kernel erase the kernel stack before + returning from system calls. This has the effect of leaving + the stack initialized to the poison value, which both reduces + the lifetime of any sensitive stack contents and reduces + potential for uninitialized stack variable exploits or information + exposures (it does not cover functions reaching the same stack + depth as prior functions during the same syscall). This blocks + most uninitialized stack variable attacks, with the performance + impact being driven by the depth of the stack usage, rather than + the function calling complexity. + + The performance impact on a single CPU system kernel compilation + sees a 1% slowdown, other systems and workloads may vary and you + are advised to test this feature on your expected workload before + deploying it. + + This plugin was ported from grsecurity/PaX. More information at: + * https://grsecurity.net/ + * https://pax.grsecurity.net/ + +config STACKLEAK_TRACK_MIN_SIZE + int "Minimum stack frame size of functions tracked by STACKLEAK" + default 100 + range 0 4096 + depends on GCC_PLUGIN_STACKLEAK + help + The STACKLEAK gcc plugin instruments the kernel code for tracking + the lowest border of the kernel stack (and for some other purposes). + It inserts the stackleak_track_stack() call for the functions with + a stack frame size greater than or equal to this parameter. + If unsure, leave the default value 100. + +config STACKLEAK_METRICS + bool "Show STACKLEAK metrics in the /proc file system" + depends on GCC_PLUGIN_STACKLEAK + depends on PROC_FS + help + If this is set, STACKLEAK metrics for every task are available in + the /proc file system. In particular, /proc/<pid>/stack_depth + shows the maximum kernel stack consumption for the current and + previous syscalls. Although this information is not precise, it + can be useful for estimating the STACKLEAK performance impact for + your workloads. + +config STACKLEAK_RUNTIME_DISABLE + bool "Allow runtime disabling of kernel stack erasing" + depends on GCC_PLUGIN_STACKLEAK + help + This option provides 'stack_erasing' sysctl, which can be used in + runtime to control kernel stack erasing for kernels built with + CONFIG_GCC_PLUGIN_STACKLEAK. + +endmenu + +endmenu diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index b9298d2e8165..9ab5613fe07c 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -123,22 +123,16 @@ static int aafs_show_path(struct seq_file *seq, struct dentry *dentry) return 0; } -static void aafs_i_callback(struct rcu_head *head) +static void aafs_free_inode(struct inode *inode) { - struct inode *inode = container_of(head, struct inode, i_rcu); if (S_ISLNK(inode->i_mode)) kfree(inode->i_link); free_inode_nonrcu(inode); } -static void aafs_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, aafs_i_callback); -} - static const struct super_operations aafs_super_ops = { .statfs = simple_statfs, - .destroy_inode = aafs_destroy_inode, + .free_inode = aafs_free_inode, .show_path = aafs_show_path, }; diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c index af03d98c7552..baba63bc66b1 100644 --- a/security/apparmor/crypto.c +++ b/security/apparmor/crypto.c @@ -43,7 +43,6 @@ char *aa_calc_hash(void *data, size_t len) goto fail; desc->tfm = apparmor_tfm; - desc->flags = 0; error = crypto_shash_init(desc); if (error) @@ -81,7 +80,6 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, goto fail; desc->tfm = apparmor_tfm; - desc->flags = 0; error = crypto_shash_init(desc); if (error) diff --git a/security/inode.c b/security/inode.c index 421dd72b5876..aacc4dabba7d 100644 --- a/security/inode.c +++ b/security/inode.c @@ -27,22 +27,16 @@ static struct vfsmount *mount; static int mount_count; -static void securityfs_i_callback(struct rcu_head *head) +static void securityfs_free_inode(struct inode *inode) { - struct inode *inode = container_of(head, struct inode, i_rcu); if (S_ISLNK(inode->i_mode)) kfree(inode->i_link); free_inode_nonrcu(inode); } -static void securityfs_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, securityfs_i_callback); -} - static const struct super_operations securityfs_super_operations = { .statfs = simple_statfs, - .destroy_inode = securityfs_destroy_inode, + .free_inode = securityfs_free_inode, }; static int fill_super(struct super_block *sb, void *data, int silent) diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index d775e03fbbcc..99080871eb9f 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -104,9 +104,16 @@ int asymmetric_verify(struct key *keyring, const char *sig, memset(&pks, 0, sizeof(pks)); - pks.pkey_algo = "rsa"; pks.hash_algo = hash_algo_name[hdr->hash_algo]; - pks.encoding = "pkcs1"; + if (hdr->hash_algo == HASH_ALGO_STREEBOG_256 || + hdr->hash_algo == HASH_ALGO_STREEBOG_512) { + /* EC-RDSA and Streebog should go together. */ + pks.pkey_algo = "ecrdsa"; + pks.encoding = "raw"; + } else { + pks.pkey_algo = "rsa"; + pks.encoding = "pkcs1"; + } pks.digest = (u8 *)data; pks.digest_size = datalen; pks.s = hdr->sig; diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index c37d08118af5..e11564eb645b 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -124,7 +124,6 @@ out: return ERR_PTR(-ENOMEM); desc->tfm = *tfm; - desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; rc = crypto_shash_init(desc); if (rc) { diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 015aea8fdf1e..3f7cbb238923 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -192,7 +192,8 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf, if (count > XATTR_NAME_MAX) return -E2BIG; - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_EVM_XATTR); + ab = audit_log_start(audit_context(), GFP_KERNEL, + AUDIT_INTEGRITY_EVM_XATTR); if (!ab) return -ENOMEM; @@ -214,6 +215,9 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf, if (len && xattr->name[len-1] == '\n') xattr->name[len-1] = '\0'; + audit_log_format(ab, "xattr="); + audit_log_untrustedstring(ab, xattr->name); + if (strcmp(xattr->name, ".") == 0) { evm_xattrs_locked = 1; newattrs.ia_mode = S_IFREG | 0440; @@ -222,15 +226,11 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf, inode_lock(inode); err = simple_setattr(evm_xattrs, &newattrs); inode_unlock(inode); - audit_log_format(ab, "locked"); if (!err) err = count; goto out; } - audit_log_format(ab, "xattr="); - audit_log_untrustedstring(ab, xattr->name); - if (strncmp(xattr->name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) != 0) { err = -EINVAL; diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 16a4f45863b1..a32878e10ebc 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -333,7 +333,6 @@ static int ima_calc_file_hash_tfm(struct file *file, SHASH_DESC_ON_STACK(shash, tfm); shash->tfm = tfm; - shash->flags = 0; hash->length = crypto_shash_digestsize(tfm); @@ -469,7 +468,6 @@ static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, int rc, i; shash->tfm = tfm; - shash->flags = 0; hash->length = crypto_shash_digestsize(tfm); @@ -591,7 +589,6 @@ static int calc_buffer_shash_tfm(const void *buf, loff_t size, int rc; shash->tfm = tfm; - shash->flags = 0; hash->length = crypto_shash_digestsize(tfm); @@ -664,7 +661,6 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest, SHASH_DESC_ON_STACK(shash, tfm); shash->tfm = tfm; - shash->flags = 0; rc = crypto_shash_init(shash); if (rc != 0) diff --git a/security/keys/dh.c b/security/keys/dh.c index 711e89d8c415..23f95dec771b 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -112,7 +112,6 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) if (!sdesc) goto out_free_tfm; sdesc->shash.tfm = tfm; - sdesc->shash.flags = 0x0; *sdesc_ret = sdesc; diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 347108f660a1..1b1456b21a93 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -333,7 +333,6 @@ static int calc_hash(struct crypto_shash *tfm, u8 *digest, int err; desc->tfm = tfm; - desc->flags = 0; err = crypto_shash_digest(desc, buf, buflen, digest); shash_desc_zero(desc); diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 9320424c4a46..f05f7125a7d5 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -58,7 +58,7 @@ int install_user_keyrings(void) kenter("%p{%u}", user, uid); - if (user->uid_keyring && user->session_keyring) { + if (READ_ONCE(user->uid_keyring) && READ_ONCE(user->session_keyring)) { kleave(" = 0 [exist]"); return 0; } @@ -111,8 +111,10 @@ int install_user_keyrings(void) } /* install the keyrings */ - user->uid_keyring = uid_keyring; - user->session_keyring = session_keyring; + /* paired with READ_ONCE() */ + smp_store_release(&user->uid_keyring, uid_keyring); + /* paired with READ_ONCE() */ + smp_store_release(&user->session_keyring, session_keyring); } mutex_unlock(&key_user_keyring_mutex); @@ -227,6 +229,7 @@ static int install_process_keyring(void) * Install the given keyring as the session keyring of the given credentials * struct, replacing the existing one if any. If the given keyring is NULL, * then install a new anonymous session keyring. + * @cred can not be in use by any task yet. * * Return: 0 on success; -errno on failure. */ @@ -254,7 +257,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) /* install the keyring */ old = cred->session_keyring; - rcu_assign_pointer(cred->session_keyring, keyring); + cred->session_keyring = keyring; if (old) key_put(old); @@ -339,6 +342,7 @@ void key_fsgid_changed(struct task_struct *tsk) key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) { key_ref_t key_ref, ret, err; + const struct cred *cred = ctx->cred; /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were * searchable, but we failed to find a key or we found a negative key; @@ -352,9 +356,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) err = ERR_PTR(-EAGAIN); /* search the thread keyring first */ - if (ctx->cred->thread_keyring) { + if (cred->thread_keyring) { key_ref = keyring_search_aux( - make_key_ref(ctx->cred->thread_keyring, 1), ctx); + make_key_ref(cred->thread_keyring, 1), ctx); if (!IS_ERR(key_ref)) goto found; @@ -370,9 +374,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) } /* search the process keyring second */ - if (ctx->cred->process_keyring) { + if (cred->process_keyring) { key_ref = keyring_search_aux( - make_key_ref(ctx->cred->process_keyring, 1), ctx); + make_key_ref(cred->process_keyring, 1), ctx); if (!IS_ERR(key_ref)) goto found; @@ -391,12 +395,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) } /* search the session keyring */ - if (ctx->cred->session_keyring) { - rcu_read_lock(); + if (cred->session_keyring) { key_ref = keyring_search_aux( - make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1), - ctx); - rcu_read_unlock(); + make_key_ref(cred->session_keyring, 1), ctx); if (!IS_ERR(key_ref)) goto found; @@ -415,9 +416,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) } } /* or search the user-session keyring */ - else if (ctx->cred->user->session_keyring) { + else if (READ_ONCE(cred->user->session_keyring)) { key_ref = keyring_search_aux( - make_key_ref(ctx->cred->user->session_keyring, 1), + make_key_ref(READ_ONCE(cred->user->session_keyring), 1), ctx); if (!IS_ERR(key_ref)) goto found; @@ -604,7 +605,7 @@ try_again: goto error; goto reget_creds; } else if (ctx.cred->session_keyring == - ctx.cred->user->session_keyring && + READ_ONCE(ctx.cred->user->session_keyring) && lflags & KEY_LOOKUP_CREATE) { ret = join_session_keyring(NULL); if (ret < 0) @@ -612,15 +613,13 @@ try_again: goto reget_creds; } - rcu_read_lock(); - key = rcu_dereference(ctx.cred->session_keyring); + key = ctx.cred->session_keyring; __key_get(key); - rcu_read_unlock(); key_ref = make_key_ref(key, 1); break; case KEY_SPEC_USER_KEYRING: - if (!ctx.cred->user->uid_keyring) { + if (!READ_ONCE(ctx.cred->user->uid_keyring)) { ret = install_user_keyrings(); if (ret < 0) goto error; @@ -632,7 +631,7 @@ try_again: break; case KEY_SPEC_USER_SESSION_KEYRING: - if (!ctx.cred->user->session_keyring) { + if (!READ_ONCE(ctx.cred->user->session_keyring)) { ret = install_user_keyrings(); if (ret < 0) goto error; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 2f17d84d46f1..75d87f9e0f49 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -142,12 +142,10 @@ static int call_sbin_request_key(struct key *authkey, void *aux) prkey = cred->process_keyring->serial; sprintf(keyring_str[1], "%d", prkey); - rcu_read_lock(); - session = rcu_dereference(cred->session_keyring); + session = cred->session_keyring; if (!session) session = cred->user->session_keyring; sskey = session->serial; - rcu_read_unlock(); sprintf(keyring_str[2], "%d", sskey); @@ -287,10 +285,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) /* fall through */ case KEY_REQKEY_DEFL_SESSION_KEYRING: - rcu_read_lock(); - dest_keyring = key_get( - rcu_dereference(cred->session_keyring)); - rcu_read_unlock(); + dest_keyring = key_get(cred->session_keyring); if (dest_keyring) break; @@ -298,11 +293,12 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) /* fall through */ case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: dest_keyring = - key_get(cred->user->session_keyring); + key_get(READ_ONCE(cred->user->session_keyring)); break; case KEY_REQKEY_DEFL_USER_KEYRING: - dest_keyring = key_get(cred->user->uid_keyring); + dest_keyring = + key_get(READ_ONCE(cred->user->uid_keyring)); break; case KEY_REQKEY_DEFL_GROUP_KEYRING: diff --git a/security/keys/trusted.c b/security/keys/trusted.c index efdbf17f3915..a75b2f0f1230 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -55,7 +55,6 @@ static struct sdesc *init_sdesc(struct crypto_shash *alg) if (!sdesc) return ERR_PTR(-ENOMEM); sdesc->shash.tfm = alg; - sdesc->shash.flags = 0x0; return sdesc; } diff --git a/security/security.c b/security/security.c index 23cbb1a295a3..613a5c00e602 100644 --- a/security/security.c +++ b/security/security.c @@ -866,6 +866,11 @@ int security_add_mnt_opt(const char *option, const char *val, int len, } EXPORT_SYMBOL(security_add_mnt_opt); +int security_move_mount(const struct path *from_path, const struct path *to_path) +{ + return call_int_hook(move_mount, 0, from_path, to_path); +} + int security_inode_alloc(struct inode *inode) { int rc = lsm_inode_alloc(inode); @@ -1318,6 +1323,12 @@ int security_inode_copy_up_xattr(const char *name) } EXPORT_SYMBOL(security_inode_copy_up_xattr); +int security_kernfs_init_security(struct kernfs_node *kn_dir, + struct kernfs_node *kn) +{ + return call_int_hook(kernfs_init_security, 0, kn_dir, kn); +} + int security_file_permission(struct file *file, int mask) { int ret; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1d0b37af2444..c61787b15f27 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -89,6 +89,8 @@ #include <linux/msg.h> #include <linux/shm.h> #include <linux/bpf.h> +#include <linux/kernfs.h> +#include <linux/stringhash.h> /* for hashlen_string() */ #include <uapi/linux/mount.h> #include "avc.h" @@ -751,11 +753,13 @@ static int selinux_set_mnt_opts(struct super_block *sb, if (!strcmp(sb->s_type->name, "debugfs") || !strcmp(sb->s_type->name, "tracefs") || - !strcmp(sb->s_type->name, "sysfs") || - !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "pstore")) + sbsec->flags |= SE_SBGENFS; + + if (!strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "cgroup") || !strcmp(sb->s_type->name, "cgroup2")) - sbsec->flags |= SE_SBGENFS; + sbsec->flags |= SE_SBGENFS | SE_SBGENFS_XATTR; if (!sbsec->behavior) { /* @@ -1354,6 +1358,67 @@ static int selinux_genfs_get_sid(struct dentry *dentry, return rc; } +static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry, + u32 def_sid, u32 *sid) +{ +#define INITCONTEXTLEN 255 + char *context; + unsigned int len; + int rc; + + len = INITCONTEXTLEN; + context = kmalloc(len + 1, GFP_NOFS); + if (!context) + return -ENOMEM; + + context[len] = '\0'; + rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); + if (rc == -ERANGE) { + kfree(context); + + /* Need a larger buffer. Query for the right size. */ + rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0); + if (rc < 0) + return rc; + + len = rc; + context = kmalloc(len + 1, GFP_NOFS); + if (!context) + return -ENOMEM; + + context[len] = '\0'; + rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, + context, len); + } + if (rc < 0) { + kfree(context); + if (rc != -ENODATA) { + pr_warn("SELinux: %s: getxattr returned %d for dev=%s ino=%ld\n", + __func__, -rc, inode->i_sb->s_id, inode->i_ino); + return rc; + } + *sid = def_sid; + return 0; + } + + rc = security_context_to_sid_default(&selinux_state, context, rc, sid, + def_sid, GFP_NOFS); + if (rc) { + char *dev = inode->i_sb->s_id; + unsigned long ino = inode->i_ino; + + if (rc == -EINVAL) { + pr_notice_ratelimited("SELinux: inode=%lu on dev=%s was found to have an invalid context=%s. This indicates you may need to relabel the inode or the filesystem in question.\n", + ino, dev, context); + } else { + pr_warn("SELinux: %s: context_to_sid(%s) returned %d for dev=%s ino=%ld\n", + __func__, context, -rc, dev, ino); + } + } + kfree(context); + return 0; +} + /* The inode's security attributes must be initialized before first use. */ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) { @@ -1362,9 +1427,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent u32 task_sid, sid = 0; u16 sclass; struct dentry *dentry; -#define INITCONTEXTLEN 255 - char *context = NULL; - unsigned len = 0; int rc = 0; if (isec->initialized == LABEL_INITIALIZED) @@ -1432,72 +1494,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent goto out; } - len = INITCONTEXTLEN; - context = kmalloc(len+1, GFP_NOFS); - if (!context) { - rc = -ENOMEM; - dput(dentry); - goto out; - } - context[len] = '\0'; - rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); - if (rc == -ERANGE) { - kfree(context); - - /* Need a larger buffer. Query for the right size. */ - rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0); - if (rc < 0) { - dput(dentry); - goto out; - } - len = rc; - context = kmalloc(len+1, GFP_NOFS); - if (!context) { - rc = -ENOMEM; - dput(dentry); - goto out; - } - context[len] = '\0'; - rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); - } + rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid, + &sid); dput(dentry); - if (rc < 0) { - if (rc != -ENODATA) { - pr_warn("SELinux: %s: getxattr returned " - "%d for dev=%s ino=%ld\n", __func__, - -rc, inode->i_sb->s_id, inode->i_ino); - kfree(context); - goto out; - } - /* Map ENODATA to the default file SID */ - sid = sbsec->def_sid; - rc = 0; - } else { - rc = security_context_to_sid_default(&selinux_state, - context, rc, &sid, - sbsec->def_sid, - GFP_NOFS); - if (rc) { - char *dev = inode->i_sb->s_id; - unsigned long ino = inode->i_ino; - - if (rc == -EINVAL) { - if (printk_ratelimit()) - pr_notice("SELinux: inode=%lu on dev=%s was found to have an invalid " - "context=%s. This indicates you may need to relabel the inode or the " - "filesystem in question.\n", ino, dev, context); - } else { - pr_warn("SELinux: %s: context_to_sid(%s) " - "returned %d for dev=%s ino=%ld\n", - __func__, context, -rc, dev, ino); - } - kfree(context); - /* Leave with the unlabeled SID */ - rc = 0; - break; - } - } - kfree(context); + if (rc) + goto out; break; case SECURITY_FS_USE_TASK: sid = task_sid; @@ -1548,9 +1549,21 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent goto out; rc = selinux_genfs_get_sid(dentry, sclass, sbsec->flags, &sid); - dput(dentry); - if (rc) + if (rc) { + dput(dentry); goto out; + } + + if ((sbsec->flags & SE_SBGENFS_XATTR) && + (inode->i_opflags & IOP_XATTR)) { + rc = inode_doinit_use_xattr(inode, dentry, + sid, &sid); + if (rc) { + dput(dentry); + goto out; + } + } + dput(dentry); } break; } @@ -3371,6 +3384,67 @@ static int selinux_inode_copy_up_xattr(const char *name) return -EOPNOTSUPP; } +/* kernfs node operations */ + +static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, + struct kernfs_node *kn) +{ + const struct task_security_struct *tsec = current_security(); + u32 parent_sid, newsid, clen; + int rc; + char *context; + + rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, NULL, 0); + if (rc == -ENODATA) + return 0; + else if (rc < 0) + return rc; + + clen = (u32)rc; + context = kmalloc(clen, GFP_KERNEL); + if (!context) + return -ENOMEM; + + rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, context, clen); + if (rc < 0) { + kfree(context); + return rc; + } + + rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid, + GFP_KERNEL); + kfree(context); + if (rc) + return rc; + + if (tsec->create_sid) { + newsid = tsec->create_sid; + } else { + u16 secclass = inode_mode_to_security_class(kn->mode); + struct qstr q; + + q.name = kn->name; + q.hash_len = hashlen_string(kn_dir, kn->name); + + rc = security_transition_sid(&selinux_state, tsec->sid, + parent_sid, secclass, &q, + &newsid); + if (rc) + return rc; + } + + rc = security_sid_to_context_force(&selinux_state, newsid, + &context, &clen); + if (rc) + return rc; + + rc = kernfs_xattr_set(kn, XATTR_NAME_SELINUX, context, clen, + XATTR_CREATE); + kfree(context); + return rc; +} + + /* file security operations */ static int selinux_revalidate_file_permission(struct file *file, int mask) @@ -4438,7 +4512,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in struct lsm_network_audit net = {0,}; struct sockaddr_in *addr4 = NULL; struct sockaddr_in6 *addr6 = NULL; - u16 family_sa = address->sa_family; + u16 family_sa; unsigned short snum; u32 sid, node_perm; @@ -4448,6 +4522,9 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in * 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; + family_sa = address->sa_family; switch (family_sa) { case AF_UNSPEC: case AF_INET: @@ -4580,6 +4657,8 @@ 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; @@ -6719,6 +6798,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), + LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security), + LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index b5b7c5aade8c..111121281c47 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -58,6 +58,7 @@ #define SE_SBINITIALIZED 0x0100 #define SE_SBPROC 0x0200 #define SE_SBGENFS 0x0400 +#define SE_SBGENFS_XATTR 0x0800 #define CONTEXT_STR "context" #define FSCONTEXT_STR "fscontext" diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 186e727b737b..6fd9954e1c08 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -288,11 +288,8 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, int rc; struct netlbl_lsm_secattr secattr; struct sk_security_struct *sksec = ep->base.sk->sk_security; - struct sockaddr *addr; struct sockaddr_in addr4; -#if IS_ENABLED(CONFIG_IPV6) struct sockaddr_in6 addr6; -#endif if (ep->base.sk->sk_family != PF_INET && ep->base.sk->sk_family != PF_INET6) @@ -310,16 +307,15 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep, if (ip_hdr(skb)->version == 4) { addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; - addr = (struct sockaddr *)&addr4; -#if IS_ENABLED(CONFIG_IPV6) - } else { + rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr4, &secattr); + } else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) { addr6.sin6_family = AF_INET6; addr6.sin6_addr = ipv6_hdr(skb)->saddr; - addr = (struct sockaddr *)&addr6; -#endif + rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr6, &secattr); + } else { + rc = -EAFNOSUPPORT; } - rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr); if (rc == 0) sksec->nlbl_state = NLBL_LABELED; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index ec62918521b1..cc043bc8fd4c 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1318,14 +1318,11 @@ static int security_sid_to_context_core(struct selinux_state *state, rc = -EINVAL; goto out_unlock; } - if (only_invalid && !context->len) { - scontext = NULL; - scontext_len = 0; + if (only_invalid && !context->len) rc = 0; - } else { + else rc = context_struct_to_string(policydb, context, scontext, scontext_len); - } out_unlock: read_unlock(&state->ss->policy_rwlock); out: diff --git a/security/smack/smack.h b/security/smack/smack.h index cf52af77d15e..e41ca1d58484 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -348,6 +348,7 @@ extern struct list_head smack_onlycap_list; #define SMACK_HASH_SLOTS 16 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; +extern struct kmem_cache *smack_rule_cache; static inline struct task_smack *smack_cred(const struct cred *cred) { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 5c1613519d5a..0de725f88bed 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -59,6 +59,7 @@ DEFINE_MUTEX(smack_ipv6_lock); static LIST_HEAD(smk_ipv6_port_list); #endif static struct kmem_cache *smack_inode_cache; +struct kmem_cache *smack_rule_cache; int smack_enabled; #define A(s) {"smack"#s, sizeof("smack"#s) - 1, Opt_##s} @@ -354,7 +355,7 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, int rc = 0; list_for_each_entry_rcu(orp, ohead, list) { - nrp = kzalloc(sizeof(struct smack_rule), gfp); + nrp = kmem_cache_zalloc(smack_rule_cache, gfp); if (nrp == NULL) { rc = -ENOMEM; break; @@ -1931,7 +1932,7 @@ static void smack_cred_free(struct cred *cred) list_for_each_safe(l, n, &tsp->smk_rules) { rp = list_entry(l, struct smack_rule, list); list_del(&rp->list); - kfree(rp); + kmem_cache_free(smack_rule_cache, rp); } } @@ -2805,13 +2806,17 @@ static int smack_socket_socketpair(struct socket *socka, * * Records the label bound to a port. * - * Returns 0 + * Returns 0 on success, and error code otherwise */ static int smack_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { - if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) + if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) { + if (addrlen < SIN6_LEN_RFC2133 || + address->sa_family != AF_INET6) + return -EINVAL; smk_ipv6_port_label(sock, address); + } return 0; } #endif /* SMACK_IPV6_PORT_LABELING */ @@ -2847,12 +2852,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, switch (sock->sk->sk_family) { case PF_INET: - if (addrlen < sizeof(struct sockaddr_in)) + if (addrlen < sizeof(struct sockaddr_in) || + sap->sa_family != AF_INET) return -EINVAL; rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); break; case PF_INET6: - if (addrlen < sizeof(struct sockaddr_in6)) + if (addrlen < SIN6_LEN_RFC2133 || sap->sa_family != AF_INET6) return -EINVAL; #ifdef SMACK_IPV6_SECMARK_LABELING rsp = smack_ipv6host_label(sip); @@ -3682,9 +3688,16 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, switch (sock->sk->sk_family) { case AF_INET: + if (msg->msg_namelen < sizeof(struct sockaddr_in) || + sip->sin_family != AF_INET) + return -EINVAL; rc = smack_netlabel_send(sock->sk, sip); break; +#if IS_ENABLED(CONFIG_IPV6) case AF_INET6: + if (msg->msg_namelen < SIN6_LEN_RFC2133 || + sap->sin6_family != AF_INET6) + return -EINVAL; #ifdef SMACK_IPV6_SECMARK_LABELING rsp = smack_ipv6host_label(sap); if (rsp != NULL) @@ -3694,6 +3707,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, #ifdef SMACK_IPV6_PORT_LABELING rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); #endif +#endif /* IS_ENABLED(CONFIG_IPV6) */ break; } return rc; @@ -3906,6 +3920,8 @@ access_check: #ifdef SMACK_IPV6_SECMARK_LABELING if (skb && skb->secmark != 0) skp = smack_from_secid(skb->secmark); + else if (smk_ipv6_localhost(&sadd)) + break; else skp = smack_ipv6host_label(&sadd); if (skp == NULL) @@ -4758,6 +4774,12 @@ static __init int smack_init(void) if (!smack_inode_cache) return -ENOMEM; + smack_rule_cache = KMEM_CACHE(smack_rule, 0); + if (!smack_rule_cache) { + kmem_cache_destroy(smack_inode_cache); + return -ENOMEM; + } + /* * Set the security state for the initial task. */ diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index faf2ea3968b3..47f73a0dabb1 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -67,7 +67,6 @@ enum smk_inos { /* * List locks */ -static DEFINE_MUTEX(smack_master_list_lock); static DEFINE_MUTEX(smack_cipso_lock); static DEFINE_MUTEX(smack_ambient_lock); static DEFINE_MUTEX(smk_net4addr_lock); @@ -134,15 +133,7 @@ LIST_HEAD(smk_net6addr_list); /* * Rule lists are maintained for each label. - * This master list is just for reading /smack/load and /smack/load2. */ -struct smack_master_list { - struct list_head list; - struct smack_rule *smk_rule; -}; - -static LIST_HEAD(smack_rule_list); - struct smack_parsed_rule { struct smack_known *smk_subject; struct smack_known *smk_object; @@ -211,7 +202,6 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) * @srp: the rule to add or replace * @rule_list: the list of rules * @rule_lock: the rule list lock - * @global: if non-zero, indicates a global rule * * Looks through the current subject/object/access list for * the subject/object pair and replaces the access that was @@ -223,10 +213,9 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) */ static int smk_set_access(struct smack_parsed_rule *srp, struct list_head *rule_list, - struct mutex *rule_lock, int global) + struct mutex *rule_lock) { struct smack_rule *sp; - struct smack_master_list *smlp; int found = 0; int rc = 0; @@ -247,7 +236,7 @@ static int smk_set_access(struct smack_parsed_rule *srp, } if (found == 0) { - sp = kzalloc(sizeof(*sp), GFP_KERNEL); + sp = kmem_cache_zalloc(smack_rule_cache, GFP_KERNEL); if (sp == NULL) { rc = -ENOMEM; goto out; @@ -258,22 +247,6 @@ static int smk_set_access(struct smack_parsed_rule *srp, sp->smk_access = srp->smk_access1 & ~srp->smk_access2; list_add_rcu(&sp->list, rule_list); - /* - * If this is a global as opposed to self and a new rule - * it needs to get added for reporting. - */ - if (global) { - mutex_unlock(rule_lock); - smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); - if (smlp != NULL) { - smlp->smk_rule = sp; - mutex_lock(&smack_master_list_lock); - list_add_rcu(&smlp->list, &smack_rule_list); - mutex_unlock(&smack_master_list_lock); - } else - rc = -ENOMEM; - return rc; - } } out: @@ -540,9 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, if (rule_list == NULL) rc = smk_set_access(&rule, &rule.smk_subject->smk_rules, - &rule.smk_subject->smk_rules_lock, 1); + &rule.smk_subject->smk_rules_lock); else - rc = smk_set_access(&rule, rule_list, rule_lock, 0); + rc = smk_set_access(&rule, rule_list, rule_lock); if (rc) goto out; @@ -636,21 +609,23 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) static void *load2_seq_start(struct seq_file *s, loff_t *pos) { - return smk_seq_start(s, pos, &smack_rule_list); + return smk_seq_start(s, pos, &smack_known_list); } static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos) { - return smk_seq_next(s, v, pos, &smack_rule_list); + return smk_seq_next(s, v, pos, &smack_known_list); } static int load_seq_show(struct seq_file *s, void *v) { struct list_head *list = v; - struct smack_master_list *smlp = - list_entry_rcu(list, struct smack_master_list, list); + struct smack_rule *srp; + struct smack_known *skp = + list_entry_rcu(list, struct smack_known, list); - smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); + list_for_each_entry_rcu(srp, &skp->smk_rules, list) + smk_rule_show(s, srp, SMK_LABELLEN); return 0; } @@ -2352,10 +2327,12 @@ static const struct file_operations smk_access_ops = { static int load2_seq_show(struct seq_file *s, void *v) { struct list_head *list = v; - struct smack_master_list *smlp = - list_entry_rcu(list, struct smack_master_list, list); + struct smack_rule *srp; + struct smack_known *skp = + list_entry_rcu(list, struct smack_known, list); - smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); + list_for_each_entry_rcu(srp, &skp->smk_rules, list) + smk_rule_show(s, srp, SMK_LONGLABEL); return 0; } diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig index 404dce66952a..a00ab7eb6181 100644 --- a/security/tomoyo/Kconfig +++ b/security/tomoyo/Kconfig @@ -74,3 +74,13 @@ config SECURITY_TOMOYO_ACTIVATION_TRIGGER You can override this setting via TOMOYO_trigger= kernel command line option. For example, if you pass init=/bin/systemd option, you may want to also pass TOMOYO_trigger=/bin/systemd option. + +config SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING + bool "Use insecure built-in settings for fuzzing tests." + default n + depends on SECURITY_TOMOYO + select SECURITY_TOMOYO_OMIT_USERSPACE_LOADER + help + Enabling this option forces minimal built-in policy and disables + domain/program checks for run-time policy modifications. Please enable + this option only if this kernel is built for doing fuzzing tests. diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 57988d95d33d..dd3d5942e669 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -940,7 +940,7 @@ static bool tomoyo_manager(void) const char *exe; const struct task_struct *task = current; const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname; - bool found = false; + bool found = IS_ENABLED(CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING); if (!tomoyo_policy_loaded) return true; @@ -2810,6 +2810,16 @@ void tomoyo_check_profile(void) */ void __init tomoyo_load_builtin_policy(void) { +#ifdef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING + static char tomoyo_builtin_profile[] __initdata = + "PROFILE_VERSION=20150505\n" + "0-CONFIG={ mode=learning grant_log=no reject_log=yes }\n"; + static char tomoyo_builtin_exception_policy[] __initdata = + "aggregator proc:/self/exe /proc/self/exe\n"; + static char tomoyo_builtin_domain_policy[] __initdata = ""; + static char tomoyo_builtin_manager[] __initdata = ""; + static char tomoyo_builtin_stat[] __initdata = ""; +#else /* * This include file is manually created and contains built-in policy * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy", @@ -2817,6 +2827,7 @@ void __init tomoyo_load_builtin_policy(void) * "tomoyo_builtin_stat" in the form of "static char [] __initdata". */ #include "builtin-policy.h" +#endif u8 i; const int idx = tomoyo_read_lock(); diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c index 9094f4b3b367..f9ff121d7e1e 100644 --- a/security/tomoyo/network.c +++ b/security/tomoyo/network.c @@ -505,6 +505,8 @@ static int tomoyo_check_inet_address(const struct sockaddr *addr, { struct tomoyo_inet_addr_info *i = &address->inet; + if (addr_len < offsetofend(struct sockaddr, sa_family)) + return 0; switch (addr->sa_family) { case AF_INET6: if (addr_len < SIN6_LEN_RFC2133) @@ -594,6 +596,8 @@ static int tomoyo_check_unix_address(struct sockaddr *addr, { struct tomoyo_unix_addr_info *u = &address->unix0; + if (addr_len < offsetofend(struct sockaddr, sa_family)) + return 0; if (addr->sa_family != AF_UNIX) return 0; u->addr = ((struct sockaddr_un *) addr)->sun_path; diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 85e6e31dd1e5..e7832448d721 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -295,7 +295,8 @@ char *tomoyo_realpath_from_path(const struct path *path) * or dentry without vfsmount. */ if (!path->mnt || - (!inode->i_op->rename)) + (!inode->i_op->rename && + !(sb->s_type->fs_flags & FS_REQUIRES_DEV))) pos = tomoyo_get_local_path(path->dentry, buf, buf_len - 1); /* Get absolute name for the rest. */ diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 0517cbdd7275..52752e1a84ed 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c @@ -1076,8 +1076,10 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true; /* r->granted = false; */ tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]); +#ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n", domain->domainname->name); +#endif } return false; } |