Skip to content

Commit 8eb8b2b

Browse files
authored
[restapi] Fix nil pointer dereference in monitor_certs when cert file is missing (#185)
#### Why I did it `monitor_certs()` in `go-server-server/main.go` calls `os.Lstat()` on each cert file path but silently discards the error return value with `_`. When a cert file is missing or its path is invalid, `os.Lstat()` returns `(nil, error)`. Calling `.ModTime()` on the nil `FileInfo` immediately causes a **nil pointer dereference (SIGSEGV)** that crashes the entire restapi process. Observed crash in SONiC nightly CI (Arista 4600C, image 20251110.22): ``` goroutine 1 [running]: main.monitor_certs(0xc000056060, 0xc000012100) go-server-server/main.go:122 +0x... panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation addr=0x20 pc=...] ``` After the crash, `supervisord` restarted restapi and the proc-exit-listener emitted ERR alerts every 60 seconds, causing `system_health/test_system_status` to fail. ##### Work item tracking - Microsoft ADO: [37693847](https://msazure.visualstudio.com/One/_workitems/edit/37693847) #### How I did it Added explicit nil/error checks after every `os.Lstat()` call in `monitor_certs` (6 total): - **Startup section (3 calls):** use `log.Fatalf` so the process fails immediately with a descriptive error message instead of panicking with an opaque SIGSEGV. - **Monitor loop (3 calls):** use `log.Printf` + `time.Sleep` + `continue` so a transiently missing cert file is retried on the next cycle (every 3600 s) without crashing the server. #### How to verify it 1. Start restapi with `--https` flag and a cert path that does not exist on disk. 2. **Before fix:** process crashes with `panic: runtime error: invalid memory address or nil pointer dereference`. 3. **After fix:** process exits cleanly via `log.Fatalf` with `"error: couldn't stat client cert file: ..."`. #### Which release branch to backport (provide reason below if selected) - [ ] 202305 - [ ] 202311 - [ ] 202405 - [ ] 202411 - [ ] 202505 - [x] 202511 — same crash observed on image 20251110.22 (202511 branch) #### Tested branch (Please provide the tested image version) - [x] 20251110.22 (202511) — crash confirmed in nightly CI job [69e79fb88e43924279229609](https://elastictest.org/scheduler/testplan/69e79fb88e43924279229609) #### Description for the changelog Fix nil pointer dereference crash in `monitor_certs` when a TLS cert file path is invalid or missing; restapi now exits with a descriptive error at startup instead of panicking silently. Signed-off-by: Sonic Build Admin <sonicbld@microsoft.com>
1 parent df38186 commit 8eb8b2b

1 file changed

Lines changed: 30 additions & 6 deletions

File tree

go-server-server/main.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,37 @@ func signal_handler(messenger chan<- int, wgroup *sync.WaitGroup) {
102102

103103
func monitor_certs(messenger chan<- int, wgroup *sync.WaitGroup) {
104104
defer wgroup.Done()
105-
client_cert_finfo, _ := os.Lstat(*sw.ClientCertFlag)
105+
client_cert_finfo, err := os.Lstat(*sw.ClientCertFlag)
106+
if err != nil {
107+
log.Fatalf("error: couldn't stat client cert file: %s", err)
108+
}
106109
prev_client_cert_mtime := client_cert_finfo.ModTime()
107110
log.Printf("trace: Last modified time of %s is %d", client_cert_finfo.Name(), prev_client_cert_mtime.Unix())
108111

109-
server_cert_finfo, _ := os.Lstat(*sw.ServerCertFlag)
112+
server_cert_finfo, err := os.Lstat(*sw.ServerCertFlag)
113+
if err != nil {
114+
log.Fatalf("error: couldn't stat server cert file: %s", err)
115+
}
110116
prev_server_cert_mtime := server_cert_finfo.ModTime()
111117
log.Printf("trace: Last modified time of %s is %d", server_cert_finfo.Name(), prev_server_cert_mtime.Unix())
112118

113-
sever_key_finfo, _ := os.Lstat(*sw.ServerKeyFlag)
119+
sever_key_finfo, err := os.Lstat(*sw.ServerKeyFlag)
120+
if err != nil {
121+
log.Fatalf("error: couldn't stat server key file: %s", err)
122+
}
114123
prev_sever_key_mtime := sever_key_finfo.ModTime()
115124
log.Printf("trace: Last modified time of %s is %d", sever_key_finfo.Name(), prev_sever_key_mtime.Unix())
116125

117126
time.Sleep(CERT_MONITOR_FREQUENCY)
118127

119128
for {
120129
reload := false
121-
client_cert_finfo, _ := os.Lstat(*sw.ClientCertFlag)
130+
client_cert_finfo, err := os.Lstat(*sw.ClientCertFlag)
131+
if err != nil {
132+
log.Printf("error: couldn't stat client cert file: %s", err)
133+
time.Sleep(CERT_MONITOR_FREQUENCY)
134+
continue
135+
}
122136
client_cert_mtime := client_cert_finfo.ModTime()
123137
log.Printf("trace: Last modified time of %s is %d", client_cert_finfo.Name(), client_cert_mtime.Unix())
124138
if client_cert_mtime != prev_client_cert_mtime {
@@ -127,7 +141,12 @@ func monitor_certs(messenger chan<- int, wgroup *sync.WaitGroup) {
127141
}
128142
prev_client_cert_mtime = client_cert_mtime
129143

130-
server_cert_finfo, _ := os.Lstat(*sw.ServerCertFlag)
144+
server_cert_finfo, err := os.Lstat(*sw.ServerCertFlag)
145+
if err != nil {
146+
log.Printf("error: couldn't stat server cert file: %s", err)
147+
time.Sleep(CERT_MONITOR_FREQUENCY)
148+
continue
149+
}
131150
server_cert_mtime := server_cert_finfo.ModTime()
132151
log.Printf("trace: Last modified time of %s is %d", server_cert_finfo.Name(), server_cert_mtime.Unix())
133152
if server_cert_mtime != prev_server_cert_mtime {
@@ -136,7 +155,12 @@ func monitor_certs(messenger chan<- int, wgroup *sync.WaitGroup) {
136155
}
137156
prev_server_cert_mtime = server_cert_mtime
138157

139-
sever_key_finfo, _ := os.Lstat(*sw.ServerKeyFlag)
158+
sever_key_finfo, err := os.Lstat(*sw.ServerKeyFlag)
159+
if err != nil {
160+
log.Printf("error: couldn't stat server key file: %s", err)
161+
time.Sleep(CERT_MONITOR_FREQUENCY)
162+
continue
163+
}
140164
sever_key_mtime := sever_key_finfo.ModTime()
141165
log.Printf("trace: Last modified time of %s is %d", sever_key_finfo.Name(), sever_key_mtime.Unix())
142166
if sever_key_mtime != prev_sever_key_mtime {

0 commit comments

Comments
 (0)