* [PATCH RFC 11/12] integrity: move keys from the mok keyring into the secondary keyring
From: Eric Snowberg @ 2021-07-07 2:44 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Keys added to the mok keyring are only stored there temporarily. After
passing the permissions check, move the key from the mok keyring into
the secondary trusted keyring.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/integrity/digsig.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 07547f1a4806..e301cee037bf 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -175,8 +175,13 @@ static int __init integrity_add_key(const unsigned int id, const void *data,
rc = PTR_ERR(key);
pr_err("Problem loading X.509 certificate %d\n", rc);
} else {
- pr_notice("Loaded X.509 cert '%s'\n",
- key_ref_to_ptr(key)->description);
+ if (id == INTEGRITY_KEYRING_MOK)
+ rc = move_to_trusted_secondary_keyring(key_ref_to_ptr(key),
+ keyring[id]);
+ else
+ pr_notice("Loaded X.509 cert '%s'\n",
+ key_ref_to_ptr(key)->description);
+
key_ref_put(key);
}
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 08/12] integrity: restrict INTEGRITY_KEYRING_MOK to restrict_link_by_secondary_trusted_or_ca
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Set the restriction check for INTEGRITY_KEYRING_MOK keys to
restrict_link_by_secondary_trusted_or_ca. This will only allow keys
into the mok keyring that are either a CA or trusted by a key contained
within the secondary trusted keyring.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/integrity/digsig.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 56800a5f1e10..07547f1a4806 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -140,6 +140,11 @@ int __init integrity_init_keyring(const unsigned int id)
return -ENOMEM;
restriction->check = restrict_link_to_ima;
+ if (id == INTEGRITY_KEYRING_MOK)
+ restriction->check = restrict_link_by_secondary_trusted_or_ca;
+ else
+ restriction->check = restrict_link_to_ima;
+
perm |= KEY_USR_WRITE;
out:
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 12/12] integrity: Suppress error message for keys added to the mok keyring
From: Eric Snowberg @ 2021-07-07 2:44 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Suppress the error message for keys added to the mok keyring. If an
error occurs, the key will be added to the platform keyring instead.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/integrity/digsig.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index e301cee037bf..50bdf839fa44 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -173,7 +173,8 @@ static int __init integrity_add_key(const unsigned int id, const void *data,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
- pr_err("Problem loading X.509 certificate %d\n", rc);
+ if (id != INTEGRITY_KEYRING_MOK)
+ pr_err("Problem loading X.509 certificate %d\n", rc);
} else {
if (id == INTEGRITY_KEYRING_MOK)
rc = move_to_trusted_secondary_keyring(key_ref_to_ptr(key),
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 01/12] KEYS: Add KEY_ALLOC_BYPASS_RESTRICTION option to key_move
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Callers of key_create_or_update can pass KEY_ALLOC_BYPASS_RESTRICTION to
suppress the restrictions check. Add the same support to key_move to
bypass restrictions on the destination keyring.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/keys/keyring.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 5e6a90760753..56ea2b78d2e5 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1585,7 +1585,7 @@ EXPORT_SYMBOL(key_unlink);
*
* It is assumed that the caller has checked that it is permitted for a link to
* be made (the keyring should have Write permission and the key Link
- * permission).
+ * permission). It can be overridden by passing KEY_ALLOC_BYPASS_RESTRICTION.
*/
int key_move(struct key *key,
struct key *from_keyring,
@@ -1618,9 +1618,11 @@ int key_move(struct key *key,
if (to_edit->dead_leaf && (flags & KEYCTL_MOVE_EXCL))
goto error;
- ret = __key_link_check_restriction(to_keyring, key);
- if (ret < 0)
- goto error;
+ if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION)) {
+ ret = __key_link_check_restriction(to_keyring, key);
+ if (ret < 0)
+ goto error;
+ }
ret = __key_link_check_live_key(to_keyring, key);
if (ret < 0)
goto error;
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 00/12] Enroll kernel keys thru MOK
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
This is a follow up to the "Add additional MOK vars" [1] series I
previously sent. This series incorporates the feedback given
both publicly on the mailing list and privately from Mimi. This
series just focuses on getting end-user keys into the kernel trust
boundary.
Currently, pre-boot keys are not trusted within the Linux boundary [2].
Pre-boot keys include UEFI Secure Boot DB keys and MOKList keys. These
keys are loaded into the platform keyring and can only be used for kexec.
If an end-user wants to use their own key within the Linux trust
boundary, they must either compile it into the kernel themselves or use
the insert-sys-cert script. Both options present a problem. Many
end-users do not want to compile their own kernels. With the
insert-sys-cert option, there are missing upstream changes [3]. Also,
with the insert-sys-cert option, the end-user must re-sign their kernel
again with their own key, and then insert that key into the MOK db.
Another problem with insert-sys-cert is that only a single key can be
inserted into a compressed kernel.
Having the ability to insert a key into the Linux trust boundary opens
up various possibilities. The end-user can use a pre-built kernel and
sign their own kernel modules. It also opens up the ability for an
end-user to more easily use digital signature based IMA-appraisal. To
get a key into the ima keyring, it must be signed by a key within the
Linux trust boundary.
Downstream Linux distros try to have a single signed kernel for each
architecture. Each end-user may use this kernel in entirely different
ways. Some downstream kernels have chosen to always trust platform keys
within the Linux trust boundary for kernel module signing. These
kernels have no way of using digital signature base IMA appraisal.
This series adds a new MOK variable to shim. This variable allows the
end-user to decide if they want to trust keys enrolled in the MOK within
the Linux trust boundary. By default, nothing changes; MOK keys are
not trusted within the Linux kernel. They are only trusted after the
end-user makes the decision themselves. The end-user would set this
through mokutil using a new --trust-mok option [4]. This would work
similar to how the kernel uses MOK variable to enable/disable signature
validation as well as use/ignore the db.
When shim boots, it mirrors the new MokTML Boot Services variable to a new
MokListTrustedRT Runtime Services variable and extends PCR14.
MokListTrustedRT is written without EFI_VARIABLE_NON_VOLATILE set,
preventing an end-user from setting it after booting and doing a kexec.
When the kernel boots, if MokListTrustedRT is set and
EFI_VARIABLE_NON_VOLATILE is not set, the MokListRT is loaded into the
secondary trusted keyring instead of the platform keyring. Mimi has
suggested that only CA keys or keys that can be vouched for by other
kernel keys be loaded. All other certs will load into the platform
keyring instead.
This is done by introducing a new .mok keyring. This keyring is only
used during boot. After booting it is destroyed and not visible to the
end-user after booting completes. This keyring contains a new keyring
permission that only allows CA keys to be loaded. If the permission
fails, the key is later loaded into the platform keyring. After keys
are added into the .mok keyring, they are moved into the secondary
trusted keyring.
Secure Boot keys will never be trusted. They will always be loaded
into the platform keyring. If an end-user wanted to trust one, they
would need to enroll it into the MOK.
I have included links to both the mokutil [3] and shim [4] changes I
have made to support this new functionality.
Thank you and looking forward to hearing your reviews.
[1] https://lore.kernel.org/linux-integrity/20210517225714.498032-1-eric.snowberg@oracle.com/
[2] https://lore.kernel.org/lkml/1556221605.24945.3.camel@HansenPartnership.com/
[3] https://lore.kernel.org/patchwork/cover/902768/
[4] https://github.com/esnowberg/mokutil/tree/0.3.0-mokvars-v2
[5] https://github.com/esnowberg/shim/tree/mokvars-v2
Eric Snowberg (12):
KEYS: Add KEY_ALLOC_BYPASS_RESTRICTION option to key_move
KEYS: Allow unrestricted keys to be moved to the secondary keyring
KEYS: CA link restriction
integrity: add integrity_destroy_keyring
integrity: Introduce mok keyring
integrity: Trust mok keys if MokListTrustedRT found
integrity: add add_to_mok_keyring
integrity: restrict INTEGRITY_KEYRING_MOK to
restrict_link_by_secondary_trusted_or_ca
integrity: accessor function to get trust_moklist
integrity: add new keyring handler
integrity: move keys from the mok keyring into the secondary keyring
integrity: Suppress error message for keys added to the mok keyring
certs/system_keyring.c | 43 +++++++++
crypto/asymmetric_keys/restrict.c | 60 +++++++++++++
include/crypto/public_key.h | 5 ++
include/keys/system_keyring.h | 21 +++++
security/integrity/Makefile | 3 +-
security/integrity/digsig.c | 26 +++++-
security/integrity/integrity.h | 21 ++++-
.../platform_certs/keyring_handler.c | 17 +++-
.../platform_certs/keyring_handler.h | 5 ++
security/integrity/platform_certs/load_uefi.c | 5 +-
.../integrity/platform_certs/mok_keyring.c | 90 +++++++++++++++++++
security/keys/keyring.c | 10 ++-
12 files changed, 294 insertions(+), 12 deletions(-)
create mode 100644 security/integrity/platform_certs/mok_keyring.c
base-commit: 13311e74253fe64329390df80bed3f07314ddd61
--
2.18.4
^ permalink raw reply
* [PATCH RFC 03/12] KEYS: CA link restriction
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Restrict the addition of keys in a keyring based on the key to be
added being a CA (self-signed) or by being vouched for by a key in
either the built-in or the secondary trusted keyrings.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
certs/system_keyring.c | 18 ++++++++++
crypto/asymmetric_keys/restrict.c | 60 +++++++++++++++++++++++++++++++
include/crypto/public_key.h | 5 +++
include/keys/system_keyring.h | 14 ++++++++
4 files changed, 97 insertions(+)
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index f02bc5832684..b4c82276bba5 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -73,6 +73,24 @@ int restrict_link_by_builtin_and_secondary_trusted(
secondary_trusted_keys);
}
+/**
+ * restrict_link_by_secondary_trusted_or_ca - Restrict keyring
+ * addition by being a CA or vouched by the secondary keyrings.
+ *
+ * Restrict the addition of keys in a keyring based on the key-to-be-added
+ * being a CA (self signed) or by being vouched for by a key in either
+ * the built-in or the secondary system keyrings.
+ */
+int restrict_link_by_secondary_trusted_or_ca(
+ struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *restrict_key)
+{
+ return restrict_link_by_ca(dest_keyring, type, payload,
+ secondary_trusted_keys);
+}
+
/**
* Allocate a struct key_restriction for the "builtin and secondary trust"
* keyring. Only for use in system_trusted_keyring_init().
diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c
index 84cefe3b3585..75e4379226e8 100644
--- a/crypto/asymmetric_keys/restrict.c
+++ b/crypto/asymmetric_keys/restrict.c
@@ -108,6 +108,66 @@ int restrict_link_by_signature(struct key *dest_keyring,
return ret;
}
+/**
+ * restrict_link_by_ca - Restrict additions to a ring of public keys
+ * based on it being a CA
+ * @dest_keyring: Keyring being linked to.
+ * @type: The type of key being added.
+ * @payload: The payload of the new key.
+ * @trusted: A key or ring of keys that can be used to vouch for the new cert.
+ *
+ * Check if the new certificate is a CA or if they key can be vouched for
+ * by keys already linked in the destination keyring or the trusted
+ * keyring. If one of those is the signing key or it is self signed, then
+ * mark the new certificate as being ok to link.
+ *
+ * Returns 0 if the new certificate was accepted, -ENOKEY if we could not find
+ * a matching parent certificate in the trusted list. -ENOPKG if the signature
+ * uses unsupported crypto, or some other error if there is a matching
+ * certificate but the signature check cannot be performed.
+ */
+int restrict_link_by_ca(struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *trust_keyring)
+{
+ const struct public_key_signature *sig;
+ const struct public_key *pkey;
+ struct key *key;
+ int ret;
+
+ if (type != &key_type_asymmetric)
+ return -EOPNOTSUPP;
+
+ sig = payload->data[asym_auth];
+ if (!sig)
+ return -ENOPKG;
+
+ if (!sig->auth_ids[0] && !sig->auth_ids[1])
+ return -ENOKEY;
+
+ pkey = payload->data[asym_crypto];
+ if (!pkey)
+ return -ENOPKG;
+
+ ret = public_key_verify_signature(pkey, sig);
+ if (!ret)
+ return 0;
+
+ if (!trust_keyring)
+ return -ENOKEY;
+
+ key = find_asymmetric_key(trust_keyring,
+ sig->auth_ids[0], sig->auth_ids[1],
+ false);
+ if (IS_ERR(key))
+ return -ENOKEY;
+
+ ret = verify_signature(key, sig);
+ key_put(key);
+ return ret;
+}
+
static bool match_either_id(const struct asymmetric_key_ids *pair,
const struct asymmetric_key_id *single)
{
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 47accec68cb0..545af1ea57de 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -71,6 +71,11 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring,
const union key_payload *payload,
struct key *trusted);
+extern int restrict_link_by_ca(struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *trust_keyring);
+
extern int query_asymmetric_key(const struct kernel_pkey_params *,
struct kernel_pkey_query *);
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index f40837026d6d..43c76fba9481 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -34,10 +34,24 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key);
+extern int restrict_link_by_secondary_trusted_or_ca(
+ struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *restrict_key);
extern __init int move_to_trusted_secondary_keyring(struct key *key,
struct key *from_keyring);
#else
#define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
+static inline int restrict_link_by_secondary_trusted_or_ca(
+ struct key *dest_keyring,
+ const struct key_type *type,
+ const union key_payload *payload,
+ struct key *restrict_key)
+{
+ return -ENOKEY;
+}
+
static inline __init int move_to_trusted_secondary_keyring(struct key *key,
struct key *from_keyring)
{
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 04/12] integrity: add integrity_destroy_keyring
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Not all kernel keyrings need to survive past boot. Add a destroy
function to remove a keyring no longer needed.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/integrity/digsig.c | 8 ++++++++
security/integrity/integrity.h | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 3b06a01bd0fd..a8436c6b93ec 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -145,6 +145,14 @@ int __init integrity_init_keyring(const unsigned int id)
return __integrity_init_keyring(id, perm, restriction);
}
+void __init integrity_destroy_keyring(const unsigned int id)
+{
+ if (id >= INTEGRITY_KEYRING_MAX)
+ return;
+ key_put(keyring[id]);
+ keyring[id] = NULL;
+}
+
static int __init integrity_add_key(const unsigned int id, const void *data,
off_t size, key_perm_t perm)
{
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 547425c20e11..f801b2076f01 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -164,6 +164,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
int integrity_modsig_verify(unsigned int id, const struct modsig *modsig);
int __init integrity_init_keyring(const unsigned int id);
+void __init integrity_destroy_keyring(const unsigned int id);
int __init integrity_load_x509(const unsigned int id, const char *path);
int __init integrity_load_cert(const unsigned int id, const char *source,
const void *data, size_t len, key_perm_t perm);
@@ -187,6 +188,10 @@ static inline int integrity_init_keyring(const unsigned int id)
return 0;
}
+static inline void __init integrity_destroy_keyring(const unsigned int id)
+{
+}
+
static inline int __init integrity_load_cert(const unsigned int id,
const char *source,
const void *data, size_t len,
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 09/12] integrity: accessor function to get trust_moklist
From: Eric Snowberg @ 2021-07-07 2:44 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Add an accessor function to see if the mok list should be trusted.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/integrity/integrity.h | 5 +++++
security/integrity/platform_certs/mok_keyring.c | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 68720fa6454f..a5f7af825f9b 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -285,6 +285,7 @@ void __init add_to_platform_keyring(const char *source, const void *data,
size_t len);
void __init destroy_mok_keyring(void);
void __init add_to_mok_keyring(const char *source, const void *data, size_t len);
+bool __init trust_moklist(void);
#else
static inline void __init add_to_platform_keyring(const char *source,
const void *data, size_t len)
@@ -296,4 +297,8 @@ static inline void __init destroy_mok_keyring(void)
void __init add_to_mok_keyring(const char *source, const void *data, size_t len)
{
}
+static inline bool __init trust_moklist(void)
+{
+ return false;
+}
#endif
diff --git a/security/integrity/platform_certs/mok_keyring.c b/security/integrity/platform_certs/mok_keyring.c
index a5644a8a834c..7d23772a1135 100644
--- a/security/integrity/platform_certs/mok_keyring.c
+++ b/security/integrity/platform_certs/mok_keyring.c
@@ -83,3 +83,8 @@ static __init int mok_keyring_trust_setup(void)
}
late_initcall(mok_keyring_trust_setup);
+
+bool __init trust_moklist(void)
+{
+ return trust_mok;
+}
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 05/12] integrity: Introduce mok keyring
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Introduce a new keyring called mok. This keyring will be used during
boot. Afterwards it will be destroyed.
Follow on patches will use this keyring to load trusted MOK keys.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
security/integrity/Makefile | 3 ++-
security/integrity/digsig.c | 1 +
security/integrity/integrity.h | 7 ++++-
security/integrity/platform_certs/load_uefi.c | 1 +
.../integrity/platform_certs/mok_keyring.c | 26 +++++++++++++++++++
5 files changed, 36 insertions(+), 2 deletions(-)
create mode 100644 security/integrity/platform_certs/mok_keyring.c
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 7ee39d66cf16..8e2e98cba1f6 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -9,7 +9,8 @@ integrity-y := iint.o
integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
-integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o
+integrity-$(CONFIG_INTEGRITY_PLATFORM_KEYRING) += platform_certs/platform_keyring.o \
+ platform_certs/mok_keyring.o
integrity-$(CONFIG_LOAD_UEFI_KEYS) += platform_certs/efi_parser.o \
platform_certs/load_uefi.o \
platform_certs/keyring_handler.o
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index a8436c6b93ec..56800a5f1e10 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -30,6 +30,7 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
".ima",
#endif
".platform",
+ ".mok",
};
#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index f801b2076f01..5126c80bd0d4 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -151,7 +151,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
#define INTEGRITY_KEYRING_EVM 0
#define INTEGRITY_KEYRING_IMA 1
#define INTEGRITY_KEYRING_PLATFORM 2
-#define INTEGRITY_KEYRING_MAX 3
+#define INTEGRITY_KEYRING_MOK 3
+#define INTEGRITY_KEYRING_MAX 4
extern struct dentry *integrity_dir;
@@ -282,9 +283,13 @@ integrity_audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type)
#ifdef CONFIG_INTEGRITY_PLATFORM_KEYRING
void __init add_to_platform_keyring(const char *source, const void *data,
size_t len);
+void __init destroy_mok_keyring(void);
#else
static inline void __init add_to_platform_keyring(const char *source,
const void *data, size_t len)
{
}
+static inline void __init destroy_mok_keyring(void)
+{
+}
#endif
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
index f290f78c3f30..94faa4b32441 100644
--- a/security/integrity/platform_certs/load_uefi.c
+++ b/security/integrity/platform_certs/load_uefi.c
@@ -193,6 +193,7 @@ static int __init load_uefi_certs(void)
/* Load the MokListRT certs */
rc = load_moklist_certs();
+ destroy_mok_keyring();
return rc;
}
diff --git a/security/integrity/platform_certs/mok_keyring.c b/security/integrity/platform_certs/mok_keyring.c
new file mode 100644
index 000000000000..2b0d17caf8fd
--- /dev/null
+++ b/security/integrity/platform_certs/mok_keyring.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MOK keyring routines.
+ *
+ * Copyright (c) 2021, Oracle and/or its affiliates.
+ */
+
+#include "../integrity.h"
+
+static __init int mok_keyring_init(void)
+{
+ int rc;
+
+ rc = integrity_init_keyring(INTEGRITY_KEYRING_MOK);
+ if (rc)
+ return rc;
+
+ pr_notice("MOK Keyring initialized\n");
+ return 0;
+}
+device_initcall(mok_keyring_init);
+
+void __init destroy_mok_keyring(void)
+{
+ return integrity_destroy_keyring(INTEGRITY_KEYRING_MOK);
+}
--
2.18.4
^ permalink raw reply related
* [PATCH RFC 02/12] KEYS: Allow unrestricted keys to be moved to the secondary keyring
From: Eric Snowberg @ 2021-07-07 2:43 UTC (permalink / raw)
To: keyrings, linux-integrity, zohar, dhowells, dwmw2, herbert, davem,
jarkko, jmorris, serge
Cc: eric.snowberg, keescook, gregkh, torvalds, scott.branden,
weiyongjun1, nayna, ebiggers, ardb, nramas, lszubowi,
linux-kernel, linux-crypto, linux-security-module,
James.Bottomley, pjones, glin, konrad.wilk
In-Reply-To: <20210707024403.1083977-1-eric.snowberg@oracle.com>
Allow keys to be moved into the secondary keyring without checking its
trust chain. This is available only during kernel initialization.
This will allow keys in the MOK list to be added during boot.
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
---
certs/system_keyring.c | 25 +++++++++++++++++++++++++
include/keys/system_keyring.h | 7 +++++++
2 files changed, 32 insertions(+)
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 692365dee2bd..f02bc5832684 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -90,6 +90,31 @@ static __init struct key_restriction *get_builtin_and_secondary_restriction(void
return restriction;
}
+
+/**
+ * move_to_trusted_secondary_keyring - Move to the secondary trusted
+ * keyring with no validation.
+ * @key: The key to add to the secondary trusted keyring
+ * @from_keyring: The keyring containing the key to move from
+ *
+ * Move key to the secondary keyring without checking its trust chain. This
+ * is available only during kernel initialization.
+ */
+__init int move_to_trusted_secondary_keyring(struct key *key, struct key *from_keyring)
+{
+ int ret;
+
+ ret = key_move(key, from_keyring, secondary_trusted_keys,
+ KEY_ALLOC_BYPASS_RESTRICTION);
+
+ if (ret)
+ pr_err("Problem loading X.509 certificate %d\n", ret);
+ else
+ pr_notice("Loaded X.509 cert '%s' linked to secondary sys keyring\n",
+ key->description);
+
+ return ret;
+}
#endif
/*
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 6acd3cf13a18..f40837026d6d 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -34,8 +34,15 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key);
+extern __init int move_to_trusted_secondary_keyring(struct key *key,
+ struct key *from_keyring);
#else
#define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
+static inline __init int move_to_trusted_secondary_keyring(struct key *key,
+ struct key *from_keyring)
+{
+ return -EKEYREVOKED;
+}
#endif
extern struct pkcs7_message *pkcs7;
--
2.18.4
^ permalink raw reply related
* [PATCH 1/1] NAX LSM: Add initial support support
From: Igor Zhbanov @ 2021-07-07 1:03 UTC (permalink / raw)
To: linux-integrity, linux-security-module; +Cc: Igor Zhbanov, Mimi Zohar
NAX (No Anonymous Execution) is a Linux Security Module that extends DAC
by making impossible to make anonymous and modified pages executable for
privileged processes.
The module intercepts anonymous executable pages created with mmap() and
mprotect() system calls.
Depending on the settings, the module can block and log violating system
calls or log and kill the violating process.
Signed-off-by: Igor Zhbanov <i.zhbanov@omp.ru>
---
Documentation/admin-guide/LSM/NAX.rst | 48 ++++
Documentation/admin-guide/LSM/index.rst | 1 +
security/Kconfig | 11 +-
security/Makefile | 2 +
security/nax/Kconfig | 71 +++++
security/nax/Makefile | 4 +
security/nax/nax-lsm.c | 344 ++++++++++++++++++++++++
7 files changed, 476 insertions(+), 5 deletions(-)
create mode 100644 Documentation/admin-guide/LSM/NAX.rst
create mode 100644 security/nax/Kconfig
create mode 100644 security/nax/Makefile
create mode 100644 security/nax/nax-lsm.c
diff --git a/Documentation/admin-guide/LSM/NAX.rst b/Documentation/admin-guide/LSM/NAX.rst
new file mode 100644
index 000000000000..b742f881f3d7
--- /dev/null
+++ b/Documentation/admin-guide/LSM/NAX.rst
@@ -0,0 +1,48 @@
+=======
+NAX LSM
+=======
+
+:Author: Igor Zhbanov
+
+NAX (No Anonymous Execution) is a Linux Security Module that extends DAC
+by making impossible to make anonymous and modified pages executable for
+privileged processes. The module intercepts anonymous executable pages
+created with mmap() and mprotect() system calls.
+
+To select it at boot time, specify ``security=nax`` (though this will
+disable any other LSM).
+
+The privileged process is a process for which any of the following is true:
+
+- ``uid == 0``
+- ``euid == 0``
+- ``suid == 0``
+- ``fsuid == 0``
+- ``cap_effective`` has any capability except of ``kernel.nax.allowed_caps``
+- ``cap_permitted`` has any capability except of ``kernel.nax.allowed_caps``
+
+The following sysctl parameters are available:
+
+* ``kernel.nax.allowed_caps``:
+
+ Hexadecimal number representing allowed capabilities set for the privileged
+ processes.
+
+* ``kernel.nax.enforcing``:
+
+ - 0: Only log errors (when enabled by ``kernel.nax.quiet``)
+ - 1: Forbid unsafe pages mappings (default)
+
+* ``kernel.nax.locked``:
+
+ - 0: Changing of the module's sysctl parameters is allowed
+ - 1: Further changing of the module's sysctl parameters is forbidden
+
+ Setting this parameter to ``1`` after initial setup during the system boot
+ will prevent the module disabling at the later time.
+
+* ``kernel.nax.quiet``:
+
+ - 0: Log violations (default)
+ - 1: Be quiet
+ - 2: Kill the violating process and log
diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst
index a6ba95fbaa9f..e9df7fc9a461 100644
--- a/Documentation/admin-guide/LSM/index.rst
+++ b/Documentation/admin-guide/LSM/index.rst
@@ -42,6 +42,7 @@ subdirectories.
apparmor
LoadPin
+ NAX
SELinux
Smack
tomoyo
diff --git a/security/Kconfig b/security/Kconfig
index 0ced7fd33e4d..771419647ae1 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -239,6 +239,7 @@ source "security/yama/Kconfig"
source "security/safesetid/Kconfig"
source "security/lockdown/Kconfig"
source "security/landlock/Kconfig"
+source "security/nax/Kconfig"
source "security/integrity/Kconfig"
@@ -278,11 +279,11 @@ endchoice
config LSM
string "Ordered list of enabled LSMs"
- default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK
- default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR
- default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO
- default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC
- default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf"
+ default "nax,landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK
+ default "nax,landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR
+ default "nax,landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO
+ default "nax,landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC
+ default "nax,landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf"
help
A comma-separated list of LSMs, in initialization order.
Any LSMs left off this list will be ignored. This can be
diff --git a/security/Makefile b/security/Makefile
index 47e432900e24..5c261bbf4659 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -14,6 +14,7 @@ subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid
subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown
subdir-$(CONFIG_BPF_LSM) += bpf
subdir-$(CONFIG_SECURITY_LANDLOCK) += landlock
+subdir-$(CONFIG_SECURITY_NAX) += nax
# always enable default capabilities
obj-y += commoncap.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/
obj-$(CONFIG_CGROUPS) += device_cgroup.o
obj-$(CONFIG_BPF_LSM) += bpf/
obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/
+obj-$(CONFIG_SECURITY_NAX) += nax/
# Object integrity file lists
subdir-$(CONFIG_INTEGRITY) += integrity
diff --git a/security/nax/Kconfig b/security/nax/Kconfig
new file mode 100644
index 000000000000..60ef0964f00a
--- /dev/null
+++ b/security/nax/Kconfig
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SECURITY_NAX
+ bool "NAX support"
+ depends on SECURITY
+ default n
+ help
+ This selects NAX (No Anonymous Execution), which extends DAC
+ support with additional system-wide security settings beyond
+ regular Linux discretionary access controls. Currently available
+ is restriction to make anonymous and modified pages executable
+ to privileged processes. Like capabilities, this security module
+ stacks with other LSMs. Further information can be found in
+ Documentation/admin-guide/LSM/NAX.rst.
+
+ If you are unsure how to answer this question, answer N.
+
+config SECURITY_NAX_LOCKED
+ bool "Lock NAX settings"
+ depends on SECURITY_NAX
+ help
+ If selected, it will not be possible to change enforcing and quiet
+ settings via sysctl or the kernel command line. If not selected,
+ it can be enabled at boot with the kernel parameter "nax_locked=1"
+ or "kernel.nax_locked=1" sysctl (if the settings are not locked).
+
+config SECURITY_NAX_QUIET
+ bool "Silence NAX messages"
+ depends on SECURITY_NAX
+ help
+ If selected, NAX will not print violations. If not selected, it can
+ be enabled at boot with the kernel parameter "nax_quiet=1" or
+ "kernel.nax_quiet=1" sysctl (if the settings are not locked).
+
+choice
+ prompt "NAX violation action mode"
+ default SECURITY_NAX_MODE_LOG
+ depends on SECURITY_NAX
+ help
+ Select the NAX violation action mode.
+
+ In the default permissive mode the violations are only logged
+ (if logging is not suppressed). In the enforcing mode the violations
+ are prohibited. And in the kill mode the process is terminated.
+
+ The value can be changed at boot with the kernel parameter
+ "nax_mode" (0, 1, 2) or "kernel.nax_mode=" (0, 1, 2) sysctl (if the
+ settings are not locked).
+
+ config SECURITY_NAX_MODE_LOG
+ bool "Permissive mode"
+ help
+ In this mode violations are only logged (if logging is not
+ suppressed).
+ config SECURITY_NAX_MODE_ENFORCING
+ bool "Enforcing mode"
+ help
+ In this mode violations are prohibited and logged (if
+ logging is not suppressed).
+ config SECURITY_NAX_MODE_KILL
+ bool "Kill mode"
+ help
+ In this mode the voilating process is terminated. The event
+ is logged (if logging is not suppressed).
+endchoice
+
+config SECURITY_NAX_MODE
+ int
+ depends on SECURITY_NAX
+ default 0 if SECURITY_NAX_MODE_LOG
+ default 1 if SECURITY_NAX_MODE_ENFORCING
+ default 2 if SECURITY_NAX_MODE_KILL
diff --git a/security/nax/Makefile b/security/nax/Makefile
new file mode 100644
index 000000000000..9c3372210c77
--- /dev/null
+++ b/security/nax/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SECURITY_NAX) := nax.o
+
+nax-y := nax-lsm.o
diff --git a/security/nax/nax-lsm.c b/security/nax/nax-lsm.c
new file mode 100644
index 000000000000..ef99d9b36a9d
--- /dev/null
+++ b/security/nax/nax-lsm.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2016-2021 Open Mobile Platform LLC.
+ *
+ * Written by: Igor Zhbanov <i.zhbanov@omp.ru, izh1979@gmail.com>
+ *
+ * NAX (No Anonymous Execution) Linux Security Module
+ * This module prevents execution of the code in anonymous or modified pages.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation. */
+
+#define pr_fmt(fmt) "NAX: " fmt
+
+#include <linux/capability.h>
+#include <linux/cred.h>
+#include <linux/ctype.h>
+#include <linux/lsm_hooks.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <linux/securebits.h>
+#include <linux/security.h>
+#include <linux/sysctl.h>
+#include <linux/uidgid.h>
+
+#define NAX_MODE_PERMISSIVE 0 /* Log only */
+#define NAX_MODE_ENFORCING 1 /* Enforce and log */
+#define NAX_MODE_KILL 2 /* Kill process and log */
+
+static int mode = CONFIG_SECURITY_NAX_MODE,
+ quiet = IS_ENABLED(CONFIG_SECURITY_NAX_QUIET),
+ locked = IS_ENABLED(CONFIG_SECURITY_NAX_LOCKED);
+
+#define ALLOWED_CAPS_HEX_LEN (_KERNEL_CAPABILITY_U32S * 8)
+
+static char allowed_caps_hex[ALLOWED_CAPS_HEX_LEN + 1];
+static kernel_cap_t allowed_caps = CAP_EMPTY_SET;
+
+static int
+is_privileged_process(void)
+{
+ const struct cred *cred;
+ kuid_t root_uid;
+
+ cred = current_cred();
+ root_uid = make_kuid(cred->user_ns, 0);
+ /* We count a process as privileged if it any of its IDs is zero
+ * or it has any unsafe capability (even in a user namespace) */
+ if ((!issecure(SECURE_NOROOT) && (uid_eq(cred->uid, root_uid) ||
+ uid_eq(cred->euid, root_uid) ||
+ uid_eq(cred->suid, root_uid) ||
+ uid_eq(cred->fsuid, root_uid))) ||
+ (!cap_issubset(cred->cap_effective, allowed_caps)) ||
+ (!cap_issubset(cred->cap_permitted, allowed_caps)))
+ return 1;
+
+ return 0;
+}
+
+static void
+log_warn(const char *reason)
+{
+ if (quiet)
+ return;
+
+ pr_warn_ratelimited("%s: pid=%d, uid=%u, comm=\"%s\"\n",
+ reason, current->pid,
+ from_kuid(&init_user_ns, current_cred()->uid),
+ current->comm);
+}
+
+static void
+kill_current_task(void)
+{
+ pr_warn("Killing pid=%d, uid=%u, comm=\"%s\"\n",
+ current->pid, from_kuid(&init_user_ns, current_cred()->uid),
+ current->comm);
+ force_sig(SIGKILL);
+}
+
+static int
+nax_mmap_file(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags)
+{
+ int ret = 0;
+
+ if (mode == NAX_MODE_PERMISSIVE && quiet)
+ return 0; /* Skip further checks in this case */
+
+ if (!(prot & PROT_EXEC)) /* Not executable memory */
+ return 0;
+
+ if (!is_privileged_process())
+ return 0; /* Not privileged processes can do anything */
+
+ if (!file) { /* Anonymous executable memory */
+ log_warn("MMAP_ANON_EXEC");
+ ret = -EACCES;
+ } else if (prot & PROT_WRITE) { /* Mapping file RWX */
+ log_warn("MMAP_FILE_WRITE_EXEC");
+ ret = -EACCES;
+ }
+
+ if (mode == NAX_MODE_KILL)
+ kill_current_task();
+
+ return (mode != NAX_MODE_PERMISSIVE) ? ret : 0;
+}
+
+static int
+nax_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot)
+{
+ if (mode == NAX_MODE_PERMISSIVE && quiet)
+ return 0; /* Skip further checks in this case */
+
+ if (!(prot & PROT_EXEC)) /* Not executable memory */
+ return 0;
+
+ if (!is_privileged_process())
+ return 0; /* Not privileged processes can do anything */
+
+ if (!(vma->vm_flags & VM_EXEC)) {
+ int ret = 0;
+
+ if (vma->vm_start >= vma->vm_mm->start_brk &&
+ vma->vm_end <= vma->vm_mm->brk) {
+ log_warn("MPROTECT_EXEC_HEAP");
+ ret = -EACCES;
+ } else if (!vma->vm_file &&
+ ((vma->vm_start <= vma->vm_mm->start_stack &&
+ vma->vm_end >= vma->vm_mm->start_stack) ||
+ vma_is_stack_for_current(vma))) {
+ log_warn("MPROTECT_EXEC_STACK");
+ ret = -EACCES;
+ } else if (vma->vm_file && vma->anon_vma) {
+ /* We are making executable a file mapping that has
+ * had some COW done. Since pages might have been
+ * written, check ability to execute the possibly
+ * modified content. This typically should only
+ * occur for text relocations. */
+ log_warn("MPROTECT_EXEC_MODIFIED");
+ ret = -EACCES;
+ }
+
+ if (ret) {
+ if (mode == NAX_MODE_KILL)
+ kill_current_task();
+
+ return (mode != NAX_MODE_PERMISSIVE) ? ret : 0;
+ }
+ }
+
+ return nax_mmap_file(vma->vm_file, reqprot, prot,
+ vma->vm_flags & VM_SHARED);
+}
+
+static struct security_hook_list nax_hooks[] __lsm_ro_after_init = {
+ LSM_HOOK_INIT(mmap_file, nax_mmap_file),
+ LSM_HOOK_INIT(file_mprotect, nax_file_mprotect),
+};
+
+#ifdef CONFIG_SYSCTL
+
+static int
+nax_dointvec_minmax(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ if (write && (!capable(CAP_SYS_ADMIN) || locked))
+ return -EPERM;
+
+ return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+}
+
+static int
+nax_dostring(struct ctl_table *table, int write, void *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ if (write) {
+ int error;
+ char *buf = (char *)buffer;
+ size_t len = *lenp, i;
+ kernel_cap_t caps = CAP_EMPTY_SET;
+
+ if (!capable(CAP_SYS_ADMIN) || locked)
+ return -EPERM;
+
+ /* Do not allow trailing garbage or excessive length */
+ if (len == ALLOWED_CAPS_HEX_LEN + 1) {
+ if (buf[--len] != '\n')
+ return -EINVAL;
+ } else if (len > ALLOWED_CAPS_HEX_LEN || len <= 0)
+ return -EINVAL;
+
+ if ((error = proc_dostring(table, write, buffer, lenp, ppos)))
+ return error;
+
+ len = strlen(allowed_caps_hex);
+ for (i = 0; i < len; i++)
+ if (!isxdigit(allowed_caps_hex[i]))
+ return -EINVAL;
+
+ for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
+ unsigned long l;
+
+ if (kstrtoul(allowed_caps_hex +
+ (len >= 8 ? len - 8 : 0), 16, &l))
+ return -EINVAL;
+
+ caps.cap[i] = l;
+ if (len < 8)
+ break;
+
+ len -= 8;
+ allowed_caps_hex[len] = '\0';
+ }
+
+ allowed_caps = cap_intersect(caps, CAP_FULL_SET);
+ return 0;
+ } else {
+ unsigned i;
+
+ CAP_FOR_EACH_U32(i)
+ snprintf(allowed_caps_hex + i * 8, 9, "%08x",
+ allowed_caps.cap[CAP_LAST_U32 - i]);
+
+ return proc_dostring(table, write, buffer, lenp, ppos);
+ }
+}
+
+struct ctl_path nax_sysctl_path[] = {
+ { .procname = "kernel" },
+ { .procname = "nax" },
+ { }
+};
+
+static int max_mode = NAX_MODE_KILL;
+
+static struct ctl_table nax_sysctl_table[] = {
+ {
+ .procname = "allowed_caps",
+ .data = allowed_caps_hex,
+ .maxlen = ALLOWED_CAPS_HEX_LEN + 1,
+ .mode = 0644,
+ .proc_handler = nax_dostring,
+ }, {
+ .procname = "locked",
+ .data = &locked,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = nax_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ }, {
+ .procname = "mode",
+ .data = &mode,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = nax_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = &max_mode,
+ }, {
+ .procname = "quiet",
+ .data = &quiet,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = nax_dointvec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
+ { }
+};
+
+static void __init
+nax_init_sysctl(void)
+{
+ if (!register_sysctl_paths(nax_sysctl_path, nax_sysctl_table))
+ panic("NAX: sysctl registration failed.\n");
+}
+
+#else /* !CONFIG_SYSCTL */
+
+static inline void
+nax_init_sysctl(void)
+{
+
+}
+
+#endif /* !CONFIG_SYSCTL */
+
+static int __init setup_mode(char *str)
+{
+ unsigned long val;
+
+ if (!locked && !kstrtoul(str, 0, &val)) {
+ if (val > max_mode){
+ pr_err("Invalid 'nax_mode' parameter value (%s)\n",
+ str);
+ val = max_mode;
+ }
+
+ mode = val;
+ }
+
+ return 1;
+}
+__setup("nax_mode=", setup_mode);
+
+static int __init setup_quiet(char *str)
+{
+ unsigned long val;
+
+ if (!locked && !kstrtoul(str, 0, &val))
+ quiet = val ? 1 : 0;
+
+ return 1;
+}
+__setup("nax_quiet=", setup_quiet);
+
+static int __init setup_locked(char *str)
+{
+ unsigned long val;
+
+ if (!locked && !kstrtoul(str, 0, &val))
+ locked = val ? 1 : 0;
+
+ return 1;
+}
+__setup("nax_locked=", setup_locked);
+
+static __init int
+nax_init(void)
+{
+ pr_info("Starting.\n");
+ security_add_hooks(nax_hooks, ARRAY_SIZE(nax_hooks), "nax");
+ nax_init_sysctl();
+
+ return 0;
+}
+
+DEFINE_LSM(nax) = {
+ .name = "nax",
+ .init = nax_init,
+};
--
2.26.2
^ permalink raw reply related
* [PATCH 0/1] NAX (No Anonymous Execution) LSM
From: Igor Zhbanov @ 2021-07-07 1:03 UTC (permalink / raw)
To: linux-integrity, linux-security-module; +Cc: Igor Zhbanov, Mimi Zohar
[Overview]
Fileless malware attacks are becoming more and more popular, and even
ready-to-use frameworks are available [1], [2], [3]. They are based on
running of the malware code from anonymous executable memory pages (which
are not backed by an executable file or a library on a filesystem.) This
allows effectively hiding malware presence in a system, making filesystem
integrity checking tools unable to detect the intrusion.
Typically, the malware first needs to intercept the execution flow (e.g.,
by the means of ROP-based exploit). Then it needs to download the main
part (in the form of normal executable or library) from its server,
because it is hard to implement the entire exploit in ROP-based form.
There are a number of security mechanisms that can ensure the integrity
of the file-system, but we need to ensure the integrity of the code in
memory too, to be sure, that only authorized code is running in the
system.
The proposed LSM is preventing the creation of anonymous executable pages
for the privileged processes. The LSM intercepts mmap() and mprotect()
system calls and handles it similarly to SELinux handlers.
The module allows to block the violating system call or to kill the
violating process, along with rate-limited logging.
Currently, the module restricts only the privileged processes. The
privileged process is a process for which any of the following is true:
+ uid == 0 && !issecure(SECURE_NOROOT)
+ euid == 0 && !issecure(SECURE_NOROOT)
+ suid == 0 && !issecure(SECURE_NOROOT)
+ fsuid == 0 && !issecure(SECURE_NOROOT)
+ cap_effective has any capability except of kernel.nax.allowed_caps
+ cap_permitted has any capability except of kernel.nax.allowed_caps
The sysctl parameter kernel.nax.allowed_caps allows to define safe
capabilities set for the privileged processes.
[JIT]
Because of blocked anonymous code execution, JIT-compiled code, some
interpreters (which are using JIT) and libffi-based projects can be
broken.
Our observation shows that such processes are typically running by a
user, so they will not be privileged, so they will be allowed to use
anonymous executable pages.
But for small embedded set-ups it could be possible to get rid of such
processes at all, so the module could be enabled without further
restrictions to protect both privileged and non-privileged processes.
In addition, libffi can be modified not to use anonymous executable
pages.
[Similar implementations]
Although SELinux could be used to enable similar functionality, this LSM
is simpler. It could be used in set-ups, where SELinux would be overkill.
There is also SARA LSM module, which solves similar task, but it is more
complex.
[Cooperation with other security mechanisms]
NAX LSM is more useful in conjunction with IMA. IMA would be responsible
for integrity checking of file-based executables and libraries, and
NAX LSM would be responsible for preventing of anonymous code execution.
Alternatively, NAX LSM can be used with read-only root file system,
protected by dm-verity/fs-verity.
[TODO]
- Implement xattrs support for marking privileged binaries on a per-file
basis.
- Store NAX attributes in the per-task LSM blob to implement special
launchers for the privileged processes, so all of the children processes
of such a launcher would be allowed to have anonymous executable pages
(but not to grandchildren).
[Links]
[1] https://blog.fbkcs.ru/elf-in-memory-execution/
[2] https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html
[3] https://www.prodefence.org/fireelf-fileless-linux-malware-framework/
P.S. I may continue to work on this LSM from my personal e-mail
izh1979@gmail.com.
Igor Zhbanov (1):
NAX LSM: Add initial support support
Documentation/admin-guide/LSM/NAX.rst | 48 ++++
Documentation/admin-guide/LSM/index.rst | 1 +
security/Kconfig | 11 +-
security/Makefile | 2 +
security/nax/Kconfig | 71 +++++
security/nax/Makefile | 4 +
security/nax/nax-lsm.c | 344 ++++++++++++++++++++++++
7 files changed, 476 insertions(+), 5 deletions(-)
create mode 100644 Documentation/admin-guide/LSM/NAX.rst
create mode 100644 security/nax/Kconfig
create mode 100644 security/nax/Makefile
create mode 100644 security/nax/nax-lsm.c
--
2.26.2
^ permalink raw reply
* Re: [PATCH] ima: Support euid keyword for buffer measurement
From: Lakshmi Ramasubramanian @ 2021-07-06 19:29 UTC (permalink / raw)
To: Roberto Sassu, zohar
Cc: tusharsu, linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <20210705115650.3373599-1-roberto.sassu@huawei.com>
On 7/5/2021 4:56 AM, Roberto Sassu wrote:
Hi Roberto,
> This patch makes the 'euid' keyword available for buffer measurement rules,
> in the same way as for other rules. Currently, there is only support for
> the 'uid' keyword.
>
> With this change, buffer measurement (or non-measurement) can depend also
> on the process effective UID.
Who (kernel component) will be using this?
Maybe you could make this change as part of the patch set in which the
above "euid" support will be used.
thanks,
-lakshmi
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> security/integrity/ima/ima_policy.c | 12 +++++++++++-
> 1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index fd5d46e511f1..fdaa030fb04b 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -480,6 +480,16 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule,
> if ((rule->flags & IMA_UID) && !rule->uid_op(cred->uid, rule->uid))
> return false;
>
> + if (rule->flags & IMA_EUID) {
> + if (has_capability_noaudit(current, CAP_SETUID)) {
> + if (!rule->uid_op(cred->euid, rule->uid)
> + && !rule->uid_op(cred->suid, rule->uid)
> + && !rule->uid_op(cred->uid, rule->uid))
> + return false;
> + } else if (!rule->uid_op(cred->euid, rule->uid))
> + return false;
> + }
> +
> switch (rule->func) {
> case KEY_CHECK:
> if (!rule->keyrings)
> @@ -1153,7 +1163,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
> if (entry->action & ~(MEASURE | DONT_MEASURE))
> return false;
>
> - if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_PCR |
> + if (entry->flags & ~(IMA_FUNC | IMA_UID | IMA_EUID | IMA_PCR |
> IMA_LABEL))
> return false;
>
>
^ permalink raw reply
* Re: [PATCH v3 3/3] ima: Add digest and digest_len params to the functions to measure a buffer
From: Lakshmi Ramasubramanian @ 2021-07-06 19:24 UTC (permalink / raw)
To: Roberto Sassu, zohar, paul
Cc: stephen.smalley.work, prsriva02, tusharsu, linux-integrity,
linux-security-module, linux-kernel, selinux
In-Reply-To: <20210705090922.3321178-4-roberto.sassu@huawei.com>
On 7/5/2021 2:09 AM, Roberto Sassu wrote:
> This patch adds the 'digest' and 'digest_len' parameters to
> ima_measure_critical_data() and process_buffer_measurement(), so that
> callers can get the digest of the passed buffer.
>
> These functions calculate the digest even if there is no suitable rule in
> the IMA policy and, in this case, they simply return 1 before generating a
> new measurement entry.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> include/linux/ima.h | 5 +--
> security/integrity/ima/ima.h | 2 +-
> security/integrity/ima/ima_appraise.c | 2 +-
> security/integrity/ima/ima_asymmetric_keys.c | 2 +-
> security/integrity/ima/ima_init.c | 3 +-
> security/integrity/ima/ima_main.c | 36 ++++++++++++++------
> security/integrity/ima/ima_queue_keys.c | 2 +-
> security/selinux/ima.c | 6 ++--
> 8 files changed, 39 insertions(+), 19 deletions(-)
Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
-lakshmi
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 60492263aa64..b6ab66a546ae 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -38,7 +38,7 @@ extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
> extern int ima_measure_critical_data(const char *event_label,
> const char *event_name,
> const void *buf, size_t buf_len,
> - bool hash);
> + bool hash, u8 *digest, size_t digest_len);
>
> #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
> extern void ima_appraise_parse_cmdline(void);
> @@ -147,7 +147,8 @@ static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {
> static inline int ima_measure_critical_data(const char *event_label,
> const char *event_name,
> const void *buf, size_t buf_len,
> - bool hash)
> + bool hash, u8 *digest,
> + size_t digest_len)
> {
> return -ENOENT;
> }
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 03db221324c3..2f4c20b16ad7 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -268,7 +268,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
> struct inode *inode, const void *buf, int size,
> const char *eventname, enum ima_hooks func,
> int pcr, const char *func_data,
> - bool buf_hash);
> + bool buf_hash, u8 *digest, size_t digest_len);
> void ima_audit_measurement(struct integrity_iint_cache *iint,
> const unsigned char *filename);
> int ima_alloc_init_template(struct ima_event_data *event_data,
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index ef9dcfce45d4..63bec42c353f 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -357,7 +357,7 @@ int ima_check_blacklist(struct integrity_iint_cache *iint,
> if ((rc == -EPERM) && (iint->flags & IMA_MEASURE))
> process_buffer_measurement(&init_user_ns, NULL, digest, digestsize,
> "blacklisted-hash", NONE,
> - pcr, NULL, false);
> + pcr, NULL, false, NULL, 0);
> }
>
> return rc;
> diff --git a/security/integrity/ima/ima_asymmetric_keys.c b/security/integrity/ima/ima_asymmetric_keys.c
> index c985418698a4..f6aa0b47a772 100644
> --- a/security/integrity/ima/ima_asymmetric_keys.c
> +++ b/security/integrity/ima/ima_asymmetric_keys.c
> @@ -62,5 +62,5 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
> */
> process_buffer_measurement(&init_user_ns, NULL, payload, payload_len,
> keyring->description, KEY_CHECK, 0,
> - keyring->description, false);
> + keyring->description, false, NULL, 0);
> }
> diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
> index 5076a7d9d23e..b26fa67476b4 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -154,7 +154,8 @@ int __init ima_init(void)
> ima_init_key_queue();
>
> ima_measure_critical_data("kernel_info", "kernel_version",
> - UTS_RELEASE, strlen(UTS_RELEASE), false);
> + UTS_RELEASE, strlen(UTS_RELEASE), false,
> + NULL, 0);
>
> return rc;
> }
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index b512c06d8ee1..360266da5a10 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -838,17 +838,20 @@ int ima_post_load_data(char *buf, loff_t size,
> * @pcr: pcr to extend the measurement
> * @func_data: func specific data, may be NULL
> * @buf_hash: measure buffer data hash
> + * @digest: buffer digest will be written to
> + * @digest_len: buffer length
> *
> * Based on policy, either the buffer data or buffer data hash is measured
> *
> - * Return: 0 if the buffer has been successfully measured, a negative value
> - * otherwise.
> + * Return: 0 if the buffer has been successfully measured, 1 if the digest
> + * has been written to the passed location but not added to a measurement entry,
> + * a negative value otherwise.
> */
> int process_buffer_measurement(struct user_namespace *mnt_userns,
> struct inode *inode, const void *buf, int size,
> const char *eventname, enum ima_hooks func,
> int pcr, const char *func_data,
> - bool buf_hash)
> + bool buf_hash, u8 *digest, size_t digest_len)
> {
> int ret = 0;
> const char *audit_cause = "ENOMEM";
> @@ -869,7 +872,10 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
> int action = 0;
> u32 secid;
>
> - if (!ima_policy_flag)
> + if (digest && digest_len < digest_hash_len)
> + return -EINVAL;
> +
> + if (!ima_policy_flag && !digest)
> return -ENOENT;
>
> template = ima_template_desc_buf();
> @@ -891,7 +897,7 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
> action = ima_get_action(mnt_userns, inode, current_cred(),
> secid, 0, func, &pcr, &template,
> func_data);
> - if (!(action & IMA_MEASURE))
> + if (!(action & IMA_MEASURE) && !digest)
> return -ENOENT;
> }
>
> @@ -922,6 +928,12 @@ int process_buffer_measurement(struct user_namespace *mnt_userns,
> event_data.buf_len = digest_hash_len;
> }
>
> + if (digest)
> + memcpy(digest, iint.ima_hash->digest, digest_hash_len);
> +
> + if (!ima_policy_flag || (func && !(action & IMA_MEASURE)))
> + return 1;
> +
> ret = ima_alloc_init_template(&event_data, &entry, template);
> if (ret < 0) {
> audit_cause = "alloc_entry";
> @@ -964,7 +976,7 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
>
> process_buffer_measurement(file_mnt_user_ns(f.file), file_inode(f.file),
> buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0,
> - NULL, false);
> + NULL, false, NULL, 0);
> fdput(f);
> }
>
> @@ -975,26 +987,30 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
> * @buf: pointer to buffer data
> * @buf_len: length of buffer data (in bytes)
> * @hash: measure buffer data hash
> + * @digest: buffer digest will be written to
> + * @digest_len: buffer length
> *
> * Measure data critical to the integrity of the kernel into the IMA log
> * and extend the pcr. Examples of critical data could be various data
> * structures, policies, and states stored in kernel memory that can
> * impact the integrity of the system.
> *
> - * Return: 0 if the buffer has been successfully measured, a negative value
> - * otherwise.
> + * Return: 0 if the buffer has been successfully measured, 1 if the digest
> + * has been written to the passed location but not added to a measurement entry,
> + * a negative value otherwise.
> */
> int ima_measure_critical_data(const char *event_label,
> const char *event_name,
> const void *buf, size_t buf_len,
> - bool hash)
> + bool hash, u8 *digest, size_t digest_len)
> {
> if (!event_name || !event_label || !buf || !buf_len)
> return -ENOPARAM;
>
> return process_buffer_measurement(&init_user_ns, NULL, buf, buf_len,
> event_name, CRITICAL_DATA, 0,
> - event_label, hash);
> + event_label, hash, digest,
> + digest_len);
> }
>
> static int __init init_ima(void)
> diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c
> index 979ef6c71f3d..93056c03bf5a 100644
> --- a/security/integrity/ima/ima_queue_keys.c
> +++ b/security/integrity/ima/ima_queue_keys.c
> @@ -165,7 +165,7 @@ void ima_process_queued_keys(void)
> entry->keyring_name,
> KEY_CHECK, 0,
> entry->keyring_name,
> - false);
> + false, NULL, 0);
> list_del(&entry->list);
> ima_free_key_entry(entry);
> }
> diff --git a/security/selinux/ima.c b/security/selinux/ima.c
> index 34d421861bfc..727c4e43219d 100644
> --- a/security/selinux/ima.c
> +++ b/security/selinux/ima.c
> @@ -86,7 +86,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
> }
>
> ima_measure_critical_data("selinux", "selinux-state",
> - state_str, strlen(state_str), false);
> + state_str, strlen(state_str), false,
> + NULL, 0);
>
> kfree(state_str);
>
> @@ -103,7 +104,8 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
> }
>
> ima_measure_critical_data("selinux", "selinux-policy-hash",
> - policy, policy_len, true);
> + policy, policy_len, true,
> + NULL, 0);
>
> vfree(policy);
> }
>
^ permalink raw reply
* Re: [PATCH v3 2/3] ima: Return int in the functions to measure a buffer
From: Lakshmi Ramasubramanian @ 2021-07-06 19:21 UTC (permalink / raw)
To: Roberto Sassu, zohar, paul
Cc: stephen.smalley.work, prsriva02, tusharsu, linux-integrity,
linux-security-module, linux-kernel, selinux
In-Reply-To: <20210705090922.3321178-3-roberto.sassu@huawei.com>
On 7/5/2021 2:09 AM, Roberto Sassu wrote:
> ima_measure_critical_data() and process_buffer_measurement() currently
> don't return a result. A caller wouldn't be able to know whether those
> functions were executed successfully.
>
> This patch modifies the return type from void to int, and returns 0 if the
> buffer has been successfully measured, a negative value otherwise.
>
> Also, this patch does not modify the behavior of existing callers by
> processing the returned value. For those, the return value is ignored.
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> include/linux/ima.h | 15 +++++++-----
> security/integrity/ima/ima.h | 10 ++++----
> security/integrity/ima/ima_main.c | 40 ++++++++++++++++++-------------
> 3 files changed, 37 insertions(+), 28 deletions(-)
Reviewed-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
-lakshmi
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 81e830d01ced..60492263aa64 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -35,10 +35,10 @@ extern void ima_post_path_mknod(struct user_namespace *mnt_userns,
> extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
> extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
> extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
> -extern void ima_measure_critical_data(const char *event_label,
> - const char *event_name,
> - const void *buf, size_t buf_len,
> - bool hash);
> +extern int ima_measure_critical_data(const char *event_label,
> + const char *event_name,
> + const void *buf, size_t buf_len,
> + bool hash);
>
> #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
> extern void ima_appraise_parse_cmdline(void);
> @@ -144,10 +144,13 @@ static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size
>
> static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
>
> -static inline void ima_measure_critical_data(const char *event_label,
> +static inline int ima_measure_critical_data(const char *event_label,
> const char *event_name,
> const void *buf, size_t buf_len,
> - bool hash) {}
> + bool hash)
> +{
> + return -ENOENT;
> +}
>
> #endif /* CONFIG_IMA */
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index f0e448ed1f9f..03db221324c3 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -264,11 +264,11 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
> struct evm_ima_xattr_data *xattr_value,
> int xattr_len, const struct modsig *modsig, int pcr,
> struct ima_template_desc *template_desc);
> -void process_buffer_measurement(struct user_namespace *mnt_userns,
> - struct inode *inode, const void *buf, int size,
> - const char *eventname, enum ima_hooks func,
> - int pcr, const char *func_data,
> - bool buf_hash);
> +int process_buffer_measurement(struct user_namespace *mnt_userns,
> + struct inode *inode, const void *buf, int size,
> + const char *eventname, enum ima_hooks func,
> + int pcr, const char *func_data,
> + bool buf_hash);
> void ima_audit_measurement(struct integrity_iint_cache *iint,
> const unsigned char *filename);
> int ima_alloc_init_template(struct ima_event_data *event_data,
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 8ef1fa357e0c..b512c06d8ee1 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -827,7 +827,7 @@ int ima_post_load_data(char *buf, loff_t size,
> return 0;
> }
>
> -/*
> +/**
> * process_buffer_measurement - Measure the buffer or the buffer data hash
> * @mnt_userns: user namespace of the mount the inode was found from
> * @inode: inode associated with the object being measured (NULL for KEY_CHECK)
> @@ -840,12 +840,15 @@ int ima_post_load_data(char *buf, loff_t size,
> * @buf_hash: measure buffer data hash
> *
> * Based on policy, either the buffer data or buffer data hash is measured
> + *
> + * Return: 0 if the buffer has been successfully measured, a negative value
> + * otherwise.
> */
> -void process_buffer_measurement(struct user_namespace *mnt_userns,
> - struct inode *inode, const void *buf, int size,
> - const char *eventname, enum ima_hooks func,
> - int pcr, const char *func_data,
> - bool buf_hash)
> +int process_buffer_measurement(struct user_namespace *mnt_userns,
> + struct inode *inode, const void *buf, int size,
> + const char *eventname, enum ima_hooks func,
> + int pcr, const char *func_data,
> + bool buf_hash)
> {
> int ret = 0;
> const char *audit_cause = "ENOMEM";
> @@ -867,7 +870,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
> u32 secid;
>
> if (!ima_policy_flag)
> - return;
> + return -ENOENT;
>
> template = ima_template_desc_buf();
> if (!template) {
> @@ -889,7 +892,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
> secid, 0, func, &pcr, &template,
> func_data);
> if (!(action & IMA_MEASURE))
> - return;
> + return -ENOENT;
> }
>
> if (!pcr)
> @@ -937,7 +940,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
> func_measure_str(func),
> audit_cause, ret, 0, ret);
>
> - return;
> + return ret;
> }
>
> /**
> @@ -977,18 +980,21 @@ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size)
> * and extend the pcr. Examples of critical data could be various data
> * structures, policies, and states stored in kernel memory that can
> * impact the integrity of the system.
> + *
> + * Return: 0 if the buffer has been successfully measured, a negative value
> + * otherwise.
> */
> -void ima_measure_critical_data(const char *event_label,
> - const char *event_name,
> - const void *buf, size_t buf_len,
> - bool hash)
> +int ima_measure_critical_data(const char *event_label,
> + const char *event_name,
> + const void *buf, size_t buf_len,
> + bool hash)
> {
> if (!event_name || !event_label || !buf || !buf_len)
> - return;
> + return -ENOPARAM;
>
> - process_buffer_measurement(&init_user_ns, NULL, buf, buf_len, event_name,
> - CRITICAL_DATA, 0, event_label,
> - hash);
> + return process_buffer_measurement(&init_user_ns, NULL, buf, buf_len,
> + event_name, CRITICAL_DATA, 0,
> + event_label, hash);
> }
>
> static int __init init_ima(void)
>
^ permalink raw reply
* [PATCH v1 4/4] landlock_restrict_self.2: Document new syscall
From: Mickaël Salaün @ 2021-07-06 18:22 UTC (permalink / raw)
To: Alejandro Colomar, Michael Kerrisk
Cc: Mickaël Salaün, Jann Horn, Jonathan Corbet, Kees Cook,
Randy Dunlap, Vincent Dagonneau, landlock, linux-kernel,
linux-man, linux-security-module, Mickaël Salaün
In-Reply-To: <20210706182217.32338-1-mic@digikod.net>
From: Mickaël Salaün <mic@linux.microsoft.com>
This is an adaptation of
https://www.kernel.org/doc/html/v5.13/userspace-api/landlock.html
Signed-off-by: Mickaël Salaün <mic@linux.microsoft.com>
Link: https://lore.kernel.org/r/20210706182217.32338-5-mic@digikod.net
---
man2/landlock_restrict_self.2 | 125 ++++++++++++++++++++++++++++++++++
1 file changed, 125 insertions(+)
create mode 100644 man2/landlock_restrict_self.2
diff --git a/man2/landlock_restrict_self.2 b/man2/landlock_restrict_self.2
new file mode 100644
index 000000000000..589fe972487c
--- /dev/null
+++ b/man2/landlock_restrict_self.2
@@ -0,0 +1,125 @@
+.\" Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
+.\" Copyright © 2019-2020 ANSSI
+.\" Copyright © 2021 Microsoft Corporation
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date. The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein. The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.TH LANDLOCK_RESTRICT_SELF 2 2021-06-27 Linux "Linux Programmer's Manual"
+.SH NAME
+landlock_restrict_self \- enforce a Landlock ruleset
+.SH SYNOPSIS
+.nf
+.BR "#include <linux/landlock.h>" " /* Definition of " LANDLOCK_* " constants */"
+.BR "#include <sys/syscall.h>" " /* Definition of " SYS_* " constants */"
+.PP
+.BI "int syscall(SYS_landlock_restrict_self, int " ruleset_fd ,
+.BI " __u32 " flags );
+.SH DESCRIPTION
+Once a Landlock ruleset is populated with the desired rules, the
+.BR landlock_restrict_self (2)
+system call enables enforcing this ruleset on the calling thread. See
+.BR landlock (7)
+for a global overview.
+.PP
+A thread can be restricted with multiple rulesets that are then composed
+together to form the thread's Landlock domain. This can be seen as a stack
+of rulesets but it is implemented in a more efficient way. A domain can
+only be updated in such a way that the constraints of each past and future
+composed rulesets will restrict the thread and its future children for
+their entire life. It is then possible to gradually enforce tailored
+access control policies with multiple independant rulesets coming from
+different sources (e.g., init system configuration, user session policy,
+built-in application policy). However, most applications should only need
+one call to
+.BR landlock_restrict_self (2)
+and they should avoid arbitrary numbers of such calls because of the
+composed rulesets limit. Instead, developers are encouraged to build a
+tailored ruleset thanks to multiple calls to
+.BR landlock_add_rule (2)
+\&.
+.PP
+In order to enforce a ruleset, either the caller must have the
+.BR CAP_SYS_ADMIN
+capability in its user namespace, or the thread must already have the
+.I no_new_privs
+bit set. As for
+.BR seccomp (2)
+, this avoids scenarios where unprivileged processes can affect the
+behavior of privileged children (e.g., because of set-user-ID binaries).
+If that bit was not already set by an ancestor of this thread, the thread
+must make the following call:
+.IP
+.EX
+prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+.EE
+.PP
+.I ruleset_fd
+is a Landlock ruleset file descriptor obtained with
+.BR landlock_create_ruleset (2)
+and fully populated with a set of calls to
+.BR landlock_add_rule (2)
+\&.
+.PP
+.I flags
+must be 0.
+.SH RETURN VALUE
+On success,
+.BR landlock_restrict_self (2)
+returns 0.
+.SH ERRORS
+.BR landlock_restrict_self (2)
+can failed for the following reasons:
+.TP
+.BR EOPNOTSUPP
+Landlock is supported by the kernel but disabled at boot time.
+.TP
+.BR EINVAL
+.I flags
+is not 0.
+.TP
+.BR EBADF
+.I ruleset_fd
+is not a file descriptor for the current thread.
+.TP
+.BR EBADFD
+.I ruleset_fd
+is not a ruleset file descriptor.
+.TP
+.BR EPERM
+.I ruleset_fd
+has no read access to the underlying ruleset, or the calling thread is not
+running with
+.I no_new_privs
+, or it doesn't have the
+.BR CAP_SYS_ADMIN
+in its user namespace.
+.TP
+.BR E2BIG
+The maximum number of composed rulesets is reached for the calling thread.
+This limit is currently 64.
+.SH VERSIONS
+Landlock was added in Linux 5.13.
+.SH SEE ALSO
+.BR landlock (7),
+.BR landlock_create_ruleset (2),
+.BR landlock_add_rule (2)
--
2.32.0
^ permalink raw reply related
* [PATCH v1 3/4] landlock_add_rule.2: Document new syscall
From: Mickaël Salaün @ 2021-07-06 18:22 UTC (permalink / raw)
To: Alejandro Colomar, Michael Kerrisk
Cc: Mickaël Salaün, Jann Horn, Jonathan Corbet, Kees Cook,
Randy Dunlap, Vincent Dagonneau, landlock, linux-kernel,
linux-man, linux-security-module, Mickaël Salaün
In-Reply-To: <20210706182217.32338-1-mic@digikod.net>
From: Mickaël Salaün <mic@linux.microsoft.com>
This is an adaptation of
https://www.kernel.org/doc/html/v5.13/userspace-api/landlock.html
Signed-off-by: Mickaël Salaün <mic@linux.microsoft.com>
Link: https://lore.kernel.org/r/20210706182217.32338-4-mic@digikod.net
---
man2/landlock_add_rule.2 | 139 +++++++++++++++++++++++++++++++++++++++
1 file changed, 139 insertions(+)
create mode 100644 man2/landlock_add_rule.2
diff --git a/man2/landlock_add_rule.2 b/man2/landlock_add_rule.2
new file mode 100644
index 000000000000..66da2c142a03
--- /dev/null
+++ b/man2/landlock_add_rule.2
@@ -0,0 +1,139 @@
+.\" Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
+.\" Copyright © 2019-2020 ANSSI
+.\" Copyright © 2021 Microsoft Corporation
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date. The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein. The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.TH LANDLOCK_ADD_RULE 2 2021-06-27 Linux "Linux Programmer's Manual"
+.SH NAME
+landlock_add_rule \- add a new Landlock rule to a ruleset
+.SH SYNOPSIS
+.nf
+.BR "#include <linux/landlock.h>" " /* Definition of " LANDLOCK_* " constants */"
+.BR "#include <sys/syscall.h>" " /* Definition of " SYS_* " constants */"
+.PP
+.BI "int syscall(SYS_landlock_add_rule, int " ruleset_fd ,
+.BI " enum landlock_rule_type " rule_type ,
+.BI " const void * " rule_attr ", __u32 " flags );
+.SH DESCRIPTION
+A Landlock rule describes an action on an object. An object is currently a
+file hierarchy, and the related filesystem actions are defined with a set
+of access rights. This
+.BR landlock_add_rule (2)
+system call enables adding a new Landlock rule to an existing ruleset
+created with
+.BR landlock_create_ruleset (2)
+\&. See
+.BR landlock (7)
+for a global overview.
+.PP
+.I ruleset_fd
+is a Landlock ruleset file descriptor obtained with
+.BR landlock_create_ruleset (2)
+\&.
+.PP
+.I rule_type
+identifies the structure type pointed to by
+.I rule_attr
+\&. Currently, Linux supports the following
+.I rule_type
+value:
+.TP
+.BR LANDLOCK_RULE_PATH_BENEATH
+This defines the object type as a file hierarchy.
+In this case,
+.I rule_attr
+points to the following structure:
+.IP
+.in +4n
+.EX
+struct landlock_path_beneath_attr {
+ __u64 allowed_access;
+ __s32 parent_fd;
+} __attribute__((packed));
+.EE
+.in
+.IP
+.I allowed_access
+contains a bitmask of allowed filesystem actions for this file hierarchy
+(see
+.BR "Filesystem actions"
+in
+.BR landlock (7)
+).
+.IP
+.I parent_fd
+is an opened file descriptor, preferably with the
+.I O_PATH
+flag, which identifies the parent directory of the file hierarchy or a just
+file.
+.PP
+.I flags
+must be 0.
+.SH RETURN VALUE
+On success,
+.BR landlock_add_rule (2)
+returns 0.
+.SH ERRORS
+.BR landlock_add_rule (2)
+can failed for the following reasons:
+.TP
+.BR EOPNOTSUPP
+Landlock is supported by the kernel but disabled at boot time.
+.TP
+.BR EINVAL
+.I flags
+is not 0, or the rule accesses are inconsistent (i.e.
+.I rule_attr->allowed_access
+is not a subset of the ruleset handled accesses).
+.TP
+.BR ENOMSG
+Empty accesses (i.e.
+.I rule_attr->allowed_access
+is 0).
+.TP
+.BR EBADF
+.I ruleset_fd
+is not a file descriptor for the current thread, or a member of
+.I rule_attr
+is not a file descriptor as expected.
+.TP
+.BR EBADFD
+.I ruleset_fd
+is not a ruleset file descriptor, or a member of
+.I rule_attr
+is not the expected file descriptor type.
+.TP
+.BR EPERM
+.I ruleset_fd
+has no write access to the underlying ruleset.
+.TP
+.BR EFAULT
+.I rule_attr
+was not a valid address.
+.SH VERSIONS
+Landlock was added in Linux 5.13.
+.SH SEE ALSO
+.BR landlock (7),
+.BR landlock_create_ruleset (2),
+.BR landlock_restrict_self (2)
--
2.32.0
^ permalink raw reply related
* [PATCH v1 2/4] landlock_create_ruleset.2: Document new syscall
From: Mickaël Salaün @ 2021-07-06 18:22 UTC (permalink / raw)
To: Alejandro Colomar, Michael Kerrisk
Cc: Mickaël Salaün, Jann Horn, Jonathan Corbet, Kees Cook,
Randy Dunlap, Vincent Dagonneau, landlock, linux-kernel,
linux-man, linux-security-module, Mickaël Salaün
In-Reply-To: <20210706182217.32338-1-mic@digikod.net>
From: Mickaël Salaün <mic@linux.microsoft.com>
This is an adaptation of
https://www.kernel.org/doc/html/v5.13/userspace-api/landlock.html
Signed-off-by: Mickaël Salaün <mic@linux.microsoft.com>
Link: https://lore.kernel.org/r/20210706182217.32338-3-mic@digikod.net
---
man2/landlock_create_ruleset.2 | 134 +++++++++++++++++++++++++++++++++
1 file changed, 134 insertions(+)
create mode 100644 man2/landlock_create_ruleset.2
diff --git a/man2/landlock_create_ruleset.2 b/man2/landlock_create_ruleset.2
new file mode 100644
index 000000000000..5fe0f8fd808e
--- /dev/null
+++ b/man2/landlock_create_ruleset.2
@@ -0,0 +1,134 @@
+.\" Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
+.\" Copyright © 2019-2020 ANSSI
+.\" Copyright © 2021 Microsoft Corporation
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date. The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein. The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.TH LANDLOCK_CREATE_RULESET 2 2021-06-27 Linux "Linux Programmer's Manual"
+.SH NAME
+landlock_create_ruleset \- create a new Landlock ruleset
+.SH SYNOPSIS
+.nf
+.BR "#include <linux/landlock.h>" " /* Definition of " LANDLOCK_* " constants */"
+.BR "#include <sys/syscall.h>" " /* Definition of " SYS_* " constants */"
+.PP
+.BI "int syscall(SYS_landlock_create_ruleset,
+.BI " const struct landlock_ruleset_attr " attr ,
+.BI " size_t " size " , __u32 " flags );
+.SH DESCRIPTION
+A Landlock ruleset identifies a set of rules (i.e. actions on objects).
+This
+.BR landlock_create_ruleset (2)
+system call enables creating a new file descriptor identifying a ruleset.
+This file descriptor can then be used by
+.BR landlock_add_rule (2)
+and
+.BR landlock_restrict_self (2)
+\&. See
+.BR landlock (7)
+for a global overview.
+.PP
+.I attr
+specifies the properties of the new ruleset. It points to the following
+structure:
+.IP
+.in +4n
+.EX
+struct landlock_ruleset_attr {
+ __u64 handled_access_fs;
+};
+.EE
+.in
+.IP
+.I handled_access_fs
+is a bitmask of actions that is handled by this ruleset and should then be
+forbidden if no rule explicitly allow them
+(see
+.BR "Filesystem actions"
+in
+.BR landlock (7)
+).
+This enables simply restricting ambient rights (e.g., global filesystem
+access) and is needed for compatibility reasons.
+.PP
+.I size
+must be specified as
+.I sizeof(struct landlock_ruleset_attr)
+for compatibility reasons.
+.PP
+.I flags
+must be 0 if
+.I attr
+is used. Otherwise,
+.I flags
+can be set to:
+.TP
+.BR LANDLOCK_CREATE_RULESET_VERSION
+If
+.I attr
+is NULL and
+.I size
+is 0, then the returned value is the highest supported Landlock ABI version
+(starting at 1). This version can be used for a best-effort security
+approach, which is encouraged when user space is not pinned to a specific
+kernel version. All features documented in these man pages are available
+with the version 1.
+.SH RETURN VALUE
+On success,
+.BR landlock_create_ruleset (2)
+returns a new Landlock ruleset file descriptor, or a Landlock ABI version
+according to
+.I flags
+\&.
+.SH ERRORS
+.BR landlock_create_ruleset (2)
+can failed for the following reasons:
+.TP
+.BR EOPNOTSUPP
+Landlock is supported by the kernel but disabled at boot time.
+.TP
+.BR EINVAL
+Unknown
+.I flags
+, or unknown access, or too small
+.I size
+\&.
+.TP
+.BR E2BIG
+.I size
+is too big.
+.TP
+.BR EFAULT
+.I attr
+was not a valid address.
+.TP
+.BR ENOMSG
+Empty accesses (i.e.
+.I attr->handled_access_fs
+is 0).
+.SH VERSIONS
+Landlock was added in Linux 5.13.
+.SH SEE ALSO
+.BR landlock (7),
+.BR landlock_add_rule (2),
+.BR landlock_restrict_self (2)
--
2.32.0
^ permalink raw reply related
* [PATCH v1 1/4] landlock.7: Add a new page to introduce Landlock
From: Mickaël Salaün @ 2021-07-06 18:22 UTC (permalink / raw)
To: Alejandro Colomar, Michael Kerrisk
Cc: Mickaël Salaün, Jann Horn, Jonathan Corbet, Kees Cook,
Randy Dunlap, Vincent Dagonneau, landlock, linux-kernel,
linux-man, linux-security-module, Mickaël Salaün
In-Reply-To: <20210706182217.32338-1-mic@digikod.net>
From: Mickaël Salaün <mic@linux.microsoft.com>
From the user point of view, Landlock is a set of system calls enabling
to build and enforce a set of access-control rules. A ruleset can be
created with landlock_create_ruleset(2), populated with
landlock_add_rule(2) and enforced with landlock_restrict_self(2). This
man page gives an overview of the whole mechanism. Details of these
system calls are documented in their respective man pages.
This is an adaptation of
https://www.kernel.org/doc/html/v5.13/userspace-api/landlock.html
Signed-off-by: Mickaël Salaün <mic@linux.microsoft.com>
Link: https://lore.kernel.org/r/20210706182217.32338-2-mic@digikod.net
---
man7/landlock.7 | 354 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 354 insertions(+)
create mode 100644 man7/landlock.7
diff --git a/man7/landlock.7 b/man7/landlock.7
new file mode 100644
index 000000000000..32127d3b2061
--- /dev/null
+++ b/man7/landlock.7
@@ -0,0 +1,354 @@
+.\" Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
+.\" Copyright © 2019-2020 ANSSI
+.\" Copyright © 2021 Microsoft Corporation
+.\"
+.\" %%%LICENSE_START(VERBATIM)
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one.
+.\"
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date. The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein. The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\"
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\" %%%LICENSE_END
+.\"
+.TH LANDLOCK 7 2021-06-27 Linux "Linux Programmer's Manual"
+.SH NAME
+Landlock \- security sandboxing
+.SH DESCRIPTION
+Landlock is a sandboxing mechanism that enables any processes to securely
+restrict themselves and their future children.
+Because Landlock is a stackable LSM, it makes possible to create safe
+security sandboxes as new security layers in addition to the existing
+system-wide access-controls. This kind of sandbox is expected to help
+mitigate the security impact of bugs, and unexpected or malicious behaviors
+in applications.
+.PP
+A Landlock security policy is a set of access rights (e.g., open a file in
+read-only, make a directory, etc.) tied to a file hierarchy. Such policy
+can be configured and enforced by processes for themselves using three
+system calls:
+.IP \(bu 2
+.BR landlock_create_ruleset (2)
+creates a new ruleset;
+.IP \(bu
+.BR landlock_add_rule (2)
+adds a new rule to a ruleset;
+.IP \(bu
+.BR landlock_restrict_self (2)
+enforces a ruleset on the calling thread.
+.PP
+To be able to use these system calls, the running kernel must support
+Landlock and it must be enabled at boot time.
+.\"
+.SS Landlock rules
+A Landlock rule describes an action on an object. An object is currently a
+file hierarchy, and the related filesystem actions are defined with access
+rights (see
+.BR landlock_add_rule (2)
+). A set of rules is aggregated in a ruleset, which can
+then restrict the thread enforcing it, and its future children.
+.\"
+.SS Defining and enforcing a security policy
+We first need to create the ruleset that will contain our rules. For this
+example, the ruleset will contain rules that only allow read actions, but
+write actions will be denied. The ruleset then needs to handle both of
+these kind of actions. See below for the description of filesystem
+actions.
+.PP
+.in +4n
+.EX
+int ruleset_fd;
+struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs =
+ LANDLOCK_ACCESS_FS_EXECUTE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE |
+ LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_READ_DIR |
+ LANDLOCK_ACCESS_FS_REMOVE_DIR |
+ LANDLOCK_ACCESS_FS_REMOVE_FILE |
+ LANDLOCK_ACCESS_FS_MAKE_CHAR |
+ LANDLOCK_ACCESS_FS_MAKE_DIR |
+ LANDLOCK_ACCESS_FS_MAKE_REG |
+ LANDLOCK_ACCESS_FS_MAKE_SOCK |
+ LANDLOCK_ACCESS_FS_MAKE_FIFO |
+ LANDLOCK_ACCESS_FS_MAKE_BLOCK |
+ LANDLOCK_ACCESS_FS_MAKE_SYM,
+};
+
+ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+if (ruleset_fd < 0) {
+ perror("Failed to create a ruleset");
+ return 1;
+}
+.EE
+.in
+.PP
+We can now add a new rule to this ruleset thanks to the returned file
+descriptor referring to this ruleset. The rule will only allow reading the
+file hierarchy
+.I /usr
+\&. Without another rule, write actions would then be denied by the
+ruleset. To add
+.I /usr
+to the ruleset, we open it with the
+.I O_PATH
+flag and fill the
+.I struct landlock_path_beneath_attr
+with this file descriptor.
+.PP
+.in +4n
+.EX
+int err;
+struct landlock_path_beneath_attr path_beneath = {
+ .allowed_access =
+ LANDLOCK_ACCESS_FS_EXECUTE |
+ LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_READ_DIR,
+};
+
+path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC);
+if (path_beneath.parent_fd < 0) {
+ perror("Failed to open file");
+ close(ruleset_fd);
+ return 1;
+}
+err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+ &path_beneath, 0);
+close(path_beneath.parent_fd);
+if (err) {
+ perror("Failed to update ruleset");
+ close(ruleset_fd);
+ return 1;
+}
+.EE
+.in
+.PP
+We now have a ruleset with one rule allowing read access to
+.I /usr
+while denying all other handled accesses for the filesystem. The next step
+is to restrict the current thread from gaining more privileges (e.g.,
+thanks to a set-user-ID binary).
+.PP
+.in +4n
+.EX
+if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+ perror("Failed to restrict privileges");
+ close(ruleset_fd);
+ return 1;
+}
+.EE
+.in
+.PP
+The current thread is now ready to sandbox itself with the ruleset.
+.PP
+.in +4n
+.EX
+if (landlock_restrict_self(ruleset_fd, 0)) {
+ perror("Failed to enforce ruleset");
+ close(ruleset_fd);
+ return 1;
+}
+close(ruleset_fd);
+.EE
+.in
+.PP
+If the
+.BR landlock_restrict_self (2)
+system call succeeds, the current thread is now restricted and this policy
+will be enforced on all its subsequently created children as well. Once a
+thread is landlocked, there is no way to remove its security policy; only
+adding more restrictions is allowed. These threads are now in a new
+Landlock domain, merge of their parent one (if any) with the new ruleset.
+.PP
+Full working code can be found in
+.UR https://git.kernel.org\:/pub\:/scm\:/linux\:/kernel\:/git\:/stable\:/linux.git\:/tree\:/samples\:/landlock\:/sandboxer.c
+.UE
+.\"
+.SS Filesystem actions
+These flags enable to restrict a sandboxed process to a set of actions on
+files and directories. Files or directories opened before the sandboxing
+are not subject to these restrictions. See
+.BR landlock_add_rule (2)
+and
+.BR landlock_create_ruleset (2)
+for more context.
+.PP
+A file can only receive these access rights:
+.TP
+.BR LANDLOCK_ACCESS_FS_EXECUTE
+Execute a file.
+.TP
+.BR LANDLOCK_ACCESS_FS_WRITE_FILE
+Open a file with write access.
+.TP
+.BR LANDLOCK_ACCESS_FS_READ_FILE
+Open a file with read access.
+.PP
+A directory can receive access rights related to files or directories. The
+following access right is applied to the directory itself, and the
+directories beneath it:
+.TP
+.BR LANDLOCK_ACCESS_FS_READ_DIR
+Open a directory or list its content.
+.PP
+However, the following access rights only apply to the content of a
+directory, not the directory itself:
+.TP
+.BR LANDLOCK_ACCESS_FS_REMOVE_DIR
+Remove an empty directory or rename one.
+.TP
+.BR LANDLOCK_ACCESS_FS_REMOVE_FILE
+Unlink (or rename) a file.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_CHAR
+Create (or rename or link) a character device.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_DIR
+Create (or rename) a directory.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_REG
+Create (or rename or link) a regular file.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_SOCK
+Create (or rename or link) a UNIX domain socket.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_FIFO
+Create (or rename or link) a named pipe.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_BLOCK
+Create (or rename or link) a block device.
+.TP
+.BR LANDLOCK_ACCESS_FS_MAKE_SYM
+Create (or rename or link) a symbolic link.
+.\"
+.SS Layers of file path access rights
+Each time a thread enforces a ruleset on itself, it updates its Landlock
+domain with a new layer of policy. Indeed, this complementary policy is
+composed with the potentially other rulesets already restricting this
+thread. A sandboxed thread can then safely add more constraints to itself
+with a new enforced ruleset.
+.PP
+One policy layer grants access to a file path if at least one of its rules
+encountered on the path grants the access. A sandboxed thread can only
+access a file path if all its enforced policy layers grant the access as
+well as all the other system access controls (e.g., filesystem DAC, other
+LSM policies, etc.).
+.\"
+.SS Bind mounts and OverlayFS
+Landlock enables restricting access to file hierarchies, which means that
+these access rights can be propagated with bind mounts (cf.
+.BR mount_namespaces (7)
+) but not with OverlayFS.
+.PP
+A bind mount mirrors a source file hierarchy to a destination. The
+destination hierarchy is then composed of the exact same files, on which
+Landlock rules can be tied, either via the source or the destination path.
+These rules restrict access when they are encountered on a path, which
+means that they can restrict access to multiple file hierarchies at the
+same time, whether these hierarchies are the result of bind mounts or not.
+.PP
+An OverlayFS mount point consists of upper and lower layers. These layers
+are combined in a merge directory, result of the mount point. This merge
+hierarchy may include files from the upper and lower layers, but
+modifications performed on the merge hierarchy only reflects on the upper
+layer. From a Landlock policy point of view, each OverlayFS layers and
+merge hierarchies are standalone and contains their own set of files and
+directories, which is different from bind mounts. A policy restricting an
+OverlayFS layer will not restrict the resulted merged hierarchy, and vice
+versa. Landlock users should then only think about file hierarchies they
+want to allow access to, regardless of the underlying filesystem.
+.\"
+.SS Inheritance
+Every new thread resulting from a
+.BR clone (2)
+inherits Landlock domain restrictions from its parent. This is similar to
+the
+.BR seccomp (2)
+inheritance or any other LSM dealing with task's
+.BR credentials (7)
+\&. For instance, one process's thread may apply Landlock rules to itself,
+but they will not be automatically applied to other sibling threads (unlike
+POSIX thread credential changes, cf.
+.BR nptl (7)
+).
+.PP
+When a thread sandboxes itself, we have the guarantee that the related
+security policy will stay enforced on all this thread's descendants. This
+allows creating standalone and modular security policies per application,
+which will automatically be composed between themselves according to their
+runtime parent policies.
+.\"
+.SS Ptrace restrictions
+A sandboxed process has less privileges than a non-sandboxed process and
+must then be subject to additional restrictions when manipulating another
+process. To be allowed to use
+.BR ptrace (2)
+and related syscalls on a target process, a sandboxed process should have a
+subset of the target process rules, which means the tracee must be in a
+sub-domain of the tracer.
+.SH VERSIONS
+Landlock was added in Linux 5.13.
+.SH NOTES
+Landlock is enabled by CONFIG_SECURITY_LANDLOCK.
+The
+.I lsm=lsm1,...,lsmN
+command line parameter controls the sequence of the initialization of
+Linux Security Modules.
+It must contain the string
+.I landlock
+to enable Landlock.
+If the command line parameter is not specified,
+the initialization falls back to the value of the deprecated
+.I security=
+command line parameter and further to the value of CONFIG_LSM.
+We can check that Landlock is enabled by looking for
+.I
+landlock: Up and running.
+in kernel logs.
+.\"
+.PP
+It is currently not possible to restrict some file-related actions
+accessible through these syscall families:
+.BR chdir (2)
+,
+.BR truncate (2)
+,
+.BR stat (2)
+,
+.BR flock (2)
+,
+.BR chmod (2)
+,
+.BR chown (2)
+,
+.BR setxattr (2)
+,
+.BR utime (2)
+,
+.BR ioctl (2)
+,
+.BR fcntl (2)
+,
+.BR access (2)
+\&.
+Future Landlock evolutions will enable to restrict them.
+.SH SEE ALSO
+.BR landlock_create_ruleset (2),
+.BR landlock_add_rule (2),
+.BR landlock_restrict_self (2)
+.PP
+.UR https://landlock.io\:/
+.UE
--
2.32.0
^ permalink raw reply related
* [PATCH v1 0/4] Add Landlock man pages
From: Mickaël Salaün @ 2021-07-06 18:22 UTC (permalink / raw)
To: Alejandro Colomar, Michael Kerrisk
Cc: Mickaël Salaün, Jann Horn, Jonathan Corbet, Kees Cook,
Randy Dunlap, Vincent Dagonneau, landlock, linux-kernel,
linux-man, linux-security-module, Mickaël Salaün
From: Mickaël Salaün <mic@linux.microsoft.com>
Hi,
These four documents give a global overview of Landlock and explain each
system calls. This is mainly a formatting of the current kernel
documentation with some new additional details.
Regards,
Mickaël Salaün (4):
landlock.7: Add a new page to introduce Landlock
landlock_create_ruleset.2: Document new syscall
landlock_add_rule.2: Document new syscall
landlock_restrict_self.2: Document new syscall
man2/landlock_add_rule.2 | 139 +++++++++++++
man2/landlock_create_ruleset.2 | 134 +++++++++++++
man2/landlock_restrict_self.2 | 125 ++++++++++++
man7/landlock.7 | 354 +++++++++++++++++++++++++++++++++
4 files changed, 752 insertions(+)
create mode 100644 man2/landlock_add_rule.2
create mode 100644 man2/landlock_create_ruleset.2
create mode 100644 man2/landlock_restrict_self.2
create mode 100644 man7/landlock.7
base-commit: 33248cfe50ebb8762208e7ef3264676dad71b016
--
2.32.0
^ permalink raw reply
* Re: [syzbot] general protection fault in legacy_parse_param
From: Paul Moore @ 2021-07-06 12:50 UTC (permalink / raw)
To: Dmitry Vyukov
Cc: Casey Schaufler, syzbot, linux-security-module, Stephen Smalley,
selinux, David Howells, linux-fsdevel, linux-kernel,
syzkaller-bugs, viro
In-Reply-To: <CACT4Y+bj4epytaY4hhEx5GF+Z2xcMnS4AEg=JcrTEnWvXWFuGQ@mail.gmail.com>
On Mon, Jul 5, 2021 at 1:52 AM Dmitry Vyukov <dvyukov@google.com> wrote:
> On Sun, Jul 4, 2021 at 4:14 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Sat, Jul 3, 2021 at 6:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> > > On 7/2/2021 10:51 PM, Dmitry Vyukov wrote:
> > > > On Sat, Jul 3, 2021 at 7:41 AM syzbot
> > > > <syzbot+d1e3b1d92d25abf97943@syzkaller.appspotmail.com> wrote:
> > > >> Hello,
> > > >>
> > > >> syzbot found the following issue on:
> > > >>
> > > >> HEAD commit: 62fb9874 Linux 5.13
> > > >> git tree: upstream
> > > >> console output: https://syzkaller.appspot.com/x/log.txt?x=12ffa118300000
> > > >> kernel config: https://syzkaller.appspot.com/x/.config?x=19404adbea015a58
> > > >> dashboard link: https://syzkaller.appspot.com/bug?extid=d1e3b1d92d25abf97943
> > > >> compiler: Debian clang version 11.0.1-2
> > > >>
> > > >> Unfortunately, I don't have any reproducer for this issue yet.
> > > >>
> > > >> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> > > >> Reported-by: syzbot+d1e3b1d92d25abf97943@syzkaller.appspotmail.com
> > > > +Casey for what looks like a smackfs issue
> > >
> > > This is from the new mount infrastructure introduced by
> > > David Howells in November 2018. It makes sense that there
> > > may be a problem in SELinux as well, as the code was introduced
> > > by the same developer at the same time for the same purpose.
> > >
> > > > The crash was triggered by this test case:
> > > >
> > > > 21:55:33 executing program 1:
> > > > r0 = fsopen(&(0x7f0000000040)='ext3\x00', 0x1)
> > > > fsconfig$FSCONFIG_SET_STRING(r0, 0x1, &(0x7f00000002c0)='smackfsroot',
> > > > &(0x7f0000000300)='default_permissions', 0x0)
> > > >
> > > > And I think the issue is in smack_fs_context_parse_param():
> > > > https://elixir.bootlin.com/linux/latest/source/security/smack/smack_lsm.c#L691
> > > >
> > > > But it seems that selinux_fs_context_parse_param() contains the same issue:
> > > > https://elixir.bootlin.com/linux/latest/source/security/selinux/hooks.c#L2919
> > > > +So selinux maintainers as well.
> > > >
> > > >> general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN
> > > >> KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
> > > >> CPU: 0 PID: 20300 Comm: syz-executor.1 Not tainted 5.13.0-syzkaller #0
> > > >> Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
> > > >> RIP: 0010:memchr+0x2f/0x70 lib/string.c:1054
> > > >> Code: 41 54 53 48 89 d3 41 89 f7 45 31 f6 49 bc 00 00 00 00 00 fc ff df 0f 1f 44 00 00 48 85 db 74 3b 48 89 fd 48 89 f8 48 c1 e8 03 <42> 0f b6 04 20 84 c0 75 0f 48 ff cb 48 8d 7d 01 44 38 7d 00 75 db
> > > >> RSP: 0018:ffffc90001dafd00 EFLAGS: 00010246
> > > >> RAX: 0000000000000000 RBX: 0000000000000013 RCX: dffffc0000000000
> > > >> RDX: 0000000000000013 RSI: 000000000000002c RDI: 0000000000000000
> > > >> RBP: 0000000000000000 R08: ffffffff81e171bf R09: ffffffff81e16f95
> > > >> R10: 0000000000000002 R11: ffff88807e96b880 R12: dffffc0000000000
> > > >> R13: ffff888020894000 R14: 0000000000000000 R15: 000000000000002c
> > > >> FS: 00007fe01ae27700(0000) GS:ffff8880b9a00000(0000) knlGS:0000000000000000
> > > >> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > >> CR2: 00000000005645a8 CR3: 0000000018afc000 CR4: 00000000001506f0
> > > >> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > > >> DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> > > >> Call Trace:
> > > >> legacy_parse_param+0x461/0x7e0 fs/fs_context.c:537
> > > >> vfs_parse_fs_param+0x1e5/0x460 fs/fs_context.c:117
> >
> > It's Sunday morning and perhaps my mind is not yet in a "hey, let's
> > look at VFS kernel code!" mindset, but I'm not convinced the problem
> > is the 'param->string = NULL' assignment in the LSM hooks. In both
> > the case of SELinux and Smack that code ends up returning either a 0
> > (Smack) or a 1 (SELinux) - that's a little odd in it's own way, but I
> > don't believe it is relevant here - either way these return values are
> > not equal to -ENOPARAM so we should end up returning early from
> > vfs_parse_fs_param before it calls down into legacy_parse_param():
> >
> > Taken from https://elixir.bootlin.com/linux/latest/source/fs/fs_context.c#L109 :
> >
> > ret = security_fs_context_parse_param(fc, param);
> > if (ret != -ENOPARAM)
> > /* Param belongs to the LSM or is disallowed by the LSM; so
> > * don't pass to the FS.
> > */
> > return ret;
> >
> > if (fc->ops->parse_param) {
> > ret = fc->ops->parse_param(fc, param);
> > if (ret != -ENOPARAM)
> > return ret;
> > }
>
> Hi Paul,
>
> You are right.
> I almost connected the dots, but not exactly.
> Now that I read more code around, setting "param->string = NULL" in
> smack_fs_context_parse_param() looks correct to me (the fs copies and
> takes ownership of the string).
>
> I don't see how the crash happened...
FWIW, I poked around a bit too and couldn't see anything obvious
either, but I can't pretend to know as much about the VFS layer as the
VFS folks. Hopefully they might have better luck.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Refinanzierung *Heimwerkerdarlehen *Erfinderdarlehen
From: sms @ 2021-07-06 12:05 UTC (permalink / raw)
To: linux-security-module
Guten Tag linux-security-module,
Interessieren Sie sich für ein Darlehen? Wir bieten verschiedene Kreditpakete zu günstigen Zinsen an.
Wir können Ihnen helfen, Ihr Projekt zu finanzieren, Investitionskapital verfügbar. Sie können alles von € 5.000 - € 10.000.000,00 über einen Zeitraum von 1 bis 30 Jahren ausleihen.
Für weitere Details, E-Mail- info@icapitalf.com
Vielen Dank.
linux-security-module@vger.kernel.org
________________________________
*****************************************************************************************************************************************************************************************
重要提示:
本邮件及其附件中可能包含机密或特许信息,仅发给指定收件人。
若误收本邮件,请务必通知发送人并直接删去,不得谈论、使用、打印、复制、披露、分发、变更本邮件所载内容。此等行为产生的后果,达诚基金概不承担任何责任。
*****************************************************************************************************************************************************************************************
^ permalink raw reply
* Re: [PATCH v3 2/2] perf: Refactor permissions check into perf_check_permission()
From: Dmitry Vyukov @ 2021-07-06 6:16 UTC (permalink / raw)
To: Marco Elver
Cc: peterz, tglx, mingo, glider, kasan-dev, linux-kernel, mingo, acme,
mark.rutland, alexander.shishkin, jolsa, namhyung,
linux-perf-users, ebiederm, omosnace, serge,
linux-security-module
In-Reply-To: <20210705084453.2151729-2-elver@google.com>
On Mon, Jul 5, 2021 at 10:45 AM Marco Elver <elver@google.com> wrote:
>
> Refactor the permission check in perf_event_open() into a helper
> perf_check_permission(). This makes the permission check logic more
> readable (because we no longer have a negated disjunction). Add a
> comment mentioning the ptrace check also checks the uid.
>
> No functional change intended.
>
> Signed-off-by: Marco Elver <elver@google.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
> ---
> v3:
> * Introduce this patch to refactor the permissions checking logic to
> make it more readable (reported by Eric W. Biederman).
> ---
> kernel/events/core.c | 58 ++++++++++++++++++++++++--------------------
> 1 file changed, 32 insertions(+), 26 deletions(-)
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index f79ee82e644a..3008b986994b 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -11912,6 +11912,37 @@ __perf_event_ctx_lock_double(struct perf_event *group_leader,
> return gctx;
> }
>
> +static bool
> +perf_check_permission(struct perf_event_attr *attr, struct task_struct *task)
> +{
> + unsigned int ptrace_mode = PTRACE_MODE_READ_REALCREDS;
> + bool is_capable = perfmon_capable();
> +
> + if (attr->sigtrap) {
> + /*
> + * perf_event_attr::sigtrap sends signals to the other task.
> + * Require the current task to also have CAP_KILL.
> + */
> + rcu_read_lock();
> + is_capable &= ns_capable(__task_cred(task)->user_ns, CAP_KILL);
> + rcu_read_unlock();
> +
> + /*
> + * If the required capabilities aren't available, checks for
> + * ptrace permissions: upgrade to ATTACH, since sending signals
> + * can effectively change the target task.
> + */
> + ptrace_mode = PTRACE_MODE_ATTACH_REALCREDS;
> + }
> +
> + /*
> + * Preserve ptrace permission check for backwards compatibility. The
> + * ptrace check also includes checks that the current task and other
> + * task have matching uids, and is therefore not done here explicitly.
> + */
> + return is_capable || ptrace_may_access(task, ptrace_mode);
> +}
> +
> /**
> * sys_perf_event_open - open a performance event, associate it to a task/cpu
> *
> @@ -12152,43 +12183,18 @@ SYSCALL_DEFINE5(perf_event_open,
> }
>
> if (task) {
> - unsigned int ptrace_mode = PTRACE_MODE_READ_REALCREDS;
> - bool is_capable;
> -
> err = down_read_interruptible(&task->signal->exec_update_lock);
> if (err)
> goto err_file;
>
> - is_capable = perfmon_capable();
> - if (attr.sigtrap) {
> - /*
> - * perf_event_attr::sigtrap sends signals to the other
> - * task. Require the current task to also have
> - * CAP_KILL.
> - */
> - rcu_read_lock();
> - is_capable &= ns_capable(__task_cred(task)->user_ns, CAP_KILL);
> - rcu_read_unlock();
> -
> - /*
> - * If the required capabilities aren't available, checks
> - * for ptrace permissions: upgrade to ATTACH, since
> - * sending signals can effectively change the target
> - * task.
> - */
> - ptrace_mode = PTRACE_MODE_ATTACH_REALCREDS;
> - }
> -
> /*
> - * Preserve ptrace permission check for backwards compatibility.
> - *
> * We must hold exec_update_lock across this and any potential
> * perf_install_in_context() call for this new event to
> * serialize against exec() altering our credentials (and the
> * perf_event_exit_task() that could imply).
> */
> err = -EACCES;
> - if (!is_capable && !ptrace_may_access(task, ptrace_mode))
> + if (!perf_check_permission(&attr, task))
> goto err_cred;
> }
>
> --
> 2.32.0.93.g670b81a890-goog
>
^ permalink raw reply
* Re: [PATCH v3 1/2] perf: Fix required permissions if sigtrap is requested
From: Dmitry Vyukov @ 2021-07-06 6:16 UTC (permalink / raw)
To: Marco Elver
Cc: peterz, tglx, mingo, glider, kasan-dev, linux-kernel, mingo, acme,
mark.rutland, alexander.shishkin, jolsa, namhyung,
linux-perf-users, ebiederm, omosnace, serge,
linux-security-module, stable
In-Reply-To: <20210705084453.2151729-1-elver@google.com>
On Mon, Jul 5, 2021 at 10:45 AM Marco Elver <elver@google.com> wrote:
>
> If perf_event_open() is called with another task as target and
> perf_event_attr::sigtrap is set, and the target task's user does not
> match the calling user, also require the CAP_KILL capability or
> PTRACE_MODE_ATTACH permissions.
>
> Otherwise, with the CAP_PERFMON capability alone it would be possible
> for a user to send SIGTRAP signals via perf events to another user's
> tasks. This could potentially result in those tasks being terminated if
> they cannot handle SIGTRAP signals.
>
> Note: The check complements the existing capability check, but is not
> supposed to supersede the ptrace_may_access() check. At a high level we
> now have:
>
> capable of CAP_PERFMON and (CAP_KILL if sigtrap)
> OR
> ptrace_may_access(...) // also checks for same thread-group and uid
>
> Fixes: 97ba62b27867 ("perf: Add support for SIGTRAP on perf events")
> Cc: <stable@vger.kernel.org> # 5.13+
> Reported-by: Dmitry Vyukov <dvyukov@google.com>
> Signed-off-by: Marco Elver <elver@google.com>
Acked-by: Dmitry Vyukov <dvyukov@google.com>
> ---
> v3:
> * Upgrade ptrace mode check to ATTACH if attr.sigtrap, otherwise it's
> possible to change the target task (send signal) even if only read
> ptrace permissions were granted (reported by Eric W. Biederman).
>
> v2: https://lkml.kernel.org/r/20210701083842.580466-1-elver@google.com
> * Drop kill_capable() and just check CAP_KILL (reported by Ondrej Mosnacek).
> * Use ns_capable(__task_cred(task)->user_ns, CAP_KILL) to check for
> capability in target task's ns (reported by Ondrej Mosnacek).
>
> v1: https://lkml.kernel.org/r/20210630093709.3612997-1-elver@google.com
> ---
> kernel/events/core.c | 25 ++++++++++++++++++++++++-
> 1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index fe88d6eea3c2..f79ee82e644a 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -12152,10 +12152,33 @@ SYSCALL_DEFINE5(perf_event_open,
> }
>
> if (task) {
> + unsigned int ptrace_mode = PTRACE_MODE_READ_REALCREDS;
> + bool is_capable;
> +
> err = down_read_interruptible(&task->signal->exec_update_lock);
> if (err)
> goto err_file;
>
> + is_capable = perfmon_capable();
> + if (attr.sigtrap) {
> + /*
> + * perf_event_attr::sigtrap sends signals to the other
> + * task. Require the current task to also have
> + * CAP_KILL.
> + */
> + rcu_read_lock();
> + is_capable &= ns_capable(__task_cred(task)->user_ns, CAP_KILL);
> + rcu_read_unlock();
> +
> + /*
> + * If the required capabilities aren't available, checks
> + * for ptrace permissions: upgrade to ATTACH, since
> + * sending signals can effectively change the target
> + * task.
> + */
> + ptrace_mode = PTRACE_MODE_ATTACH_REALCREDS;
> + }
> +
> /*
> * Preserve ptrace permission check for backwards compatibility.
> *
> @@ -12165,7 +12188,7 @@ SYSCALL_DEFINE5(perf_event_open,
> * perf_event_exit_task() that could imply).
> */
> err = -EACCES;
> - if (!perfmon_capable() && !ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS))
> + if (!is_capable && !ptrace_may_access(task, ptrace_mode))
> goto err_cred;
> }
>
> --
> 2.32.0.93.g670b81a890-goog
>
^ permalink raw reply
* Re: [PATCH v8 3/8] security/brute: Detect a brute force attack
From: Alexander Lobakin @ 2021-07-05 12:52 UTC (permalink / raw)
To: John Wood
Cc: Alexander Lobakin, Kees Cook, Jann Horn, Jonathan Corbet,
James Morris, Serge E. Hallyn, Shuah Khan, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin, Arnd Bergmann,
Andi Kleen, valdis.kletnieks, Greg Kroah-Hartman, Randy Dunlap,
Andrew Morton, linux-doc, linux-kernel, linux-security-module,
linux-kselftest, linux-arch, linux-hardening, kernel-hardening
In-Reply-To: <20210704140108.GA2742@ubuntu>
From: John Wood <john.wood@gmx.com>
Date: Sun, 4 Jul 2021 16:01:08 +0200
> On Sat, Jul 03, 2021 at 12:59:28PM +0200, John Wood wrote:
> > Hi,
> >
> > On Fri, Jul 02, 2021 at 05:08:09PM +0000, Alexander Lobakin wrote:
> > >
> > > On the other hand, it leaves a potentional window for attackers to
> > > perform brute force from xattr-incapable filesystems. So at the end
> > > of the day I think that the current implementation (a strong
> > > rejection of such filesystems) is way more secure than having
> > > a fallback I proposed.
> >
> > I've been thinking more about this: that the Brute LSM depends on xattr
> > support and I don't like this part. I want that brute force attacks can
> > be detected and mitigated on every system (with minimal dependencies).
> > So, now I am working in a solution without this drawback. I have some
> > ideas but I need to work on it.
>
> I have been coding and testing a bit my ideas but:
>
> Trying to track the applications faults info using kernel memory ends up
> in an easy to abuse system (denied of service due to large amount of memor=
> y
> in use) :(
>
> So, I continue with the v8 idea: xattr to track application crashes info.
>
> > > I'm planning to make a patch which will eliminate such weird rootfs
> > > type selection and just always use more feature-rich tmpfs if it's
> > > compiled in. So, as an alternative, you could add it to your series
> > > as a preparatory change and just add a Kconfig dependency on
> > > CONFIG_TMPFS && CONFIG_TMPFS_XATTR to CONFIG_SECURITY_FORK_BRUTE
> > > without messing with any fallbacks at all.
> > > What do you think?
> >
> > Great. But I hope this patch will not be necessary for Brute LSM :)
>
> My words are no longer valid ;)
Ok, so here's the patch that prefers tmpfs for rootfs over ramfs
if it's built-in (which is true for 99% of systems): [0]
For now it hasn't been reviewed by anyone yet, will see. I'm running
my system with this patch for several days already and there were no
issues with rootfs or Brute so far.
[0] https://lore.kernel.org/lkml/20210702233727.21301-1-alobakin@pm.me/
> Thanks,
> John Wood
Thanks,
Al
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox