Skip to content

Commit 1d887d6

Browse files
jasjivsingh-corpjxwufan
authored andcommitted
ipe: add errno field to IPE policy load auditing
Users of IPE require a way to identify when and why an operation fails, allowing them to both respond to violations of policy and be notified of potentially malicious actions on their systems with respect to IPE. This patch introduces a new error field to the AUDIT_IPE_POLICY_LOAD event to log policy loading failures. Currently, IPE only logs successful policy loads, but not failures. Tracking failures is crucial to detect malicious attempts and ensure a complete audit trail for security events. The new error field will capture the following error codes: * -ENOKEY: Key used to sign the IPE policy not found in the keyring * -ESTALE: Attempting to update an IPE policy with an older version * -EKEYREJECTED: IPE signature verification failed * -ENOENT: Policy was deleted while updating * -EEXIST: Same name policy already deployed * -ERANGE: Policy version number overflow * -EINVAL: Policy version parsing error * -EPERM: Insufficient permission * -ENOMEM: Out of memory (OOM) * -EBADMSG: Policy is invalid Here are some examples of the updated audit record types: AUDIT_IPE_POLICY_LOAD(1422): audit: AUDIT1422 policy_name="Test_Policy" policy_version=0.0.1 policy_digest=sha256:84EFBA8FA71E62AE0A537FAB962F8A2BD1053964C4299DCA 92BFFF4DB82E86D3 auid=1000 ses=3 lsm=ipe res=1 errno=0 The above record shows a new policy has been successfully loaded into the kernel with the policy name, version, and hash with the errno=0. AUDIT_IPE_POLICY_LOAD(1422) with error: audit: AUDIT1422 policy_name=? policy_version=? policy_digest=? auid=1000 ses=3 lsm=ipe res=0 errno=-74 The above record shows a policy load failure due to an invalid policy (-EBADMSG). By adding this error field, we ensure that all policy load attempts, whether successful or failed, are logged, providing a comprehensive audit trail for IPE policy management. Signed-off-by: Jasjiv Singh <jasjivsingh@linux.microsoft.com> Signed-off-by: Fan Wu <wufan@kernel.org>
1 parent 0ff41df commit 1d887d6

File tree

5 files changed

+113
-45
lines changed

5 files changed

+113
-45
lines changed

Documentation/admin-guide/LSM/ipe.rst

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ Field descriptions:
423423

424424
Event Example::
425425

426-
type=1422 audit(1653425529.927:53): policy_name="boot_verified" policy_version=0.0.0 policy_digest=sha256:820EEA5B40CA42B51F68962354BA083122A20BB846F26765076DD8EED7B8F4DB auid=4294967295 ses=4294967295 lsm=ipe res=1
426+
type=1422 audit(1653425529.927:53): policy_name="boot_verified" policy_version=0.0.0 policy_digest=sha256:820EEA5B40CA42B51F68962354BA083122A20BB846F26765076DD8EED7B8F4DB auid=4294967295 ses=4294967295 lsm=ipe res=1 errno=0
427427
type=1300 audit(1653425529.927:53): arch=c000003e syscall=1 success=yes exit=2567 a0=3 a1=5596fcae1fb0 a2=a07 a3=2 items=0 ppid=184 pid=229 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=4294967295 comm="python3" exe="/usr/bin/python3.10" key=(null)
428428
type=1327 audit(1653425529.927:53): PROCTITLE proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2E
429429

@@ -433,24 +433,55 @@ This record will always be emitted in conjunction with a ``AUDITSYSCALL`` record
433433

434434
Field descriptions:
435435

436-
+----------------+------------+-----------+---------------------------------------------------+
437-
| Field | Value Type | Optional? | Description of Value |
438-
+================+============+===========+===================================================+
439-
| policy_name | string | No | The policy_name |
440-
+----------------+------------+-----------+---------------------------------------------------+
441-
| policy_version | string | No | The policy_version |
442-
+----------------+------------+-----------+---------------------------------------------------+
443-
| policy_digest | string | No | The policy hash |
444-
+----------------+------------+-----------+---------------------------------------------------+
445-
| auid | integer | No | The login user ID |
446-
+----------------+------------+-----------+---------------------------------------------------+
447-
| ses | integer | No | The login session ID |
448-
+----------------+------------+-----------+---------------------------------------------------+
449-
| lsm | string | No | The lsm name associated with the event |
450-
+----------------+------------+-----------+---------------------------------------------------+
451-
| res | integer | No | The result of the audited operation(success/fail) |
452-
+----------------+------------+-----------+---------------------------------------------------+
453-
436+
+----------------+------------+-----------+-------------------------------------------------------------+
437+
| Field | Value Type | Optional? | Description of Value |
438+
+================+============+===========+=============================================================+
439+
| policy_name | string | Yes | The policy_name |
440+
+----------------+------------+-----------+-------------------------------------------------------------+
441+
| policy_version | string | Yes | The policy_version |
442+
+----------------+------------+-----------+-------------------------------------------------------------+
443+
| policy_digest | string | Yes | The policy hash |
444+
+----------------+------------+-----------+-------------------------------------------------------------+
445+
| auid | integer | No | The login user ID |
446+
+----------------+------------+-----------+-------------------------------------------------------------+
447+
| ses | integer | No | The login session ID |
448+
+----------------+------------+-----------+-------------------------------------------------------------+
449+
| lsm | string | No | The lsm name associated with the event |
450+
+----------------+------------+-----------+-------------------------------------------------------------+
451+
| res | integer | No | The result of the audited operation(success/fail) |
452+
+----------------+------------+-----------+-------------------------------------------------------------+
453+
| errno | integer | No | Error code from policy loading operations (see table below) |
454+
+----------------+------------+-----------+-------------------------------------------------------------+
455+
456+
Policy error codes (errno):
457+
458+
The following table lists the error codes that may appear in the errno field while loading or updating the policy:
459+
460+
+----------------+--------------------------------------------------------+
461+
| Error Code | Description |
462+
+================+========================================================+
463+
| 0 | Success |
464+
+----------------+--------------------------------------------------------+
465+
| -EPERM | Insufficient permission |
466+
+----------------+--------------------------------------------------------+
467+
| -EEXIST | Same name policy already deployed |
468+
+----------------+--------------------------------------------------------+
469+
| -EBADMSG | Policy is invalid |
470+
+----------------+--------------------------------------------------------+
471+
| -ENOMEM | Out of memory (OOM) |
472+
+----------------+--------------------------------------------------------+
473+
| -ERANGE | Policy version number overflow |
474+
+----------------+--------------------------------------------------------+
475+
| -EINVAL | Policy version parsing error |
476+
+----------------+--------------------------------------------------------+
477+
| -ENOKEY | Key used to sign the IPE policy not found in keyring |
478+
+----------------+--------------------------------------------------------+
479+
| -EKEYREJECTED | Policy signature verification failed |
480+
+----------------+--------------------------------------------------------+
481+
| -ESTALE | Attempting to update an IPE policy with older version |
482+
+----------------+--------------------------------------------------------+
483+
| -ENOENT | Policy was deleted while updating |
484+
+----------------+--------------------------------------------------------+
454485

455486
1404 AUDIT_MAC_STATUS
456487
^^^^^^^^^^^^^^^^^^^^^

security/ipe/audit.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#define AUDIT_POLICY_LOAD_FMT "policy_name=\"%s\" policy_version=%hu.%hu.%hu "\
2323
"policy_digest=" IPE_AUDIT_HASH_ALG ":"
24+
#define AUDIT_POLICY_LOAD_NULL_FMT "policy_name=? policy_version=? "\
25+
"policy_digest=?"
2426
#define AUDIT_OLD_ACTIVE_POLICY_FMT "old_active_pol_name=\"%s\" "\
2527
"old_active_pol_version=%hu.%hu.%hu "\
2628
"old_policy_digest=" IPE_AUDIT_HASH_ALG ":"
@@ -248,22 +250,29 @@ void ipe_audit_policy_activation(const struct ipe_policy *const op,
248250
}
249251

250252
/**
251-
* ipe_audit_policy_load() - Audit a policy being loaded into the kernel.
252-
* @p: Supplies a pointer to the policy to audit.
253+
* ipe_audit_policy_load() - Audit a policy loading event.
254+
* @p: Supplies a pointer to the policy to audit or an error pointer.
253255
*/
254256
void ipe_audit_policy_load(const struct ipe_policy *const p)
255257
{
256258
struct audit_buffer *ab;
259+
int err = 0;
257260

258261
ab = audit_log_start(audit_context(), GFP_KERNEL,
259262
AUDIT_IPE_POLICY_LOAD);
260263
if (!ab)
261264
return;
262265

263-
audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p);
264-
audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=1",
266+
if (!IS_ERR(p)) {
267+
audit_policy(ab, AUDIT_POLICY_LOAD_FMT, p);
268+
} else {
269+
audit_log_format(ab, AUDIT_POLICY_LOAD_NULL_FMT);
270+
err = PTR_ERR(p);
271+
}
272+
273+
audit_log_format(ab, " auid=%u ses=%u lsm=ipe res=%d errno=%d",
265274
from_kuid(&init_user_ns, audit_get_loginuid(current)),
266-
audit_get_sessionid(current));
275+
audit_get_sessionid(current), !err, err);
267276

268277
audit_log_end(ab);
269278
}

security/ipe/fs.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ static ssize_t getenforce(struct file *f, char __user *data,
133133
* * %-ERANGE - Policy version number overflow
134134
* * %-EINVAL - Policy version parsing error
135135
* * %-EEXIST - Same name policy already deployed
136+
* * %-ENOKEY - Policy signing key not found
137+
* * %-EKEYREJECTED - Policy signature verification failed
136138
*/
137139
static ssize_t new_policy(struct file *f, const char __user *data,
138140
size_t len, loff_t *offset)
@@ -141,12 +143,17 @@ static ssize_t new_policy(struct file *f, const char __user *data,
141143
char *copy = NULL;
142144
int rc = 0;
143145

144-
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
145-
return -EPERM;
146+
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) {
147+
rc = -EPERM;
148+
goto out;
149+
}
146150

147151
copy = memdup_user_nul(data, len);
148-
if (IS_ERR(copy))
149-
return PTR_ERR(copy);
152+
if (IS_ERR(copy)) {
153+
rc = PTR_ERR(copy);
154+
copy = NULL;
155+
goto out;
156+
}
150157

151158
p = ipe_new_policy(NULL, 0, copy, len);
152159
if (IS_ERR(p)) {
@@ -158,12 +165,14 @@ static ssize_t new_policy(struct file *f, const char __user *data,
158165
if (rc)
159166
goto out;
160167

161-
ipe_audit_policy_load(p);
162-
163168
out:
164-
if (rc < 0)
165-
ipe_free_policy(p);
166169
kfree(copy);
170+
if (rc < 0) {
171+
ipe_free_policy(p);
172+
ipe_audit_policy_load(ERR_PTR(rc));
173+
} else {
174+
ipe_audit_policy_load(p);
175+
}
167176
return (rc < 0) ? rc : len;
168177
}
169178

security/ipe/policy.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@ static int set_pkcs7_data(void *ctx, const void *data, size_t len,
8484
* ipe_new_policy.
8585
*
8686
* Context: Requires root->i_rwsem to be held.
87-
* Return: %0 on success. If an error occurs, the function will return
88-
* the -errno.
87+
* Return:
88+
* * %0 - Success
89+
* * %-ENOENT - Policy was deleted while updating
90+
* * %-EINVAL - Policy name mismatch
91+
* * %-ESTALE - Policy version too old
8992
*/
9093
int ipe_update_policy(struct inode *root, const char *text, size_t textlen,
9194
const char *pkcs7, size_t pkcs7len)
@@ -146,10 +149,12 @@ int ipe_update_policy(struct inode *root, const char *text, size_t textlen,
146149
*
147150
* Return:
148151
* * a pointer to the ipe_policy structure - Success
149-
* * %-EBADMSG - Policy is invalid
150-
* * %-ENOMEM - Out of memory (OOM)
151-
* * %-ERANGE - Policy version number overflow
152-
* * %-EINVAL - Policy version parsing error
152+
* * %-EBADMSG - Policy is invalid
153+
* * %-ENOMEM - Out of memory (OOM)
154+
* * %-ERANGE - Policy version number overflow
155+
* * %-EINVAL - Policy version parsing error
156+
* * %-ENOKEY - Policy signing key not found
157+
* * %-EKEYREJECTED - Policy signature verification failed
153158
*/
154159
struct ipe_policy *ipe_new_policy(const char *text, size_t textlen,
155160
const char *pkcs7, size_t pkcs7len)

security/ipe/policy_fs.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "policy.h"
1313
#include "eval.h"
1414
#include "fs.h"
15+
#include "audit.h"
1516

1617
#define MAX_VERSION_SIZE ARRAY_SIZE("65535.65535.65535")
1718

@@ -286,8 +287,13 @@ static ssize_t getactive(struct file *f, char __user *data,
286287
* On success this updates the policy represented by $name,
287288
* in-place.
288289
*
289-
* Return: Length of buffer written on success. If an error occurs,
290-
* the function will return the -errno.
290+
* Return:
291+
* * Length of buffer written - Success
292+
* * %-EPERM - Insufficient permission
293+
* * %-ENOMEM - Out of memory (OOM)
294+
* * %-ENOENT - Policy was deleted while updating
295+
* * %-EINVAL - Policy name mismatch
296+
* * %-ESTALE - Policy version too old
291297
*/
292298
static ssize_t update_policy(struct file *f, const char __user *data,
293299
size_t len, loff_t *offset)
@@ -296,21 +302,29 @@ static ssize_t update_policy(struct file *f, const char __user *data,
296302
char *copy = NULL;
297303
int rc = 0;
298304

299-
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
300-
return -EPERM;
305+
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) {
306+
rc = -EPERM;
307+
goto out;
308+
}
301309

302310
copy = memdup_user(data, len);
303-
if (IS_ERR(copy))
304-
return PTR_ERR(copy);
311+
if (IS_ERR(copy)) {
312+
rc = PTR_ERR(copy);
313+
copy = NULL;
314+
goto out;
315+
}
305316

306317
root = d_inode(f->f_path.dentry->d_parent);
307318
inode_lock(root);
308319
rc = ipe_update_policy(root, NULL, 0, copy, len);
309320
inode_unlock(root);
310321

322+
out:
311323
kfree(copy);
312-
if (rc)
324+
if (rc) {
325+
ipe_audit_policy_load(ERR_PTR(rc));
313326
return rc;
327+
}
314328

315329
return len;
316330
}

0 commit comments

Comments
 (0)