From c42c709688c06d76ee08ea880bf166aca7ecd288 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 1 Nov 2024 12:07:08 +0100 Subject: [PATCH 1/3] Log service panics on windows --- client/server/panic_generic.go | 7 +++ client/server/panic_windows.go | 78 ++++++++++++++++++++++++++++++++++ client/server/server.go | 4 ++ 3 files changed, 89 insertions(+) create mode 100644 client/server/panic_generic.go create mode 100644 client/server/panic_windows.go diff --git a/client/server/panic_generic.go b/client/server/panic_generic.go new file mode 100644 index 0000000000..f027b954b3 --- /dev/null +++ b/client/server/panic_generic.go @@ -0,0 +1,7 @@ +//go:build !windows + +package server + +func handlePanicLog() error { + return nil +} diff --git a/client/server/panic_windows.go b/client/server/panic_windows.go new file mode 100644 index 0000000000..26401f9c46 --- /dev/null +++ b/client/server/panic_windows.go @@ -0,0 +1,78 @@ +package server + +import ( + "fmt" + "os" + "path/filepath" + "syscall" + + log "github.com/sirupsen/logrus" +) + +const ( + windowsPanicLogEnvVar = "NB_WINDOWS_PANIC_LOG" + // STD_ERROR_HANDLE ((DWORD)-12) = 4294967284 + stdErrorHandle = ^uintptr(11) +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + + // https://learn.microsoft.com/en-us/windows/console/setstdhandle + setStdHandleFn = kernel32.NewProc("SetStdHandle") +) + +func handlePanicLog() error { + logPath := os.Getenv(windowsPanicLogEnvVar) + if logPath == "" { + return nil + } + + // Ensure the directory exists + logDir := filepath.Dir(logPath) + if err := os.MkdirAll(logDir, 0755); err != nil { + return fmt.Errorf("create panic log directory: %v", err) + } + + // Open log file with append mode + f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + return fmt.Errorf("open panic log file: %v", err) + } + + // Redirect stderr to the file + if err = redirectStderr(f); err != nil { + if closeErr := f.Close(); closeErr != nil { + log.Warnf("failed to close file after redirect error: %v", closeErr) + } + return fmt.Errorf("redirect stderr: %v", err) + } + + log.Infof("successfully configured panic logging to: %s", logPath) + return nil +} + +// redirectStderr redirects stderr to the provided file +func redirectStderr(f *os.File) error { + // Get the current process's stderr handle + if err := setStdHandle(f); err != nil { + return fmt.Errorf("failed to set stderr handle: %v", err) + } + + // Also set os.Stderr for Go's standard library + os.Stderr = f + + return nil +} + +func setStdHandle(f *os.File) error { + handle := f.Fd() + r0, _, e1 := setStdHandleFn.Call(stdErrorHandle, handle) + if r0 == 0 { + if e1 != nil { + return e1 + } + return syscall.EINVAL + } + return nil +} diff --git a/client/server/server.go b/client/server/server.go index a033220819..4d921851f9 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -97,6 +97,10 @@ func (s *Server) Start() error { defer s.mutex.Unlock() state := internal.CtxGetState(s.rootCtx) + if err := handlePanicLog(); err != nil { + log.Warnf("failed to redirect stderr: %v", err) + } + if err := restoreResidualState(s.rootCtx); err != nil { log.Warnf(errRestoreResidualState, err) } From b8e8a7f186cbf97cc934a9ce5e0b4913125b9ccc Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 1 Nov 2024 12:47:58 +0100 Subject: [PATCH 2/3] Improve permissions --- client/server/panic_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/server/panic_windows.go b/client/server/panic_windows.go index 26401f9c46..4318fdd6be 100644 --- a/client/server/panic_windows.go +++ b/client/server/panic_windows.go @@ -30,7 +30,7 @@ func handlePanicLog() error { // Ensure the directory exists logDir := filepath.Dir(logPath) - if err := os.MkdirAll(logDir, 0755); err != nil { + if err := os.MkdirAll(logDir, 0750); err != nil { return fmt.Errorf("create panic log directory: %v", err) } From 86868cce317597660f56f7bd18b87eeff7d75837 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 1 Nov 2024 12:54:02 +0100 Subject: [PATCH 3/3] Fix permissions --- client/server/panic_windows.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/server/panic_windows.go b/client/server/panic_windows.go index 4318fdd6be..1d4ba4b756 100644 --- a/client/server/panic_windows.go +++ b/client/server/panic_windows.go @@ -7,6 +7,8 @@ import ( "syscall" log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/util" ) const ( @@ -31,13 +33,16 @@ func handlePanicLog() error { // Ensure the directory exists logDir := filepath.Dir(logPath) if err := os.MkdirAll(logDir, 0750); err != nil { - return fmt.Errorf("create panic log directory: %v", err) + return fmt.Errorf("create panic log directory: %w", err) + } + if err := util.EnforcePermission(logPath); err != nil { + return fmt.Errorf("enforce permission on panic log file: %w", err) } // Open log file with append mode f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { - return fmt.Errorf("open panic log file: %v", err) + return fmt.Errorf("open panic log file: %w", err) } // Redirect stderr to the file @@ -45,7 +50,7 @@ func handlePanicLog() error { if closeErr := f.Close(); closeErr != nil { log.Warnf("failed to close file after redirect error: %v", closeErr) } - return fmt.Errorf("redirect stderr: %v", err) + return fmt.Errorf("redirect stderr: %w", err) } log.Infof("successfully configured panic logging to: %s", logPath) @@ -56,7 +61,7 @@ func handlePanicLog() error { func redirectStderr(f *os.File) error { // Get the current process's stderr handle if err := setStdHandle(f); err != nil { - return fmt.Errorf("failed to set stderr handle: %v", err) + return fmt.Errorf("failed to set stderr handle: %w", err) } // Also set os.Stderr for Go's standard library