mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-26 06:33:19 -04:00
Linux 5.4-rc1
-----BEGIN PGP SIGNATURE----- iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAl2SPPkeHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiG3dcH/2iCaNvD0Ify+Ke/ d0Ncf7KhBejfW1pjGjfpfbAQkdaY/gSLsWPJmQ2HT00SmnTJ4y3zvr/HmEE8mIBA fMzY4TFHMRNNEOrCugoNxzjU5ycgIMq5doontDdHeS7Pfa8mgDLLwH/dzoORA0+b T1ZZT3yDsQ92/jW97LEhTv7UcKqgBdVT5PauU/pe6LHpqmzn8XwdiKaNTM1uY8vw U9rIrYnfxCuLfxyK7xUp6bRUlqluZrY4U+pqEnGOVlFYX1xMjjPIE9sDHJ/z5WvY JSH4/aOqVxRII2oU0+uITsO658tS912iUsa8++F6Z5R1gZSqQD1FqrvW7Z0S58Ay vjXIX3Q= =epsM -----END PGP SIGNATURE----- Merge 5.4-rc1 into android-mainline Linux 5.4-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I15eec52df70f829acf81ff614a1c2a5fb443a4e0
This commit is contained in:
commit
cb33d78781
435 changed files with 8519 additions and 3590 deletions
|
|
@ -246,6 +246,7 @@ source "security/apparmor/Kconfig"
|
|||
source "security/loadpin/Kconfig"
|
||||
source "security/yama/Kconfig"
|
||||
source "security/safesetid/Kconfig"
|
||||
source "security/lockdown/Kconfig"
|
||||
|
||||
source "security/integrity/Kconfig"
|
||||
|
||||
|
|
@ -285,11 +286,11 @@ endchoice
|
|||
|
||||
config LSM
|
||||
string "Ordered list of enabled LSMs"
|
||||
default "yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK
|
||||
default "yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR
|
||||
default "yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO
|
||||
default "yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC
|
||||
default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
|
||||
default "lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK
|
||||
default "lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR
|
||||
default "lockdown,yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO
|
||||
default "lockdown,yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC
|
||||
default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
|
||||
help
|
||||
A comma-separated list of LSMs, in initialization order.
|
||||
Any LSMs left off this list will be ignored. This can be
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
|
|||
subdir-$(CONFIG_SECURITY_YAMA) += yama
|
||||
subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
|
||||
subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid
|
||||
subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown
|
||||
|
||||
# always enable default capabilities
|
||||
obj-y += commoncap.o
|
||||
|
|
@ -27,6 +28,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
|
|||
obj-$(CONFIG_SECURITY_YAMA) += yama/
|
||||
obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
|
||||
obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/
|
||||
obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/
|
||||
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
|
||||
|
||||
# Object integrity file lists
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ if INTEGRITY
|
|||
|
||||
config INTEGRITY_SIGNATURE
|
||||
bool "Digital signature verification using multiple keyrings"
|
||||
depends on KEYS
|
||||
default n
|
||||
select KEYS
|
||||
select SIGNATURE
|
||||
help
|
||||
This option enables digital signature verification support
|
||||
|
|
|
|||
|
|
@ -39,11 +39,10 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
|
|||
#define restrict_link_to_ima restrict_link_by_builtin_trusted
|
||||
#endif
|
||||
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
const char *digest, int digestlen)
|
||||
static struct key *integrity_keyring_from_id(const unsigned int id)
|
||||
{
|
||||
if (id >= INTEGRITY_KEYRING_MAX || siglen < 2)
|
||||
return -EINVAL;
|
||||
if (id >= INTEGRITY_KEYRING_MAX)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!keyring[id]) {
|
||||
keyring[id] =
|
||||
|
|
@ -52,23 +51,49 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
|||
int err = PTR_ERR(keyring[id]);
|
||||
pr_err("no %s keyring: %d\n", keyring_name[id], err);
|
||||
keyring[id] = NULL;
|
||||
return err;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
|
||||
return keyring[id];
|
||||
}
|
||||
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
const char *digest, int digestlen)
|
||||
{
|
||||
struct key *keyring;
|
||||
|
||||
if (siglen < 2)
|
||||
return -EINVAL;
|
||||
|
||||
keyring = integrity_keyring_from_id(id);
|
||||
if (IS_ERR(keyring))
|
||||
return PTR_ERR(keyring);
|
||||
|
||||
switch (sig[1]) {
|
||||
case 1:
|
||||
/* v1 API expect signature without xattr type */
|
||||
return digsig_verify(keyring[id], sig + 1, siglen - 1,
|
||||
digest, digestlen);
|
||||
return digsig_verify(keyring, sig + 1, siglen - 1, digest,
|
||||
digestlen);
|
||||
case 2:
|
||||
return asymmetric_verify(keyring[id], sig, siglen,
|
||||
digest, digestlen);
|
||||
return asymmetric_verify(keyring, sig, siglen, digest,
|
||||
digestlen);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int integrity_modsig_verify(const unsigned int id, const struct modsig *modsig)
|
||||
{
|
||||
struct key *keyring;
|
||||
|
||||
keyring = integrity_keyring_from_id(id);
|
||||
if (IS_ERR(keyring))
|
||||
return PTR_ERR(keyring);
|
||||
|
||||
return ima_modsig_verify(keyring, modsig);
|
||||
}
|
||||
|
||||
static int __init __integrity_init_keyring(const unsigned int id,
|
||||
key_perm_t perm,
|
||||
struct key_restriction *restriction)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ config IMA_APPRAISE
|
|||
|
||||
config IMA_ARCH_POLICY
|
||||
bool "Enable loading an IMA architecture specific policy"
|
||||
depends on (KEXEC_VERIFY_SIG && IMA) || IMA_APPRAISE \
|
||||
depends on (KEXEC_SIG && IMA) || IMA_APPRAISE \
|
||||
&& INTEGRITY_ASYMMETRIC_KEYS
|
||||
default n
|
||||
help
|
||||
|
|
@ -233,6 +233,19 @@ config IMA_APPRAISE_BOOTPARAM
|
|||
This option enables the different "ima_appraise=" modes
|
||||
(eg. fix, log) from the boot command line.
|
||||
|
||||
config IMA_APPRAISE_MODSIG
|
||||
bool "Support module-style signatures for appraisal"
|
||||
depends on IMA_APPRAISE
|
||||
depends on INTEGRITY_ASYMMETRIC_KEYS
|
||||
select PKCS7_MESSAGE_PARSER
|
||||
select MODULE_SIG_FORMAT
|
||||
default n
|
||||
help
|
||||
Adds support for signatures appended to files. The format of the
|
||||
appended signature is the same used for signed kernel modules.
|
||||
The modsig keyword can be used in the IMA policy to allow a hook
|
||||
to accept such signatures.
|
||||
|
||||
config IMA_TRUSTED_KEYRING
|
||||
bool "Require all keys on the .ima keyring be signed (deprecated)"
|
||||
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@ obj-$(CONFIG_IMA) += ima.o
|
|||
ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
|
||||
ima_policy.o ima_template.o ima_template_lib.o
|
||||
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
|
||||
ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
|
||||
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
|
||||
obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ struct ima_event_data {
|
|||
const unsigned char *filename;
|
||||
struct evm_ima_xattr_data *xattr_value;
|
||||
int xattr_len;
|
||||
const struct modsig *modsig;
|
||||
const char *violation;
|
||||
const void *buf;
|
||||
int buf_len;
|
||||
|
|
@ -113,6 +114,8 @@ struct ima_kexec_hdr {
|
|||
u64 count;
|
||||
};
|
||||
|
||||
extern const int read_idmap[];
|
||||
|
||||
#ifdef CONFIG_HAVE_IMA_KEXEC
|
||||
void ima_load_kexec_buffer(void);
|
||||
#else
|
||||
|
|
@ -149,6 +152,7 @@ int template_desc_init_fields(const char *template_fmt,
|
|||
int *num_fields);
|
||||
struct ima_template_desc *ima_template_desc_current(void);
|
||||
struct ima_template_desc *lookup_template_desc(const char *name);
|
||||
bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
|
||||
int ima_restore_measurement_entry(struct ima_template_entry *entry);
|
||||
int ima_restore_measurement_list(loff_t bufsize, void *buf);
|
||||
int ima_measurements_show(struct seq_file *m, void *v);
|
||||
|
|
@ -196,6 +200,10 @@ enum ima_hooks {
|
|||
__ima_hooks(__ima_hook_enumify)
|
||||
};
|
||||
|
||||
extern const char *const func_tokens[];
|
||||
|
||||
struct modsig;
|
||||
|
||||
/* LIM API function definitions */
|
||||
int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
|
||||
int mask, enum ima_hooks func, int *pcr,
|
||||
|
|
@ -203,11 +211,11 @@ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
|
|||
int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
|
||||
int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, void *buf, loff_t size,
|
||||
enum hash_algo algo);
|
||||
enum hash_algo algo, struct modsig *modsig);
|
||||
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, int pcr,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
struct ima_template_desc *template_desc);
|
||||
void ima_audit_measurement(struct integrity_iint_cache *iint,
|
||||
const unsigned char *filename);
|
||||
|
|
@ -249,7 +257,7 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|||
struct integrity_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len);
|
||||
int xattr_len, const struct modsig *modsig);
|
||||
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
|
||||
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
|
||||
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
|
||||
|
|
@ -265,7 +273,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
|
|||
struct file *file,
|
||||
const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len)
|
||||
int xattr_len,
|
||||
const struct modsig *modsig)
|
||||
{
|
||||
return INTEGRITY_UNKNOWN;
|
||||
}
|
||||
|
|
@ -302,6 +311,51 @@ static inline int ima_read_xattr(struct dentry *dentry,
|
|||
|
||||
#endif /* CONFIG_IMA_APPRAISE */
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE_MODSIG
|
||||
bool ima_hook_supports_modsig(enum ima_hooks func);
|
||||
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
struct modsig **modsig);
|
||||
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
|
||||
int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
|
||||
const u8 **digest, u32 *digest_size);
|
||||
int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
|
||||
u32 *data_len);
|
||||
void ima_free_modsig(struct modsig *modsig);
|
||||
#else
|
||||
static inline bool ima_hook_supports_modsig(enum ima_hooks func)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
|
||||
loff_t buf_len, struct modsig **modsig)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void ima_collect_modsig(struct modsig *modsig, const void *buf,
|
||||
loff_t size)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ima_get_modsig_digest(const struct modsig *modsig,
|
||||
enum hash_algo *algo, const u8 **digest,
|
||||
u32 *digest_size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int ima_get_raw_modsig(const struct modsig *modsig,
|
||||
const void **data, u32 *data_len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void ima_free_modsig(struct modsig *modsig)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_IMA_APPRAISE_MODSIG */
|
||||
|
||||
/* LSM based policy rules require audit */
|
||||
#ifdef CONFIG_IMA_LSM_RULES
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
|
|||
else
|
||||
template_desc = ima_template_desc_current();
|
||||
|
||||
*entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
|
||||
sizeof(struct ima_field_data), GFP_NOFS);
|
||||
*entry = kzalloc(struct_size(*entry, template_data,
|
||||
template_desc->num_fields), GFP_NOFS);
|
||||
if (!*entry)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
|
|||
*/
|
||||
int ima_collect_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, void *buf, loff_t size,
|
||||
enum hash_algo algo)
|
||||
enum hash_algo algo, struct modsig *modsig)
|
||||
{
|
||||
const char *audit_cause = "failed";
|
||||
struct inode *inode = file_inode(file);
|
||||
|
|
@ -219,6 +219,14 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
|
|||
char digest[IMA_MAX_DIGEST_SIZE];
|
||||
} hash;
|
||||
|
||||
/*
|
||||
* Always collect the modsig, because IMA might have already collected
|
||||
* the file digest without collecting the modsig in a previous
|
||||
* measurement rule.
|
||||
*/
|
||||
if (modsig)
|
||||
ima_collect_modsig(modsig, buf, size);
|
||||
|
||||
if (iint->flags & IMA_COLLECTED)
|
||||
goto out;
|
||||
|
||||
|
|
@ -285,7 +293,7 @@ out:
|
|||
void ima_store_measurement(struct integrity_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, int pcr,
|
||||
int xattr_len, const struct modsig *modsig, int pcr,
|
||||
struct ima_template_desc *template_desc)
|
||||
{
|
||||
static const char op[] = "add_template_measure";
|
||||
|
|
@ -297,10 +305,17 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
|
|||
.file = file,
|
||||
.filename = filename,
|
||||
.xattr_value = xattr_value,
|
||||
.xattr_len = xattr_len };
|
||||
.xattr_len = xattr_len,
|
||||
.modsig = modsig };
|
||||
int violation = 0;
|
||||
|
||||
if (iint->measured_pcrs & (0x1 << pcr))
|
||||
/*
|
||||
* We still need to store the measurement in the case of MODSIG because
|
||||
* we only have its contents to put in the list at the time of
|
||||
* appraisal, but a file measurement from earlier might already exist in
|
||||
* the measurement list.
|
||||
*/
|
||||
if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
|
||||
return;
|
||||
|
||||
result = ima_alloc_init_template(&event_data, &entry, template_desc);
|
||||
|
|
|
|||
|
|
@ -199,6 +199,110 @@ int ima_read_xattr(struct dentry *dentry,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* xattr_verify - verify xattr digest or signature
|
||||
*
|
||||
* Verify whether the hash or signature matches the file contents.
|
||||
*
|
||||
* Return 0 on success, error code otherwise.
|
||||
*/
|
||||
static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
|
||||
struct evm_ima_xattr_data *xattr_value, int xattr_len,
|
||||
enum integrity_status *status, const char **cause)
|
||||
{
|
||||
int rc = -EINVAL, hash_start = 0;
|
||||
|
||||
switch (xattr_value->type) {
|
||||
case IMA_XATTR_DIGEST_NG:
|
||||
/* first byte contains algorithm id */
|
||||
hash_start = 1;
|
||||
/* fall through */
|
||||
case IMA_XATTR_DIGEST:
|
||||
if (iint->flags & IMA_DIGSIG_REQUIRED) {
|
||||
*cause = "IMA-signature-required";
|
||||
*status = INTEGRITY_FAIL;
|
||||
break;
|
||||
}
|
||||
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
|
||||
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
|
||||
iint->ima_hash->length)
|
||||
/*
|
||||
* xattr length may be longer. md5 hash in previous
|
||||
* version occupied 20 bytes in xattr, instead of 16
|
||||
*/
|
||||
rc = memcmp(&xattr_value->data[hash_start],
|
||||
iint->ima_hash->digest,
|
||||
iint->ima_hash->length);
|
||||
else
|
||||
rc = -EINVAL;
|
||||
if (rc) {
|
||||
*cause = "invalid-hash";
|
||||
*status = INTEGRITY_FAIL;
|
||||
break;
|
||||
}
|
||||
*status = INTEGRITY_PASS;
|
||||
break;
|
||||
case EVM_IMA_XATTR_DIGSIG:
|
||||
set_bit(IMA_DIGSIG, &iint->atomic_flags);
|
||||
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
|
||||
(const char *)xattr_value,
|
||||
xattr_len,
|
||||
iint->ima_hash->digest,
|
||||
iint->ima_hash->length);
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
*status = INTEGRITY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
|
||||
func == KEXEC_KERNEL_CHECK)
|
||||
rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
|
||||
(const char *)xattr_value,
|
||||
xattr_len,
|
||||
iint->ima_hash->digest,
|
||||
iint->ima_hash->length);
|
||||
if (rc) {
|
||||
*cause = "invalid-signature";
|
||||
*status = INTEGRITY_FAIL;
|
||||
} else {
|
||||
*status = INTEGRITY_PASS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*status = INTEGRITY_UNKNOWN;
|
||||
*cause = "unknown-ima-data";
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* modsig_verify - verify modsig signature
|
||||
*
|
||||
* Verify whether the signature matches the file contents.
|
||||
*
|
||||
* Return 0 on success, error code otherwise.
|
||||
*/
|
||||
static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
|
||||
enum integrity_status *status, const char **cause)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
|
||||
if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
|
||||
func == KEXEC_KERNEL_CHECK)
|
||||
rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM,
|
||||
modsig);
|
||||
if (rc) {
|
||||
*cause = "invalid-signature";
|
||||
*status = INTEGRITY_FAIL;
|
||||
} else {
|
||||
*status = INTEGRITY_PASS;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_appraise_measurement - appraise file measurement
|
||||
*
|
||||
|
|
@ -211,19 +315,22 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|||
struct integrity_iint_cache *iint,
|
||||
struct file *file, const unsigned char *filename,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len)
|
||||
int xattr_len, const struct modsig *modsig)
|
||||
{
|
||||
static const char op[] = "appraise_data";
|
||||
const char *cause = "unknown";
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
struct inode *inode = d_backing_inode(dentry);
|
||||
enum integrity_status status = INTEGRITY_UNKNOWN;
|
||||
int rc = xattr_len, hash_start = 0;
|
||||
int rc = xattr_len;
|
||||
bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
|
||||
|
||||
if (!(inode->i_opflags & IOP_XATTR))
|
||||
/* If not appraising a modsig, we need an xattr. */
|
||||
if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
|
||||
return INTEGRITY_UNKNOWN;
|
||||
|
||||
if (rc <= 0) {
|
||||
/* If reading the xattr failed and there's no modsig, error out. */
|
||||
if (rc <= 0 && !try_modsig) {
|
||||
if (rc && rc != -ENODATA)
|
||||
goto out;
|
||||
|
||||
|
|
@ -246,6 +353,10 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|||
case INTEGRITY_UNKNOWN:
|
||||
break;
|
||||
case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */
|
||||
/* It's fine not to have xattrs when using a modsig. */
|
||||
if (try_modsig)
|
||||
break;
|
||||
/* fall through */
|
||||
case INTEGRITY_NOLABEL: /* No security.evm xattr. */
|
||||
cause = "missing-HMAC";
|
||||
goto out;
|
||||
|
|
@ -256,65 +367,18 @@ int ima_appraise_measurement(enum ima_hooks func,
|
|||
WARN_ONCE(true, "Unexpected integrity status %d\n", status);
|
||||
}
|
||||
|
||||
switch (xattr_value->type) {
|
||||
case IMA_XATTR_DIGEST_NG:
|
||||
/* first byte contains algorithm id */
|
||||
hash_start = 1;
|
||||
/* fall through */
|
||||
case IMA_XATTR_DIGEST:
|
||||
if (iint->flags & IMA_DIGSIG_REQUIRED) {
|
||||
cause = "IMA-signature-required";
|
||||
status = INTEGRITY_FAIL;
|
||||
break;
|
||||
}
|
||||
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
|
||||
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
|
||||
iint->ima_hash->length)
|
||||
/* xattr length may be longer. md5 hash in previous
|
||||
version occupied 20 bytes in xattr, instead of 16
|
||||
*/
|
||||
rc = memcmp(&xattr_value->data[hash_start],
|
||||
iint->ima_hash->digest,
|
||||
iint->ima_hash->length);
|
||||
else
|
||||
rc = -EINVAL;
|
||||
if (rc) {
|
||||
cause = "invalid-hash";
|
||||
status = INTEGRITY_FAIL;
|
||||
break;
|
||||
}
|
||||
status = INTEGRITY_PASS;
|
||||
break;
|
||||
case EVM_IMA_XATTR_DIGSIG:
|
||||
set_bit(IMA_DIGSIG, &iint->atomic_flags);
|
||||
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
|
||||
(const char *)xattr_value,
|
||||
xattr_len,
|
||||
iint->ima_hash->digest,
|
||||
iint->ima_hash->length);
|
||||
if (rc == -EOPNOTSUPP) {
|
||||
status = INTEGRITY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
|
||||
func == KEXEC_KERNEL_CHECK)
|
||||
rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
|
||||
(const char *)xattr_value,
|
||||
xattr_len,
|
||||
iint->ima_hash->digest,
|
||||
iint->ima_hash->length);
|
||||
if (rc) {
|
||||
cause = "invalid-signature";
|
||||
status = INTEGRITY_FAIL;
|
||||
} else {
|
||||
status = INTEGRITY_PASS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status = INTEGRITY_UNKNOWN;
|
||||
cause = "unknown-ima-data";
|
||||
break;
|
||||
}
|
||||
if (xattr_value)
|
||||
rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
|
||||
&cause);
|
||||
|
||||
/*
|
||||
* If we have a modsig and either no imasig or the imasig's key isn't
|
||||
* known, then try verifying the modsig.
|
||||
*/
|
||||
if (try_modsig &&
|
||||
(!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG ||
|
||||
rc == -ENOKEY))
|
||||
rc = modsig_verify(func, modsig, &status, &cause);
|
||||
|
||||
out:
|
||||
/*
|
||||
|
|
@ -332,7 +396,7 @@ out:
|
|||
op, cause, rc, 0);
|
||||
} else if (status != INTEGRITY_PASS) {
|
||||
/* Fix mode, but don't replace file signatures. */
|
||||
if ((ima_appraise & IMA_APPRAISE_FIX) &&
|
||||
if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
|
||||
(!xattr_value ||
|
||||
xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
|
||||
if (!ima_fix_xattr(dentry, iint))
|
||||
|
|
@ -371,7 +435,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
|
|||
!(iint->flags & IMA_HASH))
|
||||
return;
|
||||
|
||||
rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
|
||||
rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo, NULL);
|
||||
if (rc < 0)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -268,8 +268,16 @@ static int ima_calc_file_hash_atfm(struct file *file,
|
|||
rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
|
||||
rc = integrity_kernel_read(file, offset, rbuf[active],
|
||||
rbuf_len);
|
||||
if (rc != rbuf_len)
|
||||
if (rc != rbuf_len) {
|
||||
if (rc >= 0)
|
||||
rc = -EINVAL;
|
||||
/*
|
||||
* Forward current rc, do not overwrite with return value
|
||||
* from ahash_wait()
|
||||
*/
|
||||
ahash_wait(ahash_rc, &wait);
|
||||
goto out3;
|
||||
}
|
||||
|
||||
if (rbuf[1] && offset) {
|
||||
/* Using two buffers, and it is not the first
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
|||
int rc = 0, action, must_appraise = 0;
|
||||
int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
|
||||
struct evm_ima_xattr_data *xattr_value = NULL;
|
||||
struct modsig *modsig = NULL;
|
||||
int xattr_len = 0;
|
||||
bool violation_check;
|
||||
enum hash_algo hash_algo;
|
||||
|
|
@ -302,13 +303,27 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
|||
}
|
||||
|
||||
if ((action & IMA_APPRAISE_SUBMASK) ||
|
||||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
|
||||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) {
|
||||
/* read 'security.ima' */
|
||||
xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
|
||||
|
||||
/*
|
||||
* Read the appended modsig if allowed by the policy, and allow
|
||||
* an additional measurement list entry, if needed, based on the
|
||||
* template format and whether the file was already measured.
|
||||
*/
|
||||
if (iint->flags & IMA_MODSIG_ALLOWED) {
|
||||
rc = ima_read_modsig(func, buf, size, &modsig);
|
||||
|
||||
if (!rc && ima_template_has_modsig(template_desc) &&
|
||||
iint->flags & IMA_MEASURED)
|
||||
action |= IMA_MEASURE;
|
||||
}
|
||||
}
|
||||
|
||||
hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
|
||||
|
||||
rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
|
||||
rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig);
|
||||
if (rc != 0 && rc != -EBADF && rc != -EINVAL)
|
||||
goto out_locked;
|
||||
|
||||
|
|
@ -317,12 +332,12 @@ static int process_measurement(struct file *file, const struct cred *cred,
|
|||
|
||||
if (action & IMA_MEASURE)
|
||||
ima_store_measurement(iint, file, pathname,
|
||||
xattr_value, xattr_len, pcr,
|
||||
xattr_value, xattr_len, modsig, pcr,
|
||||
template_desc);
|
||||
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
|
||||
inode_lock(inode);
|
||||
rc = ima_appraise_measurement(func, iint, file, pathname,
|
||||
xattr_value, xattr_len);
|
||||
xattr_value, xattr_len, modsig);
|
||||
inode_unlock(inode);
|
||||
if (!rc)
|
||||
rc = mmap_violation_check(func, file, &pathbuf,
|
||||
|
|
@ -339,6 +354,7 @@ out_locked:
|
|||
rc = -EACCES;
|
||||
mutex_unlock(&iint->mutex);
|
||||
kfree(xattr_value);
|
||||
ima_free_modsig(modsig);
|
||||
out:
|
||||
if (pathbuf)
|
||||
__putname(pathbuf);
|
||||
|
|
@ -502,7 +518,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const int read_idmap[READING_MAX_ID] = {
|
||||
const int read_idmap[READING_MAX_ID] = {
|
||||
[READING_FIRMWARE] = FIRMWARE_CHECK,
|
||||
[READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK,
|
||||
[READING_MODULE] = MODULE_CHECK,
|
||||
|
|
@ -574,7 +590,7 @@ int ima_load_data(enum kernel_load_data_id id)
|
|||
|
||||
switch (id) {
|
||||
case LOADING_KEXEC_IMAGE:
|
||||
if (IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
|
||||
if (IS_ENABLED(CONFIG_KEXEC_SIG)
|
||||
&& arch_ima_get_secureboot()) {
|
||||
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
|
||||
return -EACCES;
|
||||
|
|
|
|||
168
security/integrity/ima/ima_modsig.c
Normal file
168
security/integrity/ima/ima_modsig.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* IMA support for appraising module-style appended signatures.
|
||||
*
|
||||
* Copyright (C) 2019 IBM Corporation
|
||||
*
|
||||
* Author:
|
||||
* Thiago Jung Bauermann <bauerman@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module_signature.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include <crypto/pkcs7.h>
|
||||
|
||||
#include "ima.h"
|
||||
|
||||
struct modsig {
|
||||
struct pkcs7_message *pkcs7_msg;
|
||||
|
||||
enum hash_algo hash_algo;
|
||||
|
||||
/* This digest will go in the 'd-modsig' field of the IMA template. */
|
||||
const u8 *digest;
|
||||
u32 digest_size;
|
||||
|
||||
/*
|
||||
* This is what will go to the measurement list if the template requires
|
||||
* storing the signature.
|
||||
*/
|
||||
int raw_pkcs7_len;
|
||||
u8 raw_pkcs7[];
|
||||
};
|
||||
|
||||
/**
|
||||
* ima_hook_supports_modsig - can the policy allow modsig for this hook?
|
||||
*
|
||||
* modsig is only supported by hooks using ima_post_read_file(), because only
|
||||
* they preload the contents of the file in a buffer. FILE_CHECK does that in
|
||||
* some cases, but not when reached from vfs_open(). POLICY_CHECK can support
|
||||
* it, but it's not useful in practice because it's a text file so deny.
|
||||
*/
|
||||
bool ima_hook_supports_modsig(enum ima_hooks func)
|
||||
{
|
||||
switch (func) {
|
||||
case KEXEC_KERNEL_CHECK:
|
||||
case KEXEC_INITRAMFS_CHECK:
|
||||
case MODULE_CHECK:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_read_modsig - Read modsig from buf.
|
||||
*
|
||||
* Return: 0 on success, error code otherwise.
|
||||
*/
|
||||
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
struct modsig **modsig)
|
||||
{
|
||||
const size_t marker_len = strlen(MODULE_SIG_STRING);
|
||||
const struct module_signature *sig;
|
||||
struct modsig *hdr;
|
||||
size_t sig_len;
|
||||
const void *p;
|
||||
int rc;
|
||||
|
||||
if (buf_len <= marker_len + sizeof(*sig))
|
||||
return -ENOENT;
|
||||
|
||||
p = buf + buf_len - marker_len;
|
||||
if (memcmp(p, MODULE_SIG_STRING, marker_len))
|
||||
return -ENOENT;
|
||||
|
||||
buf_len -= marker_len;
|
||||
sig = (const struct module_signature *)(p - sizeof(*sig));
|
||||
|
||||
rc = mod_check_sig(sig, buf_len, func_tokens[func]);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
sig_len = be32_to_cpu(sig->sig_len);
|
||||
buf_len -= sig_len + sizeof(*sig);
|
||||
|
||||
/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
|
||||
hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
|
||||
if (!hdr)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
|
||||
if (IS_ERR(hdr->pkcs7_msg)) {
|
||||
rc = PTR_ERR(hdr->pkcs7_msg);
|
||||
kfree(hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
|
||||
hdr->raw_pkcs7_len = sig_len;
|
||||
|
||||
/* We don't know the hash algorithm yet. */
|
||||
hdr->hash_algo = HASH_ALGO__LAST;
|
||||
|
||||
*modsig = hdr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_collect_modsig - Calculate the file hash without the appended signature.
|
||||
*
|
||||
* Since the modsig is part of the file contents, the hash used in its signature
|
||||
* isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
|
||||
* calculates a separate one for signature verification.
|
||||
*/
|
||||
void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Provide the file contents (minus the appended sig) so that the PKCS7
|
||||
* code can calculate the file hash.
|
||||
*/
|
||||
size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
|
||||
sizeof(struct module_signature);
|
||||
rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
/* Ask the PKCS7 code to calculate the file hash. */
|
||||
rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
|
||||
&modsig->digest_size, &modsig->hash_algo);
|
||||
}
|
||||
|
||||
int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
|
||||
{
|
||||
return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring,
|
||||
VERIFYING_MODULE_SIGNATURE, NULL, NULL);
|
||||
}
|
||||
|
||||
int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
|
||||
const u8 **digest, u32 *digest_size)
|
||||
{
|
||||
*algo = modsig->hash_algo;
|
||||
*digest = modsig->digest;
|
||||
*digest_size = modsig->digest_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
|
||||
u32 *data_len)
|
||||
{
|
||||
*data = &modsig->raw_pkcs7;
|
||||
*data_len = modsig->raw_pkcs7_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ima_free_modsig(struct modsig *modsig)
|
||||
{
|
||||
if (!modsig)
|
||||
return;
|
||||
|
||||
pkcs7_free_message(modsig->pkcs7_msg);
|
||||
kfree(modsig);
|
||||
}
|
||||
|
|
@ -6,6 +6,9 @@
|
|||
* ima_policy.c
|
||||
* - initialize default measure policy rules
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
|
|
@ -491,6 +494,9 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
|
|||
struct ima_rule_entry *entry;
|
||||
int action = 0, actmask = flags | (flags << 1);
|
||||
|
||||
if (template_desc)
|
||||
*template_desc = ima_template_desc_current();
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(entry, ima_rules, list) {
|
||||
|
||||
|
|
@ -510,6 +516,7 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
|
|||
action |= IMA_FAIL_UNVERIFIABLE_SIGS;
|
||||
}
|
||||
|
||||
|
||||
if (entry->action & IMA_DO_MASK)
|
||||
actmask &= ~(entry->action | entry->action << 1);
|
||||
else
|
||||
|
|
@ -520,8 +527,6 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid,
|
|||
|
||||
if (template_desc && entry->template)
|
||||
*template_desc = entry->template;
|
||||
else if (template_desc)
|
||||
*template_desc = ima_template_desc_current();
|
||||
|
||||
if (!actmask)
|
||||
break;
|
||||
|
|
@ -843,6 +848,38 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
|
|||
ima_log_string_op(ab, key, value, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validating the appended signature included in the measurement list requires
|
||||
* the file hash calculated without the appended signature (i.e., the 'd-modsig'
|
||||
* field). Therefore, notify the user if they have the 'modsig' field but not
|
||||
* the 'd-modsig' field in the template.
|
||||
*/
|
||||
static void check_template_modsig(const struct ima_template_desc *template)
|
||||
{
|
||||
#define MSG "template with 'modsig' field also needs 'd-modsig' field\n"
|
||||
bool has_modsig, has_dmodsig;
|
||||
static bool checked;
|
||||
int i;
|
||||
|
||||
/* We only need to notify the user once. */
|
||||
if (checked)
|
||||
return;
|
||||
|
||||
has_modsig = has_dmodsig = false;
|
||||
for (i = 0; i < template->num_fields; i++) {
|
||||
if (!strcmp(template->fields[i]->field_id, "modsig"))
|
||||
has_modsig = true;
|
||||
else if (!strcmp(template->fields[i]->field_id, "d-modsig"))
|
||||
has_dmodsig = true;
|
||||
}
|
||||
|
||||
if (has_modsig && !has_dmodsig)
|
||||
pr_notice(MSG);
|
||||
|
||||
checked = true;
|
||||
#undef MSG
|
||||
}
|
||||
|
||||
static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
|
|
@ -1128,6 +1165,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
ima_log_string(ab, "appraise_type", args[0].from);
|
||||
if ((strcmp(args[0].from, "imasig")) == 0)
|
||||
entry->flags |= IMA_DIGSIG_REQUIRED;
|
||||
else if (ima_hook_supports_modsig(entry->func) &&
|
||||
strcmp(args[0].from, "imasig|modsig") == 0)
|
||||
entry->flags |= IMA_DIGSIG_REQUIRED |
|
||||
IMA_MODSIG_ALLOWED;
|
||||
else
|
||||
result = -EINVAL;
|
||||
break;
|
||||
|
|
@ -1181,6 +1222,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
else if (entry->action == APPRAISE)
|
||||
temp_ima_appraise |= ima_appraise_flag(entry->func);
|
||||
|
||||
if (!result && entry->flags & IMA_MODSIG_ALLOWED) {
|
||||
template_desc = entry->template ? entry->template :
|
||||
ima_template_desc_current();
|
||||
check_template_modsig(template_desc);
|
||||
}
|
||||
|
||||
audit_log_format(ab, "res=%d", !result);
|
||||
audit_log_end(ab);
|
||||
return result;
|
||||
|
|
@ -1252,6 +1299,12 @@ void ima_delete_rules(void)
|
|||
}
|
||||
}
|
||||
|
||||
#define __ima_hook_stringify(str) (#str),
|
||||
|
||||
const char *const func_tokens[] = {
|
||||
__ima_hooks(__ima_hook_stringify)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IMA_READ_POLICY
|
||||
enum {
|
||||
mask_exec = 0, mask_write, mask_read, mask_append
|
||||
|
|
@ -1264,12 +1317,6 @@ static const char *const mask_tokens[] = {
|
|||
"^MAY_APPEND"
|
||||
};
|
||||
|
||||
#define __ima_hook_stringify(str) (#str),
|
||||
|
||||
static const char *const func_tokens[] = {
|
||||
__ima_hooks(__ima_hook_stringify)
|
||||
};
|
||||
|
||||
void *ima_policy_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
loff_t l = *pos;
|
||||
|
|
@ -1447,8 +1494,12 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|||
}
|
||||
if (entry->template)
|
||||
seq_printf(m, "template=%s ", entry->template->name);
|
||||
if (entry->flags & IMA_DIGSIG_REQUIRED)
|
||||
seq_puts(m, "appraise_type=imasig ");
|
||||
if (entry->flags & IMA_DIGSIG_REQUIRED) {
|
||||
if (entry->flags & IMA_MODSIG_ALLOWED)
|
||||
seq_puts(m, "appraise_type=imasig|modsig ");
|
||||
else
|
||||
seq_puts(m, "appraise_type=imasig ");
|
||||
}
|
||||
if (entry->flags & IMA_PERMIT_DIRECTIO)
|
||||
seq_puts(m, "permit_directio ");
|
||||
rcu_read_unlock();
|
||||
|
|
@ -1456,3 +1507,53 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_IMA_READ_POLICY */
|
||||
|
||||
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING)
|
||||
/*
|
||||
* ima_appraise_signature: whether IMA will appraise a given function using
|
||||
* an IMA digital signature. This is restricted to cases where the kernel
|
||||
* has a set of built-in trusted keys in order to avoid an attacker simply
|
||||
* loading additional keys.
|
||||
*/
|
||||
bool ima_appraise_signature(enum kernel_read_file_id id)
|
||||
{
|
||||
struct ima_rule_entry *entry;
|
||||
bool found = false;
|
||||
enum ima_hooks func;
|
||||
|
||||
if (id >= READING_MAX_ID)
|
||||
return false;
|
||||
|
||||
func = read_idmap[id] ?: FILE_CHECK;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(entry, ima_rules, list) {
|
||||
if (entry->action != APPRAISE)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* A generic entry will match, but otherwise require that it
|
||||
* match the func we're looking for
|
||||
*/
|
||||
if (entry->func && entry->func != func)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We require this to be a digital signature, not a raw IMA
|
||||
* hash.
|
||||
*/
|
||||
if (entry->flags & IMA_DIGSIG_REQUIRED)
|
||||
found = true;
|
||||
|
||||
/*
|
||||
* We've found a rule that matches, so break now even if it
|
||||
* didn't require a digital signature - a later rule that does
|
||||
* won't override it, so would be a false positive.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return found;
|
||||
}
|
||||
#endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ static struct ima_template_desc builtin_templates[] = {
|
|||
{.name = "ima-ng", .fmt = "d-ng|n-ng"},
|
||||
{.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
|
||||
{.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
|
||||
{.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
|
||||
{.name = "", .fmt = ""}, /* placeholder for a custom format */
|
||||
};
|
||||
|
||||
|
|
@ -42,6 +43,10 @@ static const struct ima_template_field supported_fields[] = {
|
|||
.field_show = ima_show_template_sig},
|
||||
{.field_id = "buf", .field_init = ima_eventbuf_init,
|
||||
.field_show = ima_show_template_buf},
|
||||
{.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,
|
||||
.field_show = ima_show_template_digest_ng},
|
||||
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
|
||||
.field_show = ima_show_template_sig},
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -49,10 +54,29 @@ static const struct ima_template_field supported_fields[] = {
|
|||
* need to be accounted for since they shouldn't be defined in the same template
|
||||
* description as 'd-ng' and 'n-ng' respectively.
|
||||
*/
|
||||
#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf")
|
||||
#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
|
||||
|
||||
static struct ima_template_desc *ima_template;
|
||||
|
||||
/**
|
||||
* ima_template_has_modsig - Check whether template has modsig-related fields.
|
||||
* @ima_template: IMA template to check.
|
||||
*
|
||||
* Tells whether the given template has fields referencing a file's appended
|
||||
* signature.
|
||||
*/
|
||||
bool ima_template_has_modsig(const struct ima_template_desc *ima_template)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ima_template->num_fields; i++)
|
||||
if (!strcmp(ima_template->fields[i]->field_id, "modsig") ||
|
||||
!strcmp(ima_template->fields[i]->field_id, "d-modsig"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __init ima_template_setup(char *str)
|
||||
{
|
||||
struct ima_template_desc *template_desc;
|
||||
|
|
@ -282,9 +306,8 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
|
|||
int ret = 0;
|
||||
int i;
|
||||
|
||||
*entry = kzalloc(sizeof(**entry) +
|
||||
template_desc->num_fields * sizeof(struct ima_field_data),
|
||||
GFP_NOFS);
|
||||
*entry = kzalloc(struct_size(*entry, template_data,
|
||||
template_desc->num_fields), GFP_NOFS);
|
||||
if (!*entry)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,8 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
||||
static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
|
||||
u8 hash_algo,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
/*
|
||||
|
|
@ -328,6 +329,41 @@ out:
|
|||
hash_algo, field_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function writes the digest of the file which is expected to match the
|
||||
* digest contained in the file's appended signature.
|
||||
*/
|
||||
int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
enum hash_algo hash_algo;
|
||||
const u8 *cur_digest;
|
||||
u32 cur_digestsize;
|
||||
|
||||
if (!event_data->modsig)
|
||||
return 0;
|
||||
|
||||
if (event_data->violation) {
|
||||
/* Recording a violation. */
|
||||
hash_algo = HASH_ALGO_SHA1;
|
||||
cur_digest = NULL;
|
||||
cur_digestsize = 0;
|
||||
} else {
|
||||
int rc;
|
||||
|
||||
rc = ima_get_modsig_digest(event_data->modsig, &hash_algo,
|
||||
&cur_digest, &cur_digestsize);
|
||||
if (rc)
|
||||
return rc;
|
||||
else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0)
|
||||
/* There was some error collecting the digest. */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||
hash_algo, field_data);
|
||||
}
|
||||
|
||||
static int ima_eventname_init_common(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data,
|
||||
bool size_limit)
|
||||
|
|
@ -406,3 +442,29 @@ int ima_eventbuf_init(struct ima_event_data *event_data,
|
|||
event_data->buf_len, DATA_FMT_HEX,
|
||||
field_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* ima_eventmodsig_init - include the appended file signature as part of the
|
||||
* template data
|
||||
*/
|
||||
int ima_eventmodsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
const void *data;
|
||||
u32 data_len;
|
||||
int rc;
|
||||
|
||||
if (!event_data->modsig)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* modsig is a runtime structure containing pointers. Get its raw data
|
||||
* instead.
|
||||
*/
|
||||
rc = ima_get_raw_modsig(event_data->modsig, &data, &data_len);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
|
||||
field_data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,14 @@ int ima_eventname_init(struct ima_event_data *event_data,
|
|||
struct ima_field_data *field_data);
|
||||
int ima_eventdigest_ng_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventname_ng_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventbuf_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
int ima_eventmodsig_init(struct ima_event_data *event_data,
|
||||
struct ima_field_data *field_data);
|
||||
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#define IMA_NEW_FILE 0x04000000
|
||||
#define EVM_IMMUTABLE_DIGSIG 0x08000000
|
||||
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
|
||||
#define IMA_MODSIG_ALLOWED 0x20000000
|
||||
|
||||
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
|
||||
IMA_HASH | IMA_APPRAISE_SUBMASK)
|
||||
|
|
@ -147,10 +148,13 @@ int integrity_kernel_read(struct file *file, loff_t offset,
|
|||
|
||||
extern struct dentry *integrity_dir;
|
||||
|
||||
struct modsig;
|
||||
|
||||
#ifdef CONFIG_INTEGRITY_SIGNATURE
|
||||
|
||||
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
|
||||
const char *digest, int digestlen);
|
||||
int integrity_modsig_verify(unsigned int id, const struct modsig *modsig);
|
||||
|
||||
int __init integrity_init_keyring(const unsigned int id);
|
||||
int __init integrity_load_x509(const unsigned int id, const char *path);
|
||||
|
|
@ -165,6 +169,12 @@ static inline int integrity_digsig_verify(const unsigned int id,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int integrity_modsig_verify(unsigned int id,
|
||||
const struct modsig *modsig)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int integrity_init_keyring(const unsigned int id)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -190,6 +200,16 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMA_APPRAISE_MODSIG
|
||||
int ima_modsig_verify(struct key *keyring, const struct modsig *modsig);
|
||||
#else
|
||||
static inline int ima_modsig_verify(struct key *keyring,
|
||||
const struct modsig *modsig)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IMA_LOAD_X509
|
||||
void __init ima_load_x509(void);
|
||||
#else
|
||||
|
|
|
|||
47
security/lockdown/Kconfig
Normal file
47
security/lockdown/Kconfig
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
config SECURITY_LOCKDOWN_LSM
|
||||
bool "Basic module for enforcing kernel lockdown"
|
||||
depends on SECURITY
|
||||
select MODULE_SIG if MODULES
|
||||
help
|
||||
Build support for an LSM that enforces a coarse kernel lockdown
|
||||
behaviour.
|
||||
|
||||
config SECURITY_LOCKDOWN_LSM_EARLY
|
||||
bool "Enable lockdown LSM early in init"
|
||||
depends on SECURITY_LOCKDOWN_LSM
|
||||
help
|
||||
Enable the lockdown LSM early in boot. This is necessary in order
|
||||
to ensure that lockdown enforcement can be carried out on kernel
|
||||
boot parameters that are otherwise parsed before the security
|
||||
subsystem is fully initialised. If enabled, lockdown will
|
||||
unconditionally be called before any other LSMs.
|
||||
|
||||
choice
|
||||
prompt "Kernel default lockdown mode"
|
||||
default LOCK_DOWN_KERNEL_FORCE_NONE
|
||||
depends on SECURITY_LOCKDOWN_LSM
|
||||
help
|
||||
The kernel can be configured to default to differing levels of
|
||||
lockdown.
|
||||
|
||||
config LOCK_DOWN_KERNEL_FORCE_NONE
|
||||
bool "None"
|
||||
help
|
||||
No lockdown functionality is enabled by default. Lockdown may be
|
||||
enabled via the kernel commandline or /sys/kernel/security/lockdown.
|
||||
|
||||
config LOCK_DOWN_KERNEL_FORCE_INTEGRITY
|
||||
bool "Integrity"
|
||||
help
|
||||
The kernel runs in integrity mode by default. Features that allow
|
||||
the kernel to be modified at runtime are disabled.
|
||||
|
||||
config LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY
|
||||
bool "Confidentiality"
|
||||
help
|
||||
The kernel runs in confidentiality mode by default. Features that
|
||||
allow the kernel to be modified at runtime or that permit userland
|
||||
code to read confidential material held inside the kernel are
|
||||
disabled.
|
||||
|
||||
endchoice
|
||||
1
security/lockdown/Makefile
Normal file
1
security/lockdown/Makefile
Normal file
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown.o
|
||||
191
security/lockdown/lockdown.c
Normal file
191
security/lockdown/lockdown.c
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Lock down the kernel
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/security.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/lsm_hooks.h>
|
||||
|
||||
static enum lockdown_reason kernel_locked_down;
|
||||
|
||||
static const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
|
||||
[LOCKDOWN_NONE] = "none",
|
||||
[LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading",
|
||||
[LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port",
|
||||
[LOCKDOWN_KEXEC] = "kexec of unsigned images",
|
||||
[LOCKDOWN_HIBERNATION] = "hibernation",
|
||||
[LOCKDOWN_PCI_ACCESS] = "direct PCI access",
|
||||
[LOCKDOWN_IOPORT] = "raw io port access",
|
||||
[LOCKDOWN_MSR] = "raw MSR access",
|
||||
[LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables",
|
||||
[LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage",
|
||||
[LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO",
|
||||
[LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters",
|
||||
[LOCKDOWN_MMIOTRACE] = "unsafe mmio",
|
||||
[LOCKDOWN_DEBUGFS] = "debugfs access",
|
||||
[LOCKDOWN_INTEGRITY_MAX] = "integrity",
|
||||
[LOCKDOWN_KCORE] = "/proc/kcore access",
|
||||
[LOCKDOWN_KPROBES] = "use of kprobes",
|
||||
[LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM",
|
||||
[LOCKDOWN_PERF] = "unsafe use of perf",
|
||||
[LOCKDOWN_TRACEFS] = "use of tracefs",
|
||||
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
|
||||
};
|
||||
|
||||
static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
|
||||
LOCKDOWN_INTEGRITY_MAX,
|
||||
LOCKDOWN_CONFIDENTIALITY_MAX};
|
||||
|
||||
/*
|
||||
* Put the kernel into lock-down mode.
|
||||
*/
|
||||
static int lock_kernel_down(const char *where, enum lockdown_reason level)
|
||||
{
|
||||
if (kernel_locked_down >= level)
|
||||
return -EPERM;
|
||||
|
||||
kernel_locked_down = level;
|
||||
pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
|
||||
where);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init lockdown_param(char *level)
|
||||
{
|
||||
if (!level)
|
||||
return -EINVAL;
|
||||
|
||||
if (strcmp(level, "integrity") == 0)
|
||||
lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX);
|
||||
else if (strcmp(level, "confidentiality") == 0)
|
||||
lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("lockdown", lockdown_param);
|
||||
|
||||
/**
|
||||
* lockdown_is_locked_down - Find out if the kernel is locked down
|
||||
* @what: Tag to use in notice generated if lockdown is in effect
|
||||
*/
|
||||
static int lockdown_is_locked_down(enum lockdown_reason what)
|
||||
{
|
||||
if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX,
|
||||
"Invalid lockdown reason"))
|
||||
return -EPERM;
|
||||
|
||||
if (kernel_locked_down >= what) {
|
||||
if (lockdown_reasons[what])
|
||||
pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
|
||||
current->comm, lockdown_reasons[what]);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(locked_down, lockdown_is_locked_down),
|
||||
};
|
||||
|
||||
static int __init lockdown_lsm_init(void)
|
||||
{
|
||||
#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY)
|
||||
lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX);
|
||||
#elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY)
|
||||
lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX);
|
||||
#endif
|
||||
security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks),
|
||||
"lockdown");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
char temp[80];
|
||||
int i, offset = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
|
||||
enum lockdown_reason level = lockdown_levels[i];
|
||||
|
||||
if (lockdown_reasons[level]) {
|
||||
const char *label = lockdown_reasons[level];
|
||||
|
||||
if (kernel_locked_down == level)
|
||||
offset += sprintf(temp+offset, "[%s] ", label);
|
||||
else
|
||||
offset += sprintf(temp+offset, "%s ", label);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert the last space to a newline if needed. */
|
||||
if (offset > 0)
|
||||
temp[offset-1] = '\n';
|
||||
|
||||
return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
|
||||
}
|
||||
|
||||
static ssize_t lockdown_write(struct file *file, const char __user *buf,
|
||||
size_t n, loff_t *ppos)
|
||||
{
|
||||
char *state;
|
||||
int i, len, err = -EINVAL;
|
||||
|
||||
state = memdup_user_nul(buf, n);
|
||||
if (IS_ERR(state))
|
||||
return PTR_ERR(state);
|
||||
|
||||
len = strlen(state);
|
||||
if (len && state[len-1] == '\n') {
|
||||
state[len-1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) {
|
||||
enum lockdown_reason level = lockdown_levels[i];
|
||||
const char *label = lockdown_reasons[level];
|
||||
|
||||
if (label && !strcmp(state, label))
|
||||
err = lock_kernel_down("securityfs", level);
|
||||
}
|
||||
|
||||
kfree(state);
|
||||
return err ? err : n;
|
||||
}
|
||||
|
||||
static const struct file_operations lockdown_ops = {
|
||||
.read = lockdown_read,
|
||||
.write = lockdown_write,
|
||||
};
|
||||
|
||||
static int __init lockdown_secfs_init(void)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
dentry = securityfs_create_file("lockdown", 0600, NULL, NULL,
|
||||
&lockdown_ops);
|
||||
return PTR_ERR_OR_ZERO(dentry);
|
||||
}
|
||||
|
||||
core_initcall(lockdown_secfs_init);
|
||||
|
||||
#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY
|
||||
DEFINE_EARLY_LSM(lockdown) = {
|
||||
#else
|
||||
DEFINE_LSM(lockdown) = {
|
||||
#endif
|
||||
.name = "lockdown",
|
||||
.init = lockdown_lsm_init,
|
||||
};
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
/* How many LSMs were built into the kernel? */
|
||||
#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
|
||||
#define EARLY_LSM_COUNT (__end_early_lsm_info - __start_early_lsm_info)
|
||||
|
||||
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
|
||||
static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
|
||||
|
|
@ -277,6 +278,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin)
|
|||
static void __init lsm_early_cred(struct cred *cred);
|
||||
static void __init lsm_early_task(struct task_struct *task);
|
||||
|
||||
static int lsm_append(const char *new, char **result);
|
||||
|
||||
static void __init ordered_lsm_init(void)
|
||||
{
|
||||
struct lsm_info **lsm;
|
||||
|
|
@ -323,6 +326,26 @@ static void __init ordered_lsm_init(void)
|
|||
kfree(ordered_lsms);
|
||||
}
|
||||
|
||||
int __init early_security_init(void)
|
||||
{
|
||||
int i;
|
||||
struct hlist_head *list = (struct hlist_head *) &security_hook_heads;
|
||||
struct lsm_info *lsm;
|
||||
|
||||
for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head);
|
||||
i++)
|
||||
INIT_HLIST_HEAD(&list[i]);
|
||||
|
||||
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
|
||||
if (!lsm->enabled)
|
||||
lsm->enabled = &lsm_enabled_true;
|
||||
prepare_lsm(lsm);
|
||||
initialize_lsm(lsm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* security_init - initializes the security framework
|
||||
*
|
||||
|
|
@ -330,14 +353,18 @@ static void __init ordered_lsm_init(void)
|
|||
*/
|
||||
int __init security_init(void)
|
||||
{
|
||||
int i;
|
||||
struct hlist_head *list = (struct hlist_head *) &security_hook_heads;
|
||||
struct lsm_info *lsm;
|
||||
|
||||
pr_info("Security Framework initializing\n");
|
||||
|
||||
for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head);
|
||||
i++)
|
||||
INIT_HLIST_HEAD(&list[i]);
|
||||
/*
|
||||
* Append the names of the early LSM modules now that kmalloc() is
|
||||
* available
|
||||
*/
|
||||
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
|
||||
if (lsm->enabled)
|
||||
lsm_append(lsm->name, &lsm_names);
|
||||
}
|
||||
|
||||
/* Load LSMs in specified order. */
|
||||
ordered_lsm_init();
|
||||
|
|
@ -384,7 +411,7 @@ static bool match_last_lsm(const char *list, const char *lsm)
|
|||
return !strcmp(last, lsm);
|
||||
}
|
||||
|
||||
static int lsm_append(char *new, char **result)
|
||||
static int lsm_append(const char *new, char **result)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
|
|
@ -422,8 +449,15 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
|
|||
hooks[i].lsm = lsm;
|
||||
hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
|
||||
}
|
||||
if (lsm_append(lsm, &lsm_names) < 0)
|
||||
panic("%s - Cannot get early memory.\n", __func__);
|
||||
|
||||
/*
|
||||
* Don't try to append during early_security_init(), we'll come back
|
||||
* and fix this up afterwards.
|
||||
*/
|
||||
if (slab_is_available()) {
|
||||
if (lsm_append(lsm, &lsm_names) < 0)
|
||||
panic("%s - Cannot get early memory.\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
int call_blocking_lsm_notifier(enum lsm_event event, void *data)
|
||||
|
|
@ -2365,3 +2399,9 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux)
|
|||
call_void_hook(bpf_prog_free_security, aux);
|
||||
}
|
||||
#endif /* CONFIG_BPF_SYSCALL */
|
||||
|
||||
int security_locked_down(enum lockdown_reason what)
|
||||
{
|
||||
return call_int_hook(locked_down, 0, what);
|
||||
}
|
||||
EXPORT_SYMBOL(security_locked_down);
|
||||
|
|
|
|||
Loading…
Reference in a new issue