diff options
author | Ondrej Mosnacek <omosnace@redhat.com> | 2019-04-10 05:14:20 -0400 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2019-04-15 18:14:01 -0400 |
commit | 7e8eda734d30de81d06a949c9bf9853c445ede4e (patch) | |
tree | d16d77f902e5e7bc24ce1afcb0589544d5e5e602 | |
parent | 2d87a0674bd60d855e4008e2d84f5b23d7cb9b7d (diff) |
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>
-rw-r--r-- | include/linux/audit.h | 61 | ||||
-rw-r--r-- | include/uapi/linux/audit.h | 1 | ||||
-rw-r--r-- | kernel/auditsc.c | 22 | ||||
-rw-r--r-- | kernel/time/ntp.c | 22 | ||||
-rw-r--r-- | kernel/time/ntp_internal.h | 4 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 7 |
6 files changed, 112 insertions, 5 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h index 2c62c0468888..43a23e28ba23 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -86,6 +86,29 @@ struct audit_field { | |||
86 | u32 op; | 86 | u32 op; |
87 | }; | 87 | }; |
88 | 88 | ||
89 | enum audit_ntp_type { | ||
90 | AUDIT_NTP_OFFSET, | ||
91 | AUDIT_NTP_FREQ, | ||
92 | AUDIT_NTP_STATUS, | ||
93 | AUDIT_NTP_TAI, | ||
94 | AUDIT_NTP_TICK, | ||
95 | AUDIT_NTP_ADJUST, | ||
96 | |||
97 | AUDIT_NTP_NVALS /* count */ | ||
98 | }; | ||
99 | |||
100 | #ifdef CONFIG_AUDITSYSCALL | ||
101 | struct audit_ntp_val { | ||
102 | long long oldval, newval; | ||
103 | }; | ||
104 | |||
105 | struct audit_ntp_data { | ||
106 | struct audit_ntp_val vals[AUDIT_NTP_NVALS]; | ||
107 | }; | ||
108 | #else | ||
109 | struct audit_ntp_data {}; | ||
110 | #endif | ||
111 | |||
89 | extern int is_audit_feature_set(int which); | 112 | extern int is_audit_feature_set(int which); |
90 | 113 | ||
91 | extern int __init audit_register_class(int class, unsigned *list); | 114 | extern int __init audit_register_class(int class, unsigned *list); |
@@ -366,6 +389,7 @@ extern void __audit_mmap_fd(int fd, int flags); | |||
366 | extern void __audit_log_kern_module(char *name); | 389 | extern void __audit_log_kern_module(char *name); |
367 | extern void __audit_fanotify(unsigned int response); | 390 | extern void __audit_fanotify(unsigned int response); |
368 | extern void __audit_tk_injoffset(struct timespec64 offset); | 391 | extern void __audit_tk_injoffset(struct timespec64 offset); |
392 | extern void __audit_ntp_log(const struct audit_ntp_data *ad); | ||
369 | 393 | ||
370 | static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) | 394 | static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) |
371 | { | 395 | { |
@@ -478,6 +502,29 @@ static inline void audit_tk_injoffset(struct timespec64 offset) | |||
478 | __audit_tk_injoffset(offset); | 502 | __audit_tk_injoffset(offset); |
479 | } | 503 | } |
480 | 504 | ||
505 | static inline void audit_ntp_init(struct audit_ntp_data *ad) | ||
506 | { | ||
507 | memset(ad, 0, sizeof(*ad)); | ||
508 | } | ||
509 | |||
510 | static inline void audit_ntp_set_old(struct audit_ntp_data *ad, | ||
511 | enum audit_ntp_type type, long long val) | ||
512 | { | ||
513 | ad->vals[type].oldval = val; | ||
514 | } | ||
515 | |||
516 | static inline void audit_ntp_set_new(struct audit_ntp_data *ad, | ||
517 | enum audit_ntp_type type, long long val) | ||
518 | { | ||
519 | ad->vals[type].newval = val; | ||
520 | } | ||
521 | |||
522 | static inline void audit_ntp_log(const struct audit_ntp_data *ad) | ||
523 | { | ||
524 | if (!audit_dummy_context()) | ||
525 | __audit_ntp_log(ad); | ||
526 | } | ||
527 | |||
481 | extern int audit_n_rules; | 528 | extern int audit_n_rules; |
482 | extern int audit_signals; | 529 | extern int audit_signals; |
483 | #else /* CONFIG_AUDITSYSCALL */ | 530 | #else /* CONFIG_AUDITSYSCALL */ |
@@ -594,6 +641,20 @@ static inline void audit_fanotify(unsigned int response) | |||
594 | static inline void audit_tk_injoffset(struct timespec64 offset) | 641 | static inline void audit_tk_injoffset(struct timespec64 offset) |
595 | { } | 642 | { } |
596 | 643 | ||
644 | static inline void audit_ntp_init(struct audit_ntp_data *ad) | ||
645 | { } | ||
646 | |||
647 | static inline void audit_ntp_set_old(struct audit_ntp_data *ad, | ||
648 | enum audit_ntp_type type, long long val) | ||
649 | { } | ||
650 | |||
651 | static inline void audit_ntp_set_new(struct audit_ntp_data *ad, | ||
652 | enum audit_ntp_type type, long long val) | ||
653 | { } | ||
654 | |||
655 | static inline void audit_ntp_log(const struct audit_ntp_data *ad) | ||
656 | { } | ||
657 | |||
597 | static inline void audit_ptrace(struct task_struct *t) | 658 | static inline void audit_ptrace(struct task_struct *t) |
598 | { } | 659 | { } |
599 | #define audit_n_rules 0 | 660 | #define audit_n_rules 0 |
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index ab58d67baf4d..a1280af20336 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h | |||
@@ -115,6 +115,7 @@ | |||
115 | #define AUDIT_KERN_MODULE 1330 /* Kernel Module events */ | 115 | #define AUDIT_KERN_MODULE 1330 /* Kernel Module events */ |
116 | #define AUDIT_FANOTIFY 1331 /* Fanotify access decision */ | 116 | #define AUDIT_FANOTIFY 1331 /* Fanotify access decision */ |
117 | #define AUDIT_TIME_INJOFFSET 1332 /* Timekeeping offset injected */ | 117 | #define AUDIT_TIME_INJOFFSET 1332 /* Timekeeping offset injected */ |
118 | #define AUDIT_TIME_ADJNTPVAL 1333 /* NTP value adjustment */ | ||
118 | 119 | ||
119 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ | 120 | #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ |
120 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ | 121 | #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 3843495d0083..5371b59bde36 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -2519,6 +2519,28 @@ void __audit_tk_injoffset(struct timespec64 offset) | |||
2519 | (long long)offset.tv_sec, offset.tv_nsec); | 2519 | (long long)offset.tv_sec, offset.tv_nsec); |
2520 | } | 2520 | } |
2521 | 2521 | ||
2522 | static void audit_log_ntp_val(const struct audit_ntp_data *ad, | ||
2523 | const char *op, enum audit_ntp_type type) | ||
2524 | { | ||
2525 | const struct audit_ntp_val *val = &ad->vals[type]; | ||
2526 | |||
2527 | if (val->newval == val->oldval) | ||
2528 | return; | ||
2529 | |||
2530 | audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJNTPVAL, | ||
2531 | "op=%s old=%lli new=%lli", op, val->oldval, val->newval); | ||
2532 | } | ||
2533 | |||
2534 | void __audit_ntp_log(const struct audit_ntp_data *ad) | ||
2535 | { | ||
2536 | audit_log_ntp_val(ad, "offset", AUDIT_NTP_OFFSET); | ||
2537 | audit_log_ntp_val(ad, "freq", AUDIT_NTP_FREQ); | ||
2538 | audit_log_ntp_val(ad, "status", AUDIT_NTP_STATUS); | ||
2539 | audit_log_ntp_val(ad, "tai", AUDIT_NTP_TAI); | ||
2540 | audit_log_ntp_val(ad, "tick", AUDIT_NTP_TICK); | ||
2541 | audit_log_ntp_val(ad, "adjust", AUDIT_NTP_ADJUST); | ||
2542 | } | ||
2543 | |||
2522 | static void audit_log_task(struct audit_buffer *ab) | 2544 | static void audit_log_task(struct audit_buffer *ab) |
2523 | { | 2545 | { |
2524 | kuid_t auid, uid; | 2546 | kuid_t auid, uid; |
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 92a90014a925..ac5555e25733 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/rtc.h> | 19 | #include <linux/rtc.h> |
20 | #include <linux/audit.h> | ||
20 | 21 | ||
21 | #include "ntp_internal.h" | 22 | #include "ntp_internal.h" |
22 | #include "timekeeping_internal.h" | 23 | #include "timekeeping_internal.h" |
@@ -709,7 +710,7 @@ static inline void process_adjtimex_modes(const struct __kernel_timex *txc, | |||
709 | * kernel time-keeping variables. used by xntpd. | 710 | * kernel time-keeping variables. used by xntpd. |
710 | */ | 711 | */ |
711 | int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, | 712 | int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, |
712 | s32 *time_tai) | 713 | s32 *time_tai, struct audit_ntp_data *ad) |
713 | { | 714 | { |
714 | int result; | 715 | int result; |
715 | 716 | ||
@@ -720,14 +721,29 @@ int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, | |||
720 | /* adjtime() is independent from ntp_adjtime() */ | 721 | /* adjtime() is independent from ntp_adjtime() */ |
721 | time_adjust = txc->offset; | 722 | time_adjust = txc->offset; |
722 | ntp_update_frequency(); | 723 | ntp_update_frequency(); |
724 | |||
725 | audit_ntp_set_old(ad, AUDIT_NTP_ADJUST, save_adjust); | ||
726 | audit_ntp_set_new(ad, AUDIT_NTP_ADJUST, time_adjust); | ||
723 | } | 727 | } |
724 | txc->offset = save_adjust; | 728 | txc->offset = save_adjust; |
725 | } else { | 729 | } else { |
726 | |||
727 | /* If there are input parameters, then process them: */ | 730 | /* If there are input parameters, then process them: */ |
728 | if (txc->modes) | 731 | if (txc->modes) { |
732 | audit_ntp_set_old(ad, AUDIT_NTP_OFFSET, time_offset); | ||
733 | audit_ntp_set_old(ad, AUDIT_NTP_FREQ, time_freq); | ||
734 | audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status); | ||
735 | audit_ntp_set_old(ad, AUDIT_NTP_TAI, *time_tai); | ||
736 | audit_ntp_set_old(ad, AUDIT_NTP_TICK, tick_usec); | ||
737 | |||
729 | process_adjtimex_modes(txc, time_tai); | 738 | process_adjtimex_modes(txc, time_tai); |
730 | 739 | ||
740 | audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset); | ||
741 | audit_ntp_set_new(ad, AUDIT_NTP_FREQ, time_freq); | ||
742 | audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status); | ||
743 | audit_ntp_set_new(ad, AUDIT_NTP_TAI, *time_tai); | ||
744 | audit_ntp_set_new(ad, AUDIT_NTP_TICK, tick_usec); | ||
745 | } | ||
746 | |||
731 | txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, | 747 | txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, |
732 | NTP_SCALE_SHIFT); | 748 | NTP_SCALE_SHIFT); |
733 | if (!(time_status & STA_NANO)) | 749 | if (!(time_status & STA_NANO)) |
diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h index 40e6122e634e..908ecaa65fc3 100644 --- a/kernel/time/ntp_internal.h +++ b/kernel/time/ntp_internal.h | |||
@@ -8,6 +8,8 @@ extern void ntp_clear(void); | |||
8 | extern u64 ntp_tick_length(void); | 8 | extern u64 ntp_tick_length(void); |
9 | extern ktime_t ntp_get_next_leap(void); | 9 | extern ktime_t ntp_get_next_leap(void); |
10 | extern int second_overflow(time64_t secs); | 10 | extern int second_overflow(time64_t secs); |
11 | extern int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, s32 *time_tai); | 11 | extern int __do_adjtimex(struct __kernel_timex *txc, |
12 | const struct timespec64 *ts, | ||
13 | s32 *time_tai, struct audit_ntp_data *ad); | ||
12 | extern void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts); | 14 | extern void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts); |
13 | #endif /* _LINUX_NTP_INTERNAL_H */ | 15 | #endif /* _LINUX_NTP_INTERNAL_H */ |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 3d24be4cd607..f366f2fdf1b0 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -2307,6 +2307,7 @@ static int timekeeping_validate_timex(const struct __kernel_timex *txc) | |||
2307 | int do_adjtimex(struct __kernel_timex *txc) | 2307 | int do_adjtimex(struct __kernel_timex *txc) |
2308 | { | 2308 | { |
2309 | struct timekeeper *tk = &tk_core.timekeeper; | 2309 | struct timekeeper *tk = &tk_core.timekeeper; |
2310 | struct audit_ntp_data ad; | ||
2310 | unsigned long flags; | 2311 | unsigned long flags; |
2311 | struct timespec64 ts; | 2312 | struct timespec64 ts; |
2312 | s32 orig_tai, tai; | 2313 | s32 orig_tai, tai; |
@@ -2330,13 +2331,15 @@ int do_adjtimex(struct __kernel_timex *txc) | |||
2330 | audit_tk_injoffset(delta); | 2331 | audit_tk_injoffset(delta); |
2331 | } | 2332 | } |
2332 | 2333 | ||
2334 | audit_ntp_init(&ad); | ||
2335 | |||
2333 | ktime_get_real_ts64(&ts); | 2336 | ktime_get_real_ts64(&ts); |
2334 | 2337 | ||
2335 | raw_spin_lock_irqsave(&timekeeper_lock, flags); | 2338 | raw_spin_lock_irqsave(&timekeeper_lock, flags); |
2336 | write_seqcount_begin(&tk_core.seq); | 2339 | write_seqcount_begin(&tk_core.seq); |
2337 | 2340 | ||
2338 | orig_tai = tai = tk->tai_offset; | 2341 | orig_tai = tai = tk->tai_offset; |
2339 | ret = __do_adjtimex(txc, &ts, &tai); | 2342 | ret = __do_adjtimex(txc, &ts, &tai, &ad); |
2340 | 2343 | ||
2341 | if (tai != orig_tai) { | 2344 | if (tai != orig_tai) { |
2342 | __timekeeping_set_tai_offset(tk, tai); | 2345 | __timekeeping_set_tai_offset(tk, tai); |
@@ -2347,6 +2350,8 @@ int do_adjtimex(struct __kernel_timex *txc) | |||
2347 | write_seqcount_end(&tk_core.seq); | 2350 | write_seqcount_end(&tk_core.seq); |
2348 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); | 2351 | raw_spin_unlock_irqrestore(&timekeeper_lock, flags); |
2349 | 2352 | ||
2353 | audit_ntp_log(&ad); | ||
2354 | |||
2350 | /* Update the multiplier immediately if frequency was set directly */ | 2355 | /* Update the multiplier immediately if frequency was set directly */ |
2351 | if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK)) | 2356 | if (txc->modes & (ADJ_FREQUENCY | ADJ_TICK)) |
2352 | timekeeping_advance(TK_ADV_FREQ); | 2357 | timekeeping_advance(TK_ADV_FREQ); |