ntp: Audit NTP parameters adjustment

Emit an audit record every time selected NTP parameters are modified
from userspace (via adjtimex(2) or clock_adjtime(2)). These parameters
may be used to indirectly change system clock, and thus their
modifications should be audited.

Such events will now generate records of type AUDIT_TIME_ADJNTPVAL
containing the following fields:
  - op -- which value was adjusted:
    - offset -- corresponding to the time_offset variable
    - freq   -- corresponding to the time_freq variable
    - status -- corresponding to the time_status variable
    - adjust -- corresponding to the time_adjust variable
    - tick   -- corresponding to the tick_usec variable
    - tai    -- corresponding to the timekeeping's TAI offset
  - old -- the old value
  - new -- the new value

Example records:

type=TIME_ADJNTPVAL msg=audit(1530616044.507:7): op=status old=64 new=8256
type=TIME_ADJNTPVAL msg=audit(1530616044.511:11): op=freq old=0 new=49180377088000

The records of this type will be associated with the corresponding
syscall records.

An overview of parameter changes that can be done via do_adjtimex()
(based on information from Miroslav Lichvar) and whether they are
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%
                 (AUDITED)
    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)

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Reviewed-by: Richard Guy Briggs <rgb@redhat.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Ondrej Mosnacek 2019-04-10 11:14:20 +02:00 committed by Paul Moore
parent 2d87a0674b
commit 7e8eda734d
6 changed files with 112 additions and 5 deletions

View File

@ -86,6 +86,29 @@ struct audit_field {
u32 op; u32 op;
}; };
enum audit_ntp_type {
AUDIT_NTP_OFFSET,
AUDIT_NTP_FREQ,
AUDIT_NTP_STATUS,
AUDIT_NTP_TAI,
AUDIT_NTP_TICK,
AUDIT_NTP_ADJUST,
AUDIT_NTP_NVALS /* count */
};
#ifdef CONFIG_AUDITSYSCALL
struct audit_ntp_val {
long long oldval, newval;
};
struct audit_ntp_data {
struct audit_ntp_val vals[AUDIT_NTP_NVALS];
};
#else
struct audit_ntp_data {};
#endif
extern int is_audit_feature_set(int which); extern int is_audit_feature_set(int which);
extern int __init audit_register_class(int class, unsigned *list); extern int __init audit_register_class(int class, unsigned *list);
@ -366,6 +389,7 @@ extern void __audit_mmap_fd(int fd, int flags);
extern void __audit_log_kern_module(char *name); extern void __audit_log_kern_module(char *name);
extern void __audit_fanotify(unsigned int response); extern void __audit_fanotify(unsigned int response);
extern void __audit_tk_injoffset(struct timespec64 offset); extern void __audit_tk_injoffset(struct timespec64 offset);
extern void __audit_ntp_log(const struct audit_ntp_data *ad);
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{ {
@ -478,6 +502,29 @@ static inline void audit_tk_injoffset(struct timespec64 offset)
__audit_tk_injoffset(offset); __audit_tk_injoffset(offset);
} }
static inline void audit_ntp_init(struct audit_ntp_data *ad)
{
memset(ad, 0, sizeof(*ad));
}
static inline void audit_ntp_set_old(struct audit_ntp_data *ad,
enum audit_ntp_type type, long long val)
{
ad->vals[type].oldval = val;
}
static inline void audit_ntp_set_new(struct audit_ntp_data *ad,
enum audit_ntp_type type, long long val)
{
ad->vals[type].newval = val;
}
static inline void audit_ntp_log(const struct audit_ntp_data *ad)
{
if (!audit_dummy_context())
__audit_ntp_log(ad);
}
extern int audit_n_rules; extern int audit_n_rules;
extern int audit_signals; extern int audit_signals;
#else /* CONFIG_AUDITSYSCALL */ #else /* CONFIG_AUDITSYSCALL */
@ -594,6 +641,20 @@ static inline void audit_fanotify(unsigned int response)
static inline void audit_tk_injoffset(struct timespec64 offset) static inline void audit_tk_injoffset(struct timespec64 offset)
{ } { }
static inline void audit_ntp_init(struct audit_ntp_data *ad)
{ }
static inline void audit_ntp_set_old(struct audit_ntp_data *ad,
enum audit_ntp_type type, long long val)
{ }
static inline void audit_ntp_set_new(struct audit_ntp_data *ad,
enum audit_ntp_type type, long long val)
{ }
static inline void audit_ntp_log(const struct audit_ntp_data *ad)
{ }
static inline void audit_ptrace(struct task_struct *t) static inline void audit_ptrace(struct task_struct *t)
{ } { }
#define audit_n_rules 0 #define audit_n_rules 0

View File

@ -115,6 +115,7 @@
#define AUDIT_KERN_MODULE 1330 /* Kernel Module events */ #define AUDIT_KERN_MODULE 1330 /* Kernel Module events */
#define AUDIT_FANOTIFY 1331 /* Fanotify access decision */ #define AUDIT_FANOTIFY 1331 /* Fanotify access decision */
#define AUDIT_TIME_INJOFFSET 1332 /* Timekeeping offset injected */ #define AUDIT_TIME_INJOFFSET 1332 /* Timekeeping offset injected */
#define AUDIT_TIME_ADJNTPVAL 1333 /* NTP value adjustment */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */

View File

@ -2519,6 +2519,28 @@ void __audit_tk_injoffset(struct timespec64 offset)
(long long)offset.tv_sec, offset.tv_nsec); (long long)offset.tv_sec, offset.tv_nsec);
} }
static void audit_log_ntp_val(const struct audit_ntp_data *ad,
const char *op, enum audit_ntp_type type)
{
const struct audit_ntp_val *val = &ad->vals[type];
if (val->newval == val->oldval)
return;
audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJNTPVAL,
"op=%s old=%lli new=%lli", op, val->oldval, val->newval);
}
void __audit_ntp_log(const struct audit_ntp_data *ad)
{
audit_log_ntp_val(ad, "offset", AUDIT_NTP_OFFSET);
audit_log_ntp_val(ad, "freq", AUDIT_NTP_FREQ);
audit_log_ntp_val(ad, "status", AUDIT_NTP_STATUS);
audit_log_ntp_val(ad, "tai", AUDIT_NTP_TAI);
audit_log_ntp_val(ad, "tick", AUDIT_NTP_TICK);
audit_log_ntp_val(ad, "adjust", AUDIT_NTP_ADJUST);
}
static void audit_log_task(struct audit_buffer *ab) static void audit_log_task(struct audit_buffer *ab)
{ {
kuid_t auid, uid; kuid_t auid, uid;

View File

@ -17,6 +17,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/audit.h>
#include "ntp_internal.h" #include "ntp_internal.h"
#include "timekeeping_internal.h" #include "timekeeping_internal.h"
@ -709,7 +710,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
* kernel time-keeping variables. used by xntpd. * kernel time-keeping variables. used by xntpd.
*/ */
int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
s32 *time_tai) s32 *time_tai, struct audit_ntp_data *ad)
{ {
int result; int result;
@ -720,14 +721,29 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
/* adjtime() is independent from ntp_adjtime() */ /* adjtime() is independent from ntp_adjtime() */
time_adjust = txc->offset; time_adjust = txc->offset;
ntp_update_frequency(); ntp_update_frequency();
audit_ntp_set_old(ad, AUDIT_NTP_ADJUST, save_adjust);
audit_ntp_set_new(ad, AUDIT_NTP_ADJUST, time_adjust);
} }
txc->offset = save_adjust; txc->offset = save_adjust;
} else { } else {
/* If there are input parameters, then process them: */ /* If there are input parameters, then process them: */
if (txc->modes) if (txc->modes) {
audit_ntp_set_old(ad, AUDIT_NTP_OFFSET, time_offset);
audit_ntp_set_old(ad, AUDIT_NTP_FREQ, time_freq);
audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status);
audit_ntp_set_old(ad, AUDIT_NTP_TAI, *time_tai);
audit_ntp_set_old(ad, AUDIT_NTP_TICK, tick_usec);
process_adjtimex_modes(txc, time_tai); process_adjtimex_modes(txc, time_tai);
audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset);
audit_ntp_set_new(ad, AUDIT_NTP_FREQ, time_freq);
audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status);
audit_ntp_set_new(ad, AUDIT_NTP_TAI, *time_tai);
audit_ntp_set_new(ad, AUDIT_NTP_TICK, tick_usec);
}
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
NTP_SCALE_SHIFT); NTP_SCALE_SHIFT);
if (!(time_status & STA_NANO)) if (!(time_status & STA_NANO))

View File

@ -8,6 +8,8 @@ extern void ntp_clear(void);
extern u64 ntp_tick_length(void); extern u64 ntp_tick_length(void);
extern ktime_t ntp_get_next_leap(void); extern ktime_t ntp_get_next_leap(void);
extern int second_overflow(time64_t secs); extern int second_overflow(time64_t secs);
extern int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, s32 *time_tai); extern int __do_adjtimex(struct __kernel_timex *txc,
const struct timespec64 *ts,
s32 *time_tai, struct audit_ntp_data *ad);
extern void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts); extern void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts);
#endif /* _LINUX_NTP_INTERNAL_H */ #endif /* _LINUX_NTP_INTERNAL_H */

View File

@ -2307,6 +2307,7 @@ static int timekeeping_validate_timex(const struct __kernel_timex *txc)
int do_adjtimex(struct __kernel_timex *txc) int do_adjtimex(struct __kernel_timex *txc)
{ {
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
struct audit_ntp_data ad;
unsigned long flags; unsigned long flags;
struct timespec64 ts; struct timespec64 ts;
s32 orig_tai, tai; s32 orig_tai, tai;
@ -2330,13 +2331,15 @@ int do_adjtimex(struct __kernel_timex *txc)
audit_tk_injoffset(delta); audit_tk_injoffset(delta);
} }
audit_ntp_init(&ad);
ktime_get_real_ts64(&ts); ktime_get_real_ts64(&ts);
raw_spin_lock_irqsave(&timekeeper_lock, flags); raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq); write_seqcount_begin(&tk_core.seq);
orig_tai = tai = tk->tai_offset; orig_tai = tai = tk->tai_offset;
ret = __do_adjtimex(txc, &ts, &tai); ret = __do_adjtimex(txc, &ts, &tai, &ad);
if (tai != orig_tai) { if (tai != orig_tai) {
__timekeeping_set_tai_offset(tk, tai); __timekeeping_set_tai_offset(tk, tai);
@ -2347,6 +2350,8 @@ int do_adjtimex(struct __kernel_timex *txc)
write_seqcount_end(&tk_core.seq); write_seqcount_end(&tk_core.seq);
raw_spin_unlock_irqrestore(&timekeeper_lock, flags); raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
audit_ntp_log(&ad);
/* Update the multiplier immediately if frequency was set directly */ /* Update the multiplier immediately if frequency was set directly */
if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK)) if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK))
timekeeping_advance(TK_ADV_FREQ); timekeeping_advance(TK_ADV_FREQ);