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:
parent
2d87a0674b
commit
7e8eda734d
@ -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
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
@ -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))
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user