任務越簡單,我就越容易犯錯

任務越簡單,我就越容易犯錯

這項瑣碎的任務發生在一個星期五下午,本應花費 2-3 分鐘的時間。總的來說,一如既往。

一位同事要求我修復他伺服器上的腳本。我照做了,遞給他,不經意地落下:“時間快了5分鐘。”讓伺服器自己處理同步。半小時,一個小時過去了,他依然氣喘吁籲,小聲咒罵。

「愚蠢的! — 我想,切換到伺服器控制台 — 好吧,我再休息幾分鐘。

讓我們來看看 ntp、rdate、sdwdate 未安裝 時間同步 已禁用且未運行。

# timedatectl
      Local time: Sun 2019-08-25 20:44:39 +03
  Universal time: Sun 2019-08-25 17:44:39 UTC
        RTC time: Sun 2019-08-25 17:39:52
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

在這裡我會立即註意到硬體時間是正確的:進一步導航會更容易。

這就是一系列錯誤的開始。

第一個錯誤。自信心

咔嚓咔嚓...

# systemctl enable systemd-timesyncd.service && systemctl start systemd-timesyncd.service && ntpdate 0.ru.pool.ntp.org && timedatectl set-ntp on && timedatectl
25 Aug 21:00:10 ntpdate[28114]: adjust time server 195.210.189.106 offset -249.015251 sec
      Local time: Sun 2019-08-25 21:00:10 +03
  Universal time: Sun 2019-08-25 18:00:10 UTC
        RTC time: Sun 2019-08-25 18:00:10
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a

一切正常,時間已同步,系統時間與硬體時間一致。 「拿走吧,」我說完就繼續我的事了。

「拿什麼? - 同事很憤怒。 “都是同一時間啊!”

你解決典型問題的次數越多,你的思維就越狹隘,你不再認為第一百次或第一千次情況會有所不同,但這次不會。

# timedatectl
      Local time: Sun 2019-08-25 21:09:15 +03
  Universal time: Sun 2019-08-25 18:09:15 UTC
        RTC time: Sun 2019-08-25 18:05:04
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

系統時間又錯了。

讓我們再試一次:

# ntpdate 0.ru.pool.ntp.org && timedatectl && sleep 1 && timedatectl
25 Aug 21:07:37 ntpdate[30350]: step time server 89.175.20.7 offset -249.220828 sec
      Local time: Sun 2019-08-25 21:07:37 +03
  Universal time: Sun 2019-08-25 18:07:37 UTC
        RTC time: Sun 2019-08-25 18:07:37
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a
      Local time: Sun 2019-08-25 21:11:46 +03
  Universal time: Sun 2019-08-25 18:11:46 UTC
        RTC time: Sun 2019-08-25 18:07:37
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

讓我們換個方式:

# date -s "2019-08-25 21:10:30" && date && sleep 1 && timedatectl
Sun Aug 25 21:10:30 +03 2019
Sun Aug 25 21:10:30 +03 2019
      Local time: Sun 2019-08-25 21:14:36 +03
  Universal time: Sun 2019-08-25 18:14:36 UTC
        RTC time: Sun 2019-08-25 18:10:30
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

像這樣:

# hwclock --hctosys && timedatectl && sleep 1 && timedatectl
      Local time: Sun 2019-08-25 21:11:31 +03
  Universal time: Sun 2019-08-25 18:11:31 UTC
        RTC time: Sun 2019-08-25 18:11:31
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: no
      DST active: n/a
      Local time: Sun 2019-08-25 21:15:36 +03
  Universal time: Sun 2019-08-25 18:15:36 UTC
        RTC time: Sun 2019-08-25 18:11:32
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: yes
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

時間定為一瞬間,立刻又開始「奔騰」。

同時,在日誌中,在進行此類手動更改時,我們僅看到系統報告時間已分別以正確/錯誤的方向更改,以及偶爾更改 重新同步 來自 systemd-timesyncd。

Aug 25 21:18:51 wisi systemd[1]: Time has been changed
Aug 25 21:18:51 wisi systemd-timesyncd[29258]: System time changed. Resyncing.
Aug 25 21:18:51 wisi systemd[1187]: Time has been changed
Aug 25 21:18:51 wisi systemd[1]: Time has been changed
Aug 25 21:18:51 wisi systemd[1187]: Time has been changed

這裡

# ps afx | grep "[1]187"
 1187 ?        Ss     0:02 /lib/systemd/systemd --user

此時,已經有必要尋找原因了,但經過18年的管理,大腦已經累積了「時間」錯誤的統計數據,並出於習慣,再次歸咎於同步。
讓我們完全關閉它。

# timedatectl set-ntp off && systemctl stop systemd-timesyncd.service
# hwclock --hctosys && timedatectl && sleep 1 && timedatectl
      Local time: Sun 2019-08-25 21:25:40 +03
  Universal time: Sun 2019-08-25 18:25:40 UTC
        RTC time: Sun 2019-08-25 18:25:40
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a
      Local time: Sun 2019-08-25 21:29:31 +03
  Universal time: Sun 2019-08-25 18:29:31 UTC
        RTC time: Sun 2019-08-25 18:25:41
       Time zone: Europe/Minsk (+03, +0300)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a

並在日誌中

Aug 25 21:25:40 wisi systemd[1]: Time has been changed
Aug 25 21:25:40 wisi systemd[1187]: Time has been changed
Aug 25 21:29:30 wisi systemd[1]: Time has been changed
Aug 25 21:29:30 wisi systemd[1187]: Time has been changed

重新同步 消失了,否則日誌是原始的。

檢查結論 轉儲 在所有介面的連接埠 123 上。沒有人提出要求,但時間仍在流逝。

錯誤二。匆忙

距離一周的工作結束還有一個小時,我不想帶著一個沒有解決的瑣碎問題去週末(不要注意代碼中的時間,文章是在接下來的幾天裡寫的) )。
在這裡,我不再尋找原因,而是開始嘗試對結果做出解釋。我說「發明」是因為無論對結果的解釋多麼合乎邏輯,這都是解決問題的有缺陷的方法。

該伺服器是串流媒體伺服器,並將 DVB-S2 串流轉換為 IP。 DVB-S 流包含時間戳,因此接收器、復用器、加擾器和電視經常使用它們來同步系統時鐘。 DVB-S 板驅動程式內建於核心中,因此確保刪除 DVB-S2 串流的最快方法是斷開來自「板」的電纜。幸好伺服器在牆後,也就這樣吧。

當然,如果日誌包含了應該存在的內容,這種情況就不會發生,但更多內容將在文章末尾再次介紹。

好吧,既然我們已經刪除了所有衛星訊號,我們也將刪除地面訊號 - 同時我們拔掉所有網路電纜。伺服器與外界隔絕,完全自主工作,但係統時鐘仍然很匆忙。

工作週結束了,日期/時間問題本身並不重要,所以你可以回家了,但在這裡我犯了一個新的錯誤。

錯誤三。顧問

絕不!如果問題的答案需要的不僅僅是研究谷歌的第一頁和閱讀一個手冊頁,那麼永遠不要在論壇和一般專業(la stackoverflow)網站上提問。

他們會把你送回谷歌,閱讀同一個人並通俗地解釋論壇/網站的規則,但不會給你答案。

以下是一些客觀因素:

  • 除了你之外沒有人能知道問題所在;
  • 沒有人可以在與您相同的條件下進行測試

和主觀:

  • 你可能不會提供解決問題的所有信息,因為你已經找到了“正確”的方向,並圍繞它提出了問題的本質;
  • 領班(主持人、老前輩、管理員)總是對的,如果領班錯了…好吧,你知道…

如果在回覆評論時,您仍然處於經過審查的詞彙範圍內,那麼您就很緊張。

解決方法

沒有必要將任務分為簡單和複雜。

我們不再依賴我們的經驗、統計數據、顧問,並開始不「解釋」最終結果,而是不斷尋找原因。

既然有人設定了時間,必然會發生對應的系統呼叫。

正如在軟體文件中最好的文件是來源一樣,在系統管理中最好的助手是審計,在我們的例子中 審核.

一瞬間的疑惑我查了一下法力,但不完全確定Linux中的時間只能設定 時鐘設定時間 и 設定時間,所以對於第一個測試,我選擇了所有「合適」的呼叫:

# man syscalls | col | grep -F '(2)' | grep -vE '(:|;)' | grep -E '(time|date|clock)' | sed "s/(2).*//" | xargs -I SYSCALL echo "-S SYSCALL " | xargs echo
-S adjtimex -S clock_adjtime -S clock_getres -S clock_gettime -S clock_nanosleep -S clock_settime -S futimesat -S getitimer -S gettimeofday -S mq_timedreceive -S mq_timedsend -S rt_sigtimedwait -S s390_runtime_instr -S setitimer -S settimeofday -S stime -S time -S timer_create -S timer_delete -S timer_getoverrun -S timer_gettime -S timer_settime -S timerfd_create -S timerfd_gettime -S timerfd_settime -S times -S utime -S utimensat -S utimes

並丟棄 s390_runtime_instr、stime、timerfd_create, 哪個 審計控制 沒有意識到,最初以以下形式發起審核:

auditctl -a exit,always -S adjtimex -S clock_adjtime -S clock_getres -S clock_nanosleep -S clock_settime -S futimesat -S getitimer -S gettimeofday -S mq_timedreceive -S mq_timedsend -S rt_sigtimedwait -S semtimedop -S setitimer -S settimeofday -S time -S timer_create -S timer_delete -S timer_getoverrun -S timer_gettime -S timer_settime -S timerfd_gettime -S timerfd_settime -S times -S utime -S utimensat -S utimes

確保日誌位置中沒有我感興趣的其他日誌後 系統調用 除了這兩個之外,我只進一步使用了它們。

運行系統調用審核 時鐘設定時間 и 設定時間 並嘗試更改日期:

# auditctl -a exit,always -S clock_settime -S settimeofday && date -s "2019-08-22 12:10:00" && sleep 5 && auditctl -D

增加了五秒鐘的延遲,以確保我們的「寄生蟲」能夠糾正時間。

我們看一下報告:

# aureport -s -i

Syscall Report
=======================================
# date time syscall pid comm auid event
=======================================
Warning - freq is non-zero and incremental flushing not selected.
1. 08/22/2019 12:10:00 settimeofday 3088 chkcache_proces root 479630
2. 08/26/2019 09:37:06 clock_settime 1538 date root 479629

在這裡我們看到我們的 日期 而我們不知道 chkcache_進程。它最終出現在上面的報告中,因為 aureport 在從二進位轉換時按日期對輸出進行排序,並且事件發生在我們設定的時間 日期-s“2019-08-22 12:10:00”.
誰生了他?

# ausearch -sc settimeofday --comm "chkcache_proces"
----
time->Thu Aug 22 12:10:00 2019
type=PROCTITLE msg=audit(1566465000.000:479630): proctitle="/usr/local/bin/oscam"
type=SYSCALL msg=audit(1566465000.000:479630): arch=c000003e syscall=164 success=yes exit=0 a0=7fde0dfc6e60 a1=0 a2=136cf a3=713ba56 items=0 ppid=3081 pid=3088 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts20 ses=68149 comm="chkcache_proces" exe="/usr/local/bin/oscam" key=(null)

/usr/local/bin/oscam - 我們的寄生蟲被發現了。儘管其行為“惡意”,但無法拒絕條件接收系統,但我仍然想知道 奧斯卡姆,什麼鬼?

很快就能找到答案 原始碼:

#if defined(CLOCKFIX)
if (tv.tv_sec > lasttime.tv_sec || (tv.tv_sec == lasttime.tv_sec && tv.tv_usec >= lasttime.tv_usec)) // check for time issues!
{
  lasttime = tv; // register this valid time
}
  else
{
  tv = lasttime;
  settimeofday(&tv, NULL); // set time back to last known valid time
  //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** n");
}

這裡看起來多麼可愛 註解掉了 警告...

來源: www.habr.com

添加評論