[PATCH ghak10 v5 2/2] timekeeping/ntp: Audit clock/NTP params adjustments

John Stultz john.stultz at linaro.org
Fri Aug 24 20:20:41 UTC 2018


On Fri, Aug 24, 2018 at 12:47 PM, Richard Guy Briggs <rgb at redhat.com> wrote:
> On 2018-08-24 14:00, Ondrej Mosnacek wrote:
>> This patch adds logging of all attempts to either inject an offset into
>> the clock (producing an AUDIT_TIME_INJOFFSET record) or adjust an NTP
>> parameter (producing an AUDIT_TIME_ADJNTPVAL record).
>
> I thought I saw it suggested earlier in one of the replies to a previous
> revision of the patchset to separate the two types of records with their
> calling circumstances.  The inj-offset bits could stand alone in their
> own patch leaving all the rest in its own patch.  The record numbers and
> examples are easier to offer when given together, but they aren't as
> clear they are indepnendent records and callers.  That way, each patch
> stands on its own.  (more below)
>
>> For reference, running the following commands:
>>
>>     auditctl -D
>>     auditctl -a exit,always -F arch=b64 -S adjtimex
>>     chronyd -q
>>
>> produces audit records like this:
>>
>> type=TIME_ADJNTPVAL msg=audit(1530616044.507:5): op=adjust old=0 new=0
>> type=SYSCALL msg=audit(1530616044.507:5): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78c00 a1=0 a2=4 a3=7f754ae28c0a items=0 ppid=626 pid=629 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.507:5): proctitle=6368726F6E7964002D71
>> type=SYSCALL msg=audit(1530616044.507:6): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78c00 a1=1 a2=1 a3=7f754ae28c0a items=0 ppid=626 pid=629 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.507:6): proctitle=6368726F6E7964002D71
>> type=TIME_INJOFFSET msg=audit(1530616044.507:7): sec=0 nsec=0
>> type=TIME_ADJNTPVAL msg=audit(1530616044.507:7): op=status old=64 new=8256
>> type=SYSCALL msg=audit(1530616044.507:7): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78c00 a1=1 a2=1 a3=7f754ae28c0a items=0 ppid=626 pid=629 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.507:7): proctitle=6368726F6E7964002D71
>> type=TIME_ADJNTPVAL msg=audit(1530616044.507:8): op=status old=8256 new=8257
>> type=TIME_ADJNTPVAL msg=audit(1530616044.507:8): op=offset old=0 new=0
>> type=TIME_ADJNTPVAL msg=audit(1530616044.507:8): op=freq old=0 new=0
>> type=SYSCALL msg=audit(1530616044.507:8): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78ab0 a1=0 a2=55e129c850c0 a3=7f754ae28c0a items=0 ppid=626 pid=629 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.507:8): proctitle=6368726F6E7964002D71
>> type=TIME_ADJNTPVAL msg=audit(1530616044.507:9): op=status old=8257 new=64
>> type=SYSCALL msg=audit(1530616044.507:9): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78ab0 a1=0 a2=55e129c850c0 a3=7f754ae28c0a items=0 ppid=626 pid=629 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.507:9): proctitle=6368726F6E7964002D71
>> type=SYSCALL msg=audit(1530616044.507:10): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78a70 a1=0 a2=55e129c850c0 a3=7f754ae28c0a items=0 ppid=626 pid=629 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.507:10): proctitle=6368726F6E7964002D71
>> type=TIME_ADJNTPVAL msg=audit(1530616044.511:11): op=freq old=0 new=49180377088000
>> type=TIME_ADJNTPVAL msg=audit(1530616044.511:11): op=tick old=10000 new=10000
>> type=SYSCALL msg=audit(1530616044.511:11): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78ad0 a1=0 a2=2710 a3=f42f82a800000 items=0 ppid=626 pid=629 auid=0 uid=385 gid=382 euid=385 suid=385 fsuid=385 egid=382 sgid=382 fsgid=382 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.511:11): proctitle=6368726F6E7964002D71
>> type=TIME_ADJNTPVAL msg=audit(1530616044.521:12): op=status old=64 new=64
>> type=SYSCALL msg=audit(1530616044.521:12): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78b40 a1=1 a2=40 a3=f91f6ef84fbab items=0 ppid=626 pid=629 auid=0 uid=385 gid=382 euid=385 suid=385 fsuid=385 egid=382 sgid=382 fsgid=382 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616044.521:12): proctitle=6368726F6E7964002D71
>> type=TIME_INJOFFSET msg=audit(1530616049.652:13): sec=-16 nsec=124887145
>> type=TIME_ADJNTPVAL msg=audit(1530616049.652:13): op=status old=64 new=8256
>> type=SYSCALL msg=audit(1530616049.652:13): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78270 a1=1 a2=fffffffffffffff0 a3=137b828205ca12 items=0 ppid=626 pid=629 auid=0 uid=385 gid=382 euid=385 suid=385 fsuid=385 egid=382 sgid=382 fsgid=382 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616049.652:13): proctitle=6368726F6E7964002D71
>> type=TIME_ADJNTPVAL msg=audit(1530616033.783:14): op=freq old=49180377088000 new=49180377088000
>> type=TIME_ADJNTPVAL msg=audit(1530616033.783:14): op=tick old=10000 new=10000
>> type=SYSCALL msg=audit(1530616033.783:14): arch=c000003e syscall=159 success=yes exit=5 a0=7fff57e78bc0 a1=0 a2=2710 a3=0 items=0 ppid=626 pid=629 auid=0 uid=385 gid=382 euid=385 suid=385 fsuid=385 egid=382 sgid=382 fsgid=382 tty=(none) ses=1 comm="chronyd" exe="/usr/sbin/chronyd" subj=system_u:system_r:kernel_t:s0 key=(null)
>> type=PROCTITLE msg=audit(1530616033.783:14): proctitle=6368726F6E7964002D71
>>
>> The chronyd command that produced the above records executed the
>> following adjtimex(2) syscalls (as per strace output):
>>
>> adjtimex({modes=ADJ_OFFSET|0x8000, offset=0, freq=0, maxerror=16000000, esterror=16000000, status=STA_UNSYNC, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=507215}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_MAXERROR, offset=0, freq=0, maxerror=0, esterror=16000000, status=STA_UNSYNC, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=507438}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_SETOFFSET|ADJ_NANO, offset=0, freq=0, maxerror=16000000, esterror=16000000, status=STA_UNSYNC|STA_NANO, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=507604737}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_OFFSET|ADJ_STATUS, offset=0, freq=0, maxerror=16000000, esterror=16000000, status=STA_PLL|STA_UNSYNC|STA_NANO, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=507698330}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_STATUS, offset=0, freq=0, maxerror=16000000, esterror=16000000, status=STA_UNSYNC, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=507792}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=0, offset=0, freq=0, maxerror=16000000, esterror=16000000, status=STA_UNSYNC, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=508000}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_FREQUENCY|ADJ_TICK, offset=0, freq=750433, maxerror=16000000, esterror=16000000, status=STA_UNSYNC, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=512146}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_MAXERROR|ADJ_ESTERROR|ADJ_STATUS, offset=0, freq=750433, maxerror=16000000, esterror=16000000, status=STA_UNSYNC, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616044, tv_usec=522506}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_SETOFFSET|ADJ_NANO, offset=0, freq=750433, maxerror=16000000, esterror=16000000, status=STA_UNSYNC|STA_NANO, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616033, tv_usec=778717675}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>> adjtimex({modes=ADJ_FREQUENCY|ADJ_TICK, offset=0, freq=750433, maxerror=16000000, esterror=16000000, status=STA_UNSYNC|STA_NANO, constant=2, precision=1, tolerance=32768000, time={tv_sec=1530616033, tv_usec=784644657}, tick=10000, ppsfreq=0, jitter=0, shift=0, stabil=0, jitcnt=0, calcnt=0, errcnt=0, stbcnt=0, tai=0}) = 5 (TIME_ERROR)
>>
>> (The struct timex fields above are from *after* the syscall was
>> executed, so they contain the current (new) values as set from the
>> kernel, except of the 'modes' field, which contains the original value
>> sent by the caller.)
>>
>> The changes to the time_maxerror, time_esterror, and time_constant
>> variables are not logged, as these are not important for security.
>>
>> Note that the records are emitted even when the actual value does not
>> change (i.e. when there is an explicit attempt to change a value, but
>> the new value equals the old one).
>>
>> An overview of changes that can be done via adjtimex(2) (based on
>> information from Miroslav Lichvar) and whether they are audited:
>>   timekeeping_inject_offset() -- injects offset directly into system
>>                                  time (AUDITED)
>>   __timekeeping_set_tai_offset() -- sets the offset from the
>>                                     International Atomic Time
>>                                     (AUDITED)
>>   NTP variables:
>>     time_offset -- can adjust the clock by up to 0.5 seconds per call
>>                    and also speed it up or slow down by up to about
>>                    0.05% (43 seconds per day) (AUDITED)
>>     time_freq -- can speed up or slow down by up to about 0.05%
>>     time_status -- can insert/delete leap seconds and it also enables/
>>                    disables synchronization of the hardware real-time
>>                    clock (AUDITED)
>>     time_maxerror, time_esterror -- change error estimates used to
>>                                     inform userspace applications
>>                                     (NOT AUDITED)
>>     time_constant -- controls the speed of the clock adjustments that
>>                      are made when time_offset is set (NOT AUDITED)
>>     time_adjust -- can temporarily speed up or slow down the clock by up
>>                    to 0.05% (AUDITED)
>>     tick_usec -- a more extreme version of time_freq; can speed up or
>>                  slow down the clock by up to 10% (AUDITED)
>>
>> Cc: Miroslav Lichvar <mlichvar at redhat.com>
>> Signed-off-by: Ondrej Mosnacek <omosnace at redhat.com>
>> ---
>>  kernel/time/ntp.c         | 38 ++++++++++++++++++++++++++++++--------
>>  kernel/time/timekeeping.c |  3 +++
>>  2 files changed, 33 insertions(+), 8 deletions(-)
>>
>> diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
>> index a09ded765f6c..f96c6d326aae 100644
>> --- a/kernel/time/ntp.c
>> +++ b/kernel/time/ntp.c
>> @@ -18,6 +18,7 @@
>>  #include <linux/module.h>
>>  #include <linux/rtc.h>
>>  #include <linux/math64.h>
>> +#include <linux/audit.h>
>>
>>  #include "ntp_internal.h"
>>  #include "timekeeping_internal.h"
>> @@ -294,6 +295,8 @@ static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
>>
>>  static void ntp_update_offset(long offset)
>>  {
>> +     s64 old_offset = time_offset;
>> +     s64 old_freq = time_freq;
>>       s64 freq_adj;
>>       s64 offset64;
>>       long secs;
>> @@ -342,6 +345,9 @@ static void ntp_update_offset(long offset)
>>       time_freq   = max(freq_adj, -MAXFREQ_SCALED);
>>
>>       time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
>> +
>> +     audit_ntp_adjust("offset", old_offset, time_offset);
>> +     audit_ntp_adjust("freq", old_freq, time_freq);
>>  }
>>
>>  /**
>> @@ -669,21 +675,31 @@ static inline void process_adjtimex_modes(struct timex *txc,
>>                                               struct timespec64 *ts,
>>                                               s32 *time_tai)
>>  {
>> -     if (txc->modes & ADJ_STATUS)
>> -             process_adj_status(txc, ts);
>> +     if (txc->modes & (ADJ_STATUS | ADJ_NANO | ADJ_MICRO)) {
>> +             int old_status = time_status;
>> +
>> +             if (txc->modes & ADJ_STATUS)
>> +                     process_adj_status(txc, ts);
>>
>> -     if (txc->modes & ADJ_NANO)
>> -             time_status |= STA_NANO;
>> +             if (txc->modes & ADJ_NANO)
>> +                     time_status |= STA_NANO;
>>
>> -     if (txc->modes & ADJ_MICRO)
>> -             time_status &= ~STA_NANO;
>> +             if (txc->modes & ADJ_MICRO)
>> +                     time_status &= ~STA_NANO;
>> +
>> +             audit_ntp_adjust("status", old_status, time_status);
>> +     }
>>
>>       if (txc->modes & ADJ_FREQUENCY) {
>> +             s64 old_freq = time_freq;
>> +
>>               time_freq = txc->freq * PPM_SCALE;
>>               time_freq = min(time_freq, MAXFREQ_SCALED);
>>               time_freq = max(time_freq, -MAXFREQ_SCALED);
>>               /* update pps_freq */
>>               pps_set_freq(time_freq);
>> +
>> +             audit_ntp_adjust("freq", old_freq, time_freq);
>>       }
>>
>>       if (txc->modes & ADJ_MAXERROR)
>> @@ -700,14 +716,18 @@ static inline void process_adjtimex_modes(struct timex *txc,
>>               time_constant = max(time_constant, 0l);
>>       }
>>
>> -     if (txc->modes & ADJ_TAI && txc->constant > 0)
>> +     if (txc->modes & ADJ_TAI && txc->constant > 0) {
>> +             audit_ntp_adjust("tai", *time_tai, txc->constant);
>>               *time_tai = txc->constant;
>> +     }
>
> It appears this time_tai use of "constant" is different than
> time_constant, the former not mentioned by Miroslav Lichvar.  What is it
> and is it important to log for security?  It sounds like it is
> important.

>From the adjtimex man page:
       ADJ_TAI (since Linux 2.6.26)
              Set TAI (Atomic International Time) offset from buf->constant.

thanks
-john




More information about the Linux-audit mailing list