// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2020 - 2024 Microsoft Corporation . All rights reserved .
*/
#include <linux/errno.h>
#include <linux/verification.h>
#include "ipe.h"
#include "eval.h"
#include "fs.h"
#include "policy.h"
#include "policy_parser.h"
#include "audit.h"
/* lock for synchronizing writers across ipe policy */
DEFINE_MUTEX(ipe_policy_lock);
/**
* ver_to_u64 ( ) - Convert an internal ipe_policy_version to a u64 .
* @ p : Policy to extract the version from .
*
* Bits ( LSB is index 0 ) :
* [ 48 , 32 ] - > Major
* [ 32 , 16 ] - > Minor
* [ 16 , 0 ] - > Revision
*
* Return : u64 version of the embedded version structure .
*/
static inline u64 ver_to_u64(const struct ipe_policy *const p)
{
u64 r;
r = (((u64)p->parsed->version.major) << 32 )
| (((u64)p->parsed->version.minor) << 16 )
| ((u64)(p->parsed->version.rev));
return r;
}
/**
* ipe_free_policy ( ) - Deallocate a given IPE policy .
* @ p : Supplies the policy to free .
*
* Safe to call on IS_ERR / NULL .
*/
void ipe_free_policy(struct ipe_policy *p)
{
if (IS_ERR_OR_NULL(p))
return ;
ipe_del_policyfs_node(p);
ipe_free_parsed_policy(p->parsed);
/*
* p - > text is allocated only when p - > pkcs7 is not NULL
* otherwise it points to the plaintext data inside the pkcs7
*/
if (!p->pkcs7)
kfree(p->text);
kfree(p->pkcs7);
kfree(p);
}
static int set_pkcs7_data(void *ctx, const void *data, size_t len,
size_t asn1hdrlen __always_unused)
{
struct ipe_policy *p = ctx;
p->text = (const char *)data;
p->textlen = len;
return 0 ;
}
/**
* ipe_update_policy ( ) - parse a new policy and replace old with it .
* @ root : Supplies a pointer to the securityfs inode saved the policy .
* @ text : Supplies a pointer to the plain text policy .
* @ textlen : Supplies the length of @ text .
* @ pkcs7 : Supplies a pointer to a buffer containing a pkcs7 message .
* @ pkcs7len : Supplies the length of @ pkcs7len .
*
* @ text / @ textlen is mutually exclusive with @ pkcs7 / @ pkcs7len - see
* ipe_new_policy .
*
* Context : Requires root - > i_rwsem to be held .
* Return :
* * % 0 - Success
* * % - ENOENT - Policy was deleted while updating
* * % - EINVAL - Policy name mismatch
* * % - ESTALE - Policy version too old
*/
int ipe_update_policy(struct inode *root, const char *text, size_t textlen,
const char *pkcs7, size_t pkcs7len)
{
struct ipe_policy *old, *ap, *new = NULL;
int rc = 0 ;
old = (struct ipe_policy *)root->i_private;
if (!old)
return -ENOENT;
new = ipe_new_policy(text, textlen, pkcs7, pkcs7len);
if (IS_ERR(new ))
return PTR_ERR(new );
if (strcmp(new ->parsed->name, old->parsed->name)) {
rc = -EINVAL;
goto err;
}
if (ver_to_u64(old) >= ver_to_u64(new )) {
rc = -ESTALE;
goto err;
}
root->i_private = new ;
swap(new ->policyfs, old->policyfs);
ipe_audit_policy_load(new );
mutex_lock(&ipe_policy_lock);
ap = rcu_dereference_protected(ipe_active_policy,
lockdep_is_held(&ipe_policy_lock));
if (old == ap) {
rcu_assign_pointer(ipe_active_policy, new );
mutex_unlock(&ipe_policy_lock);
ipe_audit_policy_activation(old, new );
} else {
mutex_unlock(&ipe_policy_lock);
}
synchronize_rcu();
ipe_free_policy(old);
return 0 ;
err:
ipe_free_policy(new );
return rc;
}
/**
* ipe_new_policy ( ) - Allocate and parse an ipe_policy structure .
*
* @ text : Supplies a pointer to the plain - text policy to parse .
* @ textlen : Supplies the length of @ text .
* @ pkcs7 : Supplies a pointer to a pkcs7 - signed IPE policy .
* @ pkcs7len : Supplies the length of @ pkcs7 .
*
* @ text / @ textlen Should be NULL / 0 if @ pkcs7 / @ pkcs7len is set .
*
* Return :
* * a pointer to the ipe_policy structure - Success
* * % - EBADMSG - Policy is invalid
* * % - ENOMEM - Out of memory ( OOM )
* * % - ERANGE - Policy version number overflow
* * % - EINVAL - Policy version parsing error
* * % - ENOKEY - Policy signing key not found
* * % - EKEYREJECTED - Policy signature verification failed
*/
struct ipe_policy *ipe_new_policy(const char *text, size_t textlen,
const char *pkcs7, size_t pkcs7len)
{
struct ipe_policy *new = NULL;
int rc = 0 ;
new = kzalloc(sizeof (*new ), GFP_KERNEL);
if (!new )
return ERR_PTR(-ENOMEM);
if (!text) {
new ->pkcs7len = pkcs7len;
new ->pkcs7 = kmemdup(pkcs7, pkcs7len, GFP_KERNEL);
if (!new ->pkcs7) {
rc = -ENOMEM;
goto err;
}
rc = verify_pkcs7_signature(NULL, 0 , new ->pkcs7, pkcs7len,
#ifdef CONFIG_IPE_POLICY_SIG_SECONDARY_KEYRING
VERIFY_USE_SECONDARY_KEYRING,
#else
NULL,
#endif
VERIFYING_UNSPECIFIED_SIGNATURE,
set_pkcs7_data, new );
#ifdef CONFIG_IPE_POLICY_SIG_PLATFORM_KEYRING
if (rc == -ENOKEY || rc == -EKEYREJECTED)
rc = verify_pkcs7_signature(NULL, 0 , new ->pkcs7, pkcs7len,
VERIFY_USE_PLATFORM_KEYRING,
VERIFYING_UNSPECIFIED_SIGNATURE,
set_pkcs7_data, new );
#endif
if (rc)
goto err;
} else {
new ->textlen = textlen;
new ->text = kstrdup(text, GFP_KERNEL);
if (!new ->text) {
rc = -ENOMEM;
goto err;
}
}
rc = ipe_parse_policy(new );
if (rc)
goto err;
return new ;
err:
ipe_free_policy(new );
return ERR_PTR(rc);
}
/**
* ipe_set_active_pol ( ) - Make @ p the active policy .
* @ p : Supplies a pointer to the policy to make active .
*
* Context : Requires root - > i_rwsem , which i_private has the policy , to be held .
* Return :
* * % 0 - Success
* * % - EINVAL - New active policy version is invalid
*/
int ipe_set_active_pol(const struct ipe_policy *p)
{
struct ipe_policy *ap = NULL;
mutex_lock(&ipe_policy_lock);
ap = rcu_dereference_protected(ipe_active_policy,
lockdep_is_held(&ipe_policy_lock));
if (ap == p) {
mutex_unlock(&ipe_policy_lock);
return 0 ;
}
if (ap && ver_to_u64(ap) > ver_to_u64(p)) {
mutex_unlock(&ipe_policy_lock);
return -EINVAL;
}
rcu_assign_pointer(ipe_active_policy, p);
ipe_audit_policy_activation(ap, p);
mutex_unlock(&ipe_policy_lock);
return 0 ;
}
Messung V0.5 in Prozent C=97 H=89 G=93
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland