Re: [PATCH v2 4/6] Audit: Add record for multiple task security contexts

2025-03-13 Thread Paul Moore



On March 12, 2025 7:51:36 PM Paul Moore  wrote:

On Mar  7, 2025 Casey Schaufler  wrote:


...




diff --git a/include/linux/security.h b/include/linux/security.h
index 540894695c4b..79a9bf4a7cdd 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -168,6 +168,7 @@ struct lsm_prop {

extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
extern u32 lsm_active_cnt;
+extern u32 lsm_subjctx_cnt;


I'm not loving this.  More below, but I'd really like to hide some of
this detail inside a LSM API/hook if possible.


Thinking more about this I think we can't go with a LSM_MAX_PROPS, or 
similar determined at build time since we have the ability to toggle LSMs 
at boot.  Need to think on this some more, but the answer is going to have 
to be a variable and not a #define.


The LSM init work I'm doing right now directly impacts this, and I'm in the 
final stages now. Let me see what looks reasonable and I'll get back to you.


--
paul-moore.com








Re: [PATCH v1] audit,module: restore audit logging in load failure case

2025-03-13 Thread Richard Guy Briggs
On 2025-03-07 14:41, Steve Grubb wrote:
> On Thursday, March 6, 2025 4:41:40 PM Eastern Standard Time Richard Guy 
> Briggs wrote:
> > On 2024-10-24 16:41, Paul Moore wrote:
> > > On Oct 23, 2024 Richard Guy Briggs  wrote:
> > > > The move of the module sanity check to earlier skipped the audit
> > > > logging
> > > > call in the case of failure and to a place where the previously used
> > > > context is unavailable.
> > > > 
> > > > Add an audit logging call for the module loading failure case and get
> > > > the module name when possible.
> > > > 
> > > > Link: https://issues.redhat.com/browse/RHEL-52839
> > > > Fixes: 02da2cbab452 ("module: move check_modinfo() early to
> > > > early_mod_check()") Signed-off-by: Richard Guy Briggs 
> > > > ---
> > > > 
> > > >  kernel/module/main.c | 4 +++-
> > > >  1 file changed, 3 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > > > index 49b9bca9de12..1f482532ef66 100644
> > > > --- a/kernel/module/main.c
> > > > +++ b/kernel/module/main.c
> > > > @@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info,
> > > > const char __user *uargs,> > 
> > > >  * failures once the proper module was allocated and
> > > >  * before that.
> > > >  */
> > > > 
> > > > -   if (!module_allocated)
> > > > +   if (!module_allocated) {
> > > > +   audit_log_kern_module(info->name ? info->name : 
> "(unavailable)");
> > > > 
> > > > mod_stat_bump_becoming(info, flags);
> > > > 
> > > > +   }
> > > 
> > > We probably should move the existing audit_log_kern_module() to just
> > > after the elf_validity_cache_copy() call as both info->name and
> > > info->mod->name should be as valid as they are going to get at that
> > > point.  If we do that then we only have two cases we need to worry about,
> > > a failed module_sig_check() or a failed elf_validity_cache_copy(), and
> > > in both cases we can use "(unavailable)" without having to check
> > > info->name first.
> > 
> > Fair enough.
> > 
> > > However, assuming we move the audit_log_kern_module() call up a bit as
> > > described above, I'm not sure there is much value in calling
> > > audit_log_kern_module() with an "(unavailable)" module name in those
> > > early two cases.  We know it's an attempted module load based on the
> > > SYSCALL record, seeing an associated "(unavailable)" KERN_MODULE record
> > > doesn't provide us with any more information than if we had simply
> > > skipped the KERN_MODULE record.
> > 
> > Understood.  I wonder if the absence of the record in the error case
> > will leave us guessing if we lost a record from the event?  We will have
> > the error code from the SYSCALL record but not much more than that, and
> > some of those error codes could just as well be generated after that
> > point too.  This would be a similar situation to the vanishing fields in
> > an existing record, but is likely easier to mitigate than a
> > non-last-field vanishing or shifting around in an existing record.
> > 
> > Steve?  Atilla?  Any comments?
> 
> We should only get the events if we have syscall rules that would result in 
> kernel module loading/unloading events. I suppose that by the time audit 
> loads it's rules, many modules have already loaded. So, I don't think we need 
> to worry about early cases. But when we do get a kernel module load/unload 
> event based on the rules, we need it's name - even in failures. We need to be 
> able to determine what was attempted since this could affect system 
> integrity.

Ok, yes, agreed.  But that information isn't available yet for a number
of error cases.  It hasn't even been looked for yet after
module_sig_check() and can't be reliably found until halfway through
elf_validity_cache_copy().

So, we should provide the record and make a best effort to fill in that
information if we can.  We could try more aggressively to extract it
from the info blob, but I don't know if that is worth the effort because
a number of the steps leading up to it are necessary to check the
validity and set up structures to extract it.

> -Steve
> 
> > > Untested, but this is what I'm talking about:
> > > 
> > > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > > index 0050ef288ab3..eaa10e3c7eca 100644
> > > --- a/include/linux/audit.h
> > > +++ b/include/linux/audit.h
> > > @@ -417,7 +417,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm
> > > *bprm,> 
> > >  extern void __audit_log_capset(const struct cred *new, const struct cred
> > >  *old); extern void __audit_mmap_fd(int fd, int flags);
> > >  extern void __audit_openat2_how(struct open_how *how);
> > > 
> > > -extern void __audit_log_kern_module(char *name);
> > > +extern void __audit_log_kern_module(const char *name);
> > > 
> > >  extern void __audit_fanotify(u32 response, struct
> > >  fanotify_response_info_audit_rule *friar); extern void
> > >  __audit_tk_injoffset(struct timespec64 off

[PATCH v5 0/1] ipe: add errno field to IPE policy load auditing

2025-03-13 Thread Jasjiv Singh
Hello,

When deployment of a new IPE policy fails, there is no audit trail.
The failure is written to stderr, but not to the system log. So,
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.

Previous Postings
-
v4: 
https://lore.kernel.org/linux-security-module/1741385035-22090-2-git-send-email-jasjivsi...@linux.microsoft.com/
v3: 
https://lore.kernel.org/linux-security-module/1740784265-19829-1-git-send-email-jasjivsi...@linux.microsoft.com/
v2: 
https://lore.kernel.org/linux-security-module/1740696377-3986-1-git-send-email-jasjivsi...@linux.microsoft.com/
v1: 
https://lore.kernel.org/linux-security-module/1739569319-22015-1-git-send-email-jasjivsi...@linux.microsoft.com/

Changelog
-

v5:
* changed audit log format from AUDIT_POLICY_LOAD_FAIL_FMT to
  AUDIT_POLICY_LOAD_NULL_FMT.
* added success case in IPE policy errno documentation.
* removed unnecessary errno documentation in new_policy(),
  update_policy(), ipe_new_policy() and ipe_update_policy(). 
* merged success and failed case together in new_policy() for easy
  maintenance.

v4:
* added a seperate errno table to IPE AUDIT_IPE_POLICY_LOAD documentation.
* fixed error code handling that happens when memdup_user_nul is called
  in new_policy() and update_policy().
* added additional errno documentation to new_policy(), update_policy(),
  ipe_new_policy() and ipe_update_policy().
* added ENOKEY and EKEYREJECTED to IPE errno table documentation.

v3:
* used ERR_PTR(rc) directly rather than assigning to struct ipe_policy.
* removed unnecessary var from update_policy().
* removed unnecessary error handling from update_policy().

v2:
* added additional IPE audit log information to commit to show the errno case.
* changed log format from AUDIT_POLICY_LOAD_NULL_FMT to
  AUDIT_POLICY_LOAD_FAIL_FMT.
* removed unnecessary res var from ipe_audit_policy_load().
* handled security fs failure case in new_policy() and update_policy().
* handled insufficent failure case in new_policy() and update_policy().

Jasjiv Singh (1):
  ipe: add errno field to IPE policy load auditing

 Documentation/admin-guide/LSM/ipe.rst | 69 +++
 security/ipe/audit.c  | 19 ++--
 security/ipe/fs.c | 25 ++
 security/ipe/policy.c | 17 ---
 security/ipe/policy_fs.c  | 28 ---
 5 files changed, 113 insertions(+), 45 deletions(-)

-- 
2.34.1




[PATCH v5 1/1] ipe: add errno field to IPE policy load auditing

2025-03-13 Thread Jasjiv Singh
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 
---
 Documentation/admin-guide/LSM/ipe.rst | 69 +++
 security/ipe/audit.c  | 19 ++--
 security/ipe/fs.c | 25 ++
 security/ipe/policy.c | 17 ---
 security/ipe/policy_fs.c  | 28 ---
 5 files changed, 113 insertions(+), 45 deletions(-)

diff --git a/Documentation/admin-guide/LSM/ipe.rst 
b/Documentation/admin-guide/LSM/ipe.rst
index f93a467db628..dc7088451f9d 100644
--- a/Documentation/admin-guide/LSM/ipe.rst
+++ b/Documentation/admin-guide/LSM/ipe.rst
@@ -423,7 +423,7 @@ Field descriptions:
 
 Event Example::
 
-   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
+   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
type=1300 audit(1653425529.927:53): arch=c03e 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)
type=1327 audit(1653425529.927:53): PROCTITLE 
proctitle=707974686F6E3300746573742F6D61696E2E7079002D66002E2E
 
@@ -433,24 +433,55 @@ This record will always be emitted in conjunction with a 
``AUDITSYSCALL`` record
 
 Field descriptions:
 
-+++---+---+
-| Field  | Value Type | Optional? | Description of Value   
   |
-+++===+===+
-| policy_name| string | No| The policy_name
   |
-+++---+---+
-| policy_version | string | No| The policy_version 
   |
-+++---+---+
-| policy_digest  | string | No| The policy hash
   |
-+++---+---+
-| auid   | integer| No| The login user ID  
   |
-+++---+---+
-| ses| integer| No| The login session ID   
   |
-+++---+---+
-| lsm| string | No| The lsm name associated with the 
event|
-+++---+---+
-| res| integer| No

Re: [PATCH v1 1/1] audit: Mark audit_log_vformat() with __printf() attribute

2025-03-13 Thread Andy Shevchenko
On Wed, Mar 12, 2025 at 04:16:36PM -0400, Paul Moore wrote:
> On Wed, Mar 12, 2025 at 4:02 PM Andy Shevchenko
>  wrote:
> >
> > audit_log_vformat() is using printf() type of format, and compiler
> > is not happy about this:
> >
> > kernel/audit.c:1978:9: error: function ‘audit_log_vformat’ might be a 
> > candidate for ‘gnu_printf’ format attribute 
> > [-Werror=suggest-attribute=format]
> > kernel/audit.c:1987:17: error: function ‘audit_log_vformat’ might be a 
> > candidate for ‘gnu_printf’ format attribute 
> > [-Werror=suggest-attribute=format]
> >
> > Fix the compilation errors by adding __printf() attribute.

> It would be good to list the compiler version/flags that triggers this
> error in the patch description

CONFIG_WERROR=y (this is default), gcc (Debian 14.2.0-17) 14.2.0, `make W=1`.

> as I've compiled the audit code quite a bit and haven't seen these errors :)

Good for you, I have 100% reproducibility of this :-)

I'll do a v2 today.

-- 
With Best Regards,
Andy Shevchenko





[PATCH v2 1/1] audit: Mark audit_log_vformat() with __printf() attribute

2025-03-13 Thread Andy Shevchenko
audit_log_vformat() is using printf() type of format, and GCC compiler
(Debian 14.2.0-17) is not happy about this:

kernel/audit.c:1978:9: error: function ‘audit_log_vformat’ might be a candidate 
for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format]
kernel/audit.c:1987:17: error: function ‘audit_log_vformat’ might be a 
candidate for ‘gnu_printf’ format attribute [-Werror=suggest-attribute=format]

Fix the compilation errors (`make W=1` when CONFIG_WERROR=y, which is default)
by adding __printf() attribute.

Signed-off-by: Andy Shevchenko 
---

v2: added necessary technical information to the commit message (Paul)

 kernel/audit.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/audit.c b/kernel/audit.c
index 5f5bf85bcc90..f365e1bbeac6 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1956,8 +1956,8 @@ static inline int audit_expand(struct audit_buffer *ab, 
int extra)
  * will be called a second time.  Currently, we assume that a printk
  * can't format message larger than 1024 bytes, so we don't either.
  */
-static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
- va_list args)
+static __printf(2, 0)
+void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args)
 {
int len, avail;
struct sk_buff *skb;
-- 
2.47.2