mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 00:49:03 +00:00
Fail early if process does not have permissions to write to log file (#2138)
* Fail early if process does not have permissions to write to log file * Open file once on NewFilesystemLogWriter
This commit is contained in:
parent
b32b441c12
commit
eecef148eb
3 changed files with 63 additions and 32 deletions
1
changes/issue-1950-logging-filesystem-fail-early
Normal file
1
changes/issue-1950-logging-filesystem-fail-early
Normal file
|
|
@ -0,0 +1 @@
|
|||
* Fail early if the process does not have permissions to write to the logging file.
|
||||
|
|
@ -24,35 +24,42 @@ type filesystemLogWriter struct {
|
|||
// NewFilesystemLogWriter creates a log file for osquery status/result logs.
|
||||
// The logFile can be rotated by sending a `SIGHUP` signal to Fleet if
|
||||
// enableRotation is true
|
||||
//
|
||||
// The enableCompression argument is only used when enableRotation is true.
|
||||
func NewFilesystemLogWriter(path string, appLogger log.Logger, enableRotation bool, enableCompression bool) (*filesystemLogWriter, error) {
|
||||
if enableRotation {
|
||||
// Use lumberjack logger that supports rotation
|
||||
osquerydLogger := &lumberjack.Logger{
|
||||
Filename: path,
|
||||
MaxSize: 500, // megabytes
|
||||
MaxBackups: 3,
|
||||
MaxAge: 28, //days
|
||||
Compress: enableCompression,
|
||||
}
|
||||
appLogger = log.With(appLogger, "component", "osqueryd-logger")
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGHUP)
|
||||
go func() {
|
||||
for {
|
||||
<-sig //block on signal
|
||||
if err := osquerydLogger.Rotate(); err != nil {
|
||||
appLogger.Log("err", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return &filesystemLogWriter{osquerydLogger}, nil
|
||||
}
|
||||
// no log rotation, use "raw" bufio implementation
|
||||
writer, err := newRawLogWriter(path)
|
||||
// Fail early if the process does not have the necessary
|
||||
// permissions to open the file at path.
|
||||
file, err := openFile(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "create new raw logger")
|
||||
return nil, errors.Wrap(err, "perm check")
|
||||
}
|
||||
return &filesystemLogWriter{writer}, nil
|
||||
if !enableRotation {
|
||||
// no log rotation, use "raw" bufio implementation
|
||||
return &filesystemLogWriter{
|
||||
writer: newRawLogWriter(file),
|
||||
}, nil
|
||||
}
|
||||
// Use lumberjack logger that supports rotation
|
||||
file.Close()
|
||||
osquerydLogger := &lumberjack.Logger{
|
||||
Filename: path,
|
||||
MaxSize: 500, // megabytes
|
||||
MaxBackups: 3,
|
||||
MaxAge: 28, //days
|
||||
Compress: enableCompression,
|
||||
}
|
||||
appLogger = log.With(appLogger, "component", "osqueryd-logger")
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGHUP)
|
||||
go func() {
|
||||
for {
|
||||
<-sig //block on signal
|
||||
if err := osquerydLogger.Rotate(); err != nil {
|
||||
appLogger.Log("err", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return &filesystemLogWriter{osquerydLogger}, nil
|
||||
}
|
||||
|
||||
// If writer is based on bufio we want to flush after a batch of
|
||||
|
|
@ -85,13 +92,9 @@ type rawLogWriter struct {
|
|||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
func newRawLogWriter(path string) (*rawLogWriter, error) {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func newRawLogWriter(file *os.File) *rawLogWriter {
|
||||
buff := bufio.NewWriter(file)
|
||||
return &rawLogWriter{file: file, buff: buff}, nil
|
||||
return &rawLogWriter{file: file, buff: buff}
|
||||
}
|
||||
|
||||
// Write bytes to file
|
||||
|
|
@ -141,3 +144,7 @@ func (l *rawLogWriter) Close() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func openFile(path string) (*os.File, error) {
|
||||
return os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import (
|
|||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
stderrors "errors"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
|
@ -59,6 +61,27 @@ func TestFilesystemLogger(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
// TestFilesystemLoggerPermission tests that NewFilesystemLogWriter fails
|
||||
// if the process does not have permissions to write to the provided path.
|
||||
func TestFilesystemLoggerPermission(t *testing.T) {
|
||||
tempPath := t.TempDir()
|
||||
require.NoError(t, os.Chmod(tempPath, 0000))
|
||||
fileName := path.Join(tempPath, "filesystemLogWriter")
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
rotation bool
|
||||
}{
|
||||
{name: "with-rotation", rotation: true},
|
||||
{name: "without-rotation", rotation: false},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, err := NewFilesystemLogWriter(fileName, log.NewNopLogger(), tc.rotation, false)
|
||||
require.Error(t, err)
|
||||
require.True(t, stderrors.Is(err, fs.ErrPermission), err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFilesystemLogger(b *testing.B) {
|
||||
ctx := context.Background()
|
||||
tempPath, err := ioutil.TempDir("", "test")
|
||||
|
|
|
|||
Loading…
Reference in a new issue