[RFC PATCH ghak10 v2 2/4] audit: Add the audit_adjtime() function

Ondrej Mosnacek omosnace at redhat.com
Wed Jun 27 07:59:16 UTC 2018


ut 19. 6. 2018 o 17:04 Richard Guy Briggs <rgb at redhat.com> napísal(a):
>
> On 2018-06-19 15:58, Ondrej Mosnacek wrote:
> > This patch adds a new function that shall be used to log any
> > modification of the system's clock (via the adjtimex() syscall).
> >
> > The function logs an audit record of type AUDIT_TIME_ADJUSTED with the
> > following fields:
> > * txmodes  (the 'modes' field of struct timex; this is the only
> >   mandatory field)
> > * txsec, txusec (the 'tv_sec' and 'tv_usec' fields of the 'time' field
> >   of struct timex (respectively))
> > * txoffset (the 'offset' field of struct timex)
> > * txfreq   (the 'freq' field of struct timex)
> > * txmaxerr (the 'maxerror' field of struct timex)
> > * txesterr (the 'esterror' field of struct timex)
> > * txstatus (the 'status' field of struct timex)
> > * txconst  (the 'constant' field of struct timex)
> > * txtick   (the 'tick' field of struct timex)
>
> I see below that you conditionally log these fields if the flag is
> present.  There has been concern of fields coming and going
> (disappearing) so this could cause problems for parsers looking for
> specific fields that aren't present.  The first version of the patch
> listed them all, which may be overkill.  As has been suggested, limiting
> it to security-affecting fields would be a first step.

I assumed that it was normal for records to have some fields that are
optional (i.e. it is known and documented that they may be missing).
But I understand that it is quite inconvenient to handle such fields
and the desire to have all fields always there, even if with some
special 'empty' values...

> Another possibility would be to list one changed field per record.  This
> could work if multiple flags are infrequent in one call.  A format I'd
> suggest might be txfield=mode old=<value> new=<value>.  (Note only the
> single flag value rather than all modes flags.)  There would be more
> overhead if there was more than one field present in a call, but would
> address the disappearing fields issue.

Indeed this would be nicer, although more verbose... Also, detecting
old and new values would require a bit more intrusive code changes,
but it should be doable.

>
> > These fields allow to reconstruct what exactly was changed by the
> > adjtimex syscall and to what value(s). Note that the values reported are
> > taken directly from the structure as received from userspace. The
> > syscall handling code may do some clamping of the values internally
> > before actually changing the kernel variables. Also, the fact that this
> > record has been logged does not necessarily mean that some variable was
> > changed (it may have been set to the same value as the old value).
>
> If the value is the same, that may still be relevant for reporting that
> someone tried to set/change it.
>
> > Quick overview of the 'struct timex' semantics:
> >   The 'modes' field is a bitmask specifying which time variables (if
> >   any) should be adjusted. The other fields (of those listed above)
> >   contain the values of the respective variables that should be set. If
> >   the corresponding bit is not set in the 'modes' field, then a field's
> >   value is not significant (it may be some garbage value passed from
> >   userspace).
> >
> >   Note that after processing the input values from userspace, the
> >   handler writes (all) the current (new) internal values into the struct
> >   and hands it back to userspace. These values are not logged.
> >
> >   Also note that 'txusec' may actually mean nanoseconds, not
> >   microseconds, depending on whether ADJ_NSEC is set in 'modes'.
> >
> > Possible improvements:
> > * move the conditional for logging/not logging into audit_adjtime()
> >   - (see also next patch in series)
> >   - may not be desirable due to reasons above
> >   - we should probably either do both this and above or neither
> > * log also the old values + the actual values that get set
> >   - this would be rather difficult to do, probably not worth it
> >
> > Signed-off-by: Ondrej Mosnacek <omosnace at redhat.com>
> > ---
> >  include/linux/audit.h | 11 +++++++++++
> >  kernel/auditsc.c      | 38 ++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 49 insertions(+)
> >
> > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > index 69c78477590b..26e9db46293c 100644
> > --- a/include/linux/audit.h
> > +++ b/include/linux/audit.h
> > @@ -26,6 +26,7 @@
> >  #include <linux/sched.h>
> >  #include <linux/ptrace.h>
> >  #include <uapi/linux/audit.h>
> > +#include <uapi/linux/timex.h>
> >
> >  #define AUDIT_INO_UNSET ((unsigned long)-1)
> >  #define AUDIT_DEV_UNSET ((dev_t)-1)
> > @@ -353,6 +354,7 @@ 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_log_kern_module(char *name);
> >  extern void __audit_fanotify(unsigned int response);
> > +extern void __audit_adjtime(const struct timex *txc);
> >
> >  static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
> >  {
> > @@ -455,6 +457,12 @@ static inline void audit_fanotify(unsigned int response)
> >               __audit_fanotify(response);
> >  }
> >
> > +static inline void audit_adjtime(const struct timex *txc)
> > +{
> > +     if (!audit_dummy_context())
> > +             __audit_adjtime(txc);
> > +}
> > +
> >  extern int audit_n_rules;
> >  extern int audit_signals;
> >  #else /* CONFIG_AUDITSYSCALL */
> > @@ -581,6 +589,9 @@ static inline void audit_log_kern_module(char *name)
> >  static inline void audit_fanotify(unsigned int response)
> >  { }
> >
> > +static inline void audit_adjtime(const struct timex *txc)
> > +{ }
> > +
> >  static inline void audit_ptrace(struct task_struct *t)
> >  { }
> >  #define audit_n_rules 0
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index ceb1c4596c51..9a1f3fcc377a 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2422,6 +2422,44 @@ void __audit_fanotify(unsigned int response)
> >               AUDIT_FANOTIFY, "resp=%u", response);
> >  }
> >
> > +void __audit_adjtime(const struct timex *txc)
> > +{
> > +     struct audit_buffer *ab;
> > +
> > +     ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJUSTED);
> > +     if (unlikely(!ab))
> > +             return;
> > +
> > +     audit_log_format(ab, "txmodes=%u", txc->modes);
> > +
> > +     if (txc->modes & ADJ_SETOFFSET)
> > +             audit_log_format(ab, " txsec=%li txusec=%li",
> > +                     (long)txc->time.tv_sec, (long)txc->time.tv_usec);
> > +
> > +     if (txc->modes & ADJ_OFFSET)
> > +             audit_log_format(ab, " txoffset=%li", txc->offset);
> > +
> > +     if (txc->modes & ADJ_FREQUENCY)
> > +             audit_log_format(ab, " txfreq=%li", txc->freq);
> > +
> > +     if (txc->modes & ADJ_MAXERROR)
> > +             audit_log_format(ab, " txmaxerr=%li", txc->maxerror);
> > +
> > +     if (txc->modes & ADJ_ESTERROR)
> > +             audit_log_format(ab, " txesterr=%li", txc->esterror);
> > +
> > +     if (txc->modes & ADJ_STATUS)
> > +             audit_log_format(ab, " txstatus=%li", txc->status);
> > +
> > +     if (txc->modes & (ADJ_TIMECONST | ADJ_TAI))
> > +             audit_log_format(ab, " txconst=%li", txc->constant);
> > +
> > +     if (txc->modes & ADJ_TICK)
> > +             audit_log_format(ab, " txtick=%li", txc->tick);
> > +
> > +     audit_log_end(ab);
> > +}
> > +
> >  static void audit_log_task(struct audit_buffer *ab)
> >  {
> >       kuid_t auid, uid;
> > --
> > 2.17.1
> >
>
> - RGB
>
> --
> Richard Guy Briggs <rgb at redhat.com>
> Sr. S/W Engineer, Kernel Security, Base Operating Systems
> Remote, Ottawa, Red Hat Canada
> IRC: rgb, SunRaycer
> Voice: +1.647.777.2635, Internal: (81) 32635



--
Ondrej Mosnacek <omosnace at redhat dot com>
Associate Software Engineer, Security Technologies
Red Hat, Inc.




More information about the Linux-audit mailing list