Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion managed/cmd/pmm-encryption-rotation/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ func main() {
}

statusCode, err := encryptionService.RotateEncryptionKey(sqlDB, "pmm-managed")
sqlDB.Close() //nolint:errcheck
closeErr := sqlDB.Close()
if closeErr != nil {
logrus.Error(closeErr)
}
if err != nil {
logrus.Error(err)
os.Exit(statusCode)
Expand Down
26 changes: 18 additions & 8 deletions managed/cmd/pmm-managed/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ const (
cleanOlderThan = 30 * time.Minute

defaultContextTimeout = 10 * time.Second
// When ReadHeaderTimeout is not configured, a malicious client can open
// a connection and send headers extremely slowly (or not at all),
// keeping the connection open indefinitely. This "Slowloris" attack can eventually
// exhaust the server's connection pool, leading to a Denial of Service (DoS).
readHeaderTimeout = 10 * time.Second
pProfProfileDuration = 30 * time.Second
pProfTraceDuration = 10 * time.Second

Expand Down Expand Up @@ -439,10 +444,11 @@ func runHTTP1Server(ctx context.Context, deps *http1ServerDeps) {
mux.Handle("/v1/users/current", deps.currentUserHandler)
mux.Handle("/", proxyMux)

server := &http.Server{ //nolint:gosec
Addr: http1Addr,
ErrorLog: log.New(os.Stderr, "runJSONServer: ", 0),
Handler: mux,
server := &http.Server{
Addr: http1Addr,
ErrorLog: log.New(os.Stderr, "runJSONServer: ", 0),
Handler: mux,
ReadHeaderTimeout: readHeaderTimeout,
}
go func() {
err := server.ListenAndServe()
Expand Down Expand Up @@ -499,13 +505,17 @@ func runDebugServer(ctx context.Context) {
l.Fatal(err)
}
http.HandleFunc("/debug", func(rw http.ResponseWriter, _ *http.Request) {
rw.Write(buf.Bytes()) //nolint:errcheck
_, wErr := rw.Write(buf.Bytes())
if wErr != nil {
l.Errorf("Failed to write debug page: %v", wErr)
}
})
l.Infof("Starting server on http://%s/debug\nRegistered handlers:\n\t%s", debugAddr, strings.Join(handlers, "\n\t"))

server := &http.Server{ //nolint:gosec
Addr: debugAddr,
ErrorLog: log.New(os.Stderr, "runDebugServer: ", 0),
server := &http.Server{
Addr: debugAddr,
ErrorLog: log.New(os.Stderr, "runDebugServer: ", 0),
ReadHeaderTimeout: readHeaderTimeout,
}
go func() {
err := server.ListenAndServe()
Expand Down
5 changes: 2 additions & 3 deletions managed/models/artifact_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package models
import (
"errors"
"fmt"
"math"
"strings"

"github.com/google/uuid"
Expand Down Expand Up @@ -330,9 +331,7 @@ func DeleteArtifact(q *reform.Querier, id string) error {

// MetadataRemoveFirstN removes first N records from artifact metadata list.
func (s *Artifact) MetadataRemoveFirstN(q *reform.Querier, n uint32) error {
if n > uint32(len(s.MetadataList)) {
n = uint32(len(s.MetadataList))
}
n = min(n, math.MaxUint32)
s.MetadataList = s.MetadataList[n:]
err := q.Update(s)
Comment thread
maxkondr marked this conversation as resolved.
Outdated
if err != nil {
Expand Down
25 changes: 20 additions & 5 deletions managed/models/encryption_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ func awsOptionsHandler(val any, handler func(string) (string, error)) (any, erro
return nil, err
}

res, err := json.Marshal(o)
// The gosec G117 warning is triggered when sensitive fields (like ClientSecret, AWSSecretKey, or TLSKey)
// are part of a structure being marshaled to JSON.
// In the context of this file, these operations are intentional.
res, err := json.Marshal(o) //nolint:gosec
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -205,7 +208,10 @@ func azureOptionsHandler(val any, handler func(string) (string, error)) (any, er
return nil, err
}

res, err := json.Marshal(o)
// The gosec G117 warning is triggered when sensitive fields (like ClientSecret, AWSSecretKey, or TLSKey)
// are part of a structure being marshaled to JSON.
// In the context of this file, these operations are intentional.
res, err := json.Marshal(o) //nolint:gosec
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -244,7 +250,10 @@ func mongoDBOptionsHandler(val any, handler func(string) (string, error)) (any,
return nil, err
}

res, err := json.Marshal(o)
// The gosec G117 warning is triggered when sensitive fields (like ClientSecret, AWSSecretKey, or TLSKey)
// are part of a structure being marshaled to JSON.
// In the context of this file, these operations are intentional.
res, err := json.Marshal(o) //nolint:gosec
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -283,7 +292,10 @@ func mySQLOptionsHandler(val any, handler func(string) (string, error)) (any, er
return nil, err
}

res, err := json.Marshal(o)
// The gosec G117 warning is triggered when sensitive fields (like ClientSecret, AWSSecretKey, or TLSKey)
// are part of a structure being marshaled to JSON.
// In the context of this file, these operations are intentional.
res, err := json.Marshal(o) //nolint:gosec
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -322,7 +334,10 @@ func postgreSQLOptionsHandler(val any, handler func(string) (string, error)) (an
return nil, err
}

res, err := json.Marshal(o)
// The gosec G117 warning is triggered when sensitive fields (like ClientSecret, AWSSecretKey, or TLSKey)
// are part of a structure being marshaled to JSON.
// In the context of this file, these operations are intentional.
res, err := json.Marshal(o) //nolint:gosec
if err != nil {
return nil, err
}
Expand Down
6 changes: 5 additions & 1 deletion managed/models/role_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package models
import (
"errors"
"fmt"
"math"
"strings"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -51,9 +52,12 @@ func AssignRoles(tx *reform.TX, userID int, roleIDs []int) error {
return err
}

if roleID < 0 || roleID > math.MaxUint32 {
logrus.Warnf("Role ID %d is out of range for uint32", roleID)
}
var userRole UserRoles
userRole.UserID = userID
userRole.RoleID = uint32(roleID)
userRole.RoleID = uint32(roleID) //nolint:gosec // role ID is not expected to overflow uint32
s = append(s, &userRole)
Comment thread
maxkondr marked this conversation as resolved.
}

Expand Down
2 changes: 1 addition & 1 deletion managed/services/agents/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (s *ActionsService) StartMySQLExplainAction(
return err
}

if res.PlaceholdersCount != uint32(len(placeholders)) {
if res.PlaceholdersCount != uint32(len(placeholders)) { //nolint:gosec // placeholders count is not expected to exceed uint32
return status.Error(codes.FailedPrecondition, "placeholders count is not correct")
}
q = res.ExplainFingerprint
Expand Down
8 changes: 7 additions & 1 deletion managed/services/agents/service_info_broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package agents
import (
"context"
"fmt"
"math"
"time"

"github.com/AlekSi/pointer"
Expand Down Expand Up @@ -213,7 +214,12 @@ func (c *ServiceInfoBroker) GetInfoFromService(ctx context.Context, q *reform.Qu
}
}
agent.PostgreSQLOptions.PGSMVersion = sInfo.PgsmVersion
agent.PostgreSQLOptions.DatabaseCount = int32(databaseCount - excludedDatabaseCount)

dbCount := databaseCount - excludedDatabaseCount
if dbCount > math.MaxInt32 {
dbCount = math.MaxInt32
}
agent.PostgreSQLOptions.DatabaseCount = int32(dbCount)
Comment thread
Copilot marked this conversation as resolved.
Outdated

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
G115: integer overflow conversion int -> int32 (gosec)


l.Debugf("Updating PostgreSQL options, database count: %d.", agent.PostgreSQLOptions.DatabaseCount)
err = q.Update(new(models.EncryptAgent(*agent)))
Expand Down
34 changes: 26 additions & 8 deletions managed/services/alerting/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"errors"
"fmt"
"maps"
"math"
"os"
"path/filepath"
"sort"
Expand Down Expand Up @@ -353,19 +354,32 @@ func (s *Service) ListTemplates(ctx context.Context, req *alerting.ListTemplates
}

templates := s.GetTemplates()
res := &alerting.ListTemplatesResponse{
Templates: make([]*alerting.Template, 0, len(templates)),
TotalItems: int32(len(templates)),
TotalPages: 1,
totalItems := len(templates)
// return value type is int32, so we need to limit it to max int32 value
if totalItems > math.MaxInt32 {
s.l.Warnf("Total templates count %d is greater than max int32 value, limiting to %d.", totalItems, math.MaxInt32)
totalItems = math.MaxInt32
}

totalPages := 1
if pageSize > 0 {
res.TotalPages = int32(len(templates) / pageSize)
if len(templates)%pageSize > 0 {
res.TotalPages++
totalPages = totalItems / pageSize
if totalItems%pageSize > 0 {
totalPages++
}
// return value type is int32, so we need to limit it to max int32 value
if totalPages > math.MaxInt32 {
totalPages = math.MaxInt32
}
}

res := &alerting.ListTemplatesResponse{
Templates: make([]*alerting.Template, 0, totalItems),
TotalItems: int32(totalItems),
TotalPages: int32(totalPages),
}
Comment thread
maxkondr marked this conversation as resolved.
Outdated


names := make([]string, 0, len(templates))
for name := range templates {
names = append(names, name)
Expand Down Expand Up @@ -533,13 +547,17 @@ func convertTemplate(l *logrus.Entry, template models.Template) (*alerting.Templ
return nil, err
}

if template.Severity < math.MinInt32 || template.Severity > math.MaxInt32 {
l.Warnf("Alerting template severity %d is out of range for int32", template.Severity)
}
Comment thread
maxkondr marked this conversation as resolved.

t := &alerting.Template{
Name: template.Name,
Summary: template.Summary,
Expr: template.Expr,
Params: convertParamDefinitions(l, template.Params),
For: durationpb.New(template.For),
Severity: managementv1.Severity(template.Severity),
Severity: managementv1.Severity(template.Severity), //nolint:gosec
Labels: labels,
Annotations: annotations,
Source: convertSource(template.Source),
Expand Down
88 changes: 87 additions & 1 deletion managed/services/alerting/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package alerting

import (
"math"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -152,7 +153,7 @@ templates:
const validTemplate = `
---
templates:
- name: valid_template_1
- name: valid_template_11
version: 1
summary: Valid template 1
expr: |-
Expand Down Expand Up @@ -241,3 +242,88 @@ templates:
"placeholders: template: :4:5: executing \"\" at <.threshold>: map has no entry for key \"threshold\".")
})
}

func TestListTemplatesOverflow(t *testing.T) {
ctx := t.Context()
sqlDB := testdb.Open(t, models.SkipFixtures, nil)
t.Cleanup(func() {
require.NoError(t, sqlDB.Close())
})
db := reform.NewDB(sqlDB, postgresql.Dialect, nil)

svc, err := NewService(db, nil)
require.NoError(t, err)

t.Run("SeverityOverflow", func(t *testing.T) {
svc.rw.Lock()
svc.templates = map[string]models.Template{
"overflow": {
Name: "overflow",
Severity: math.MaxInt32 + 1,
},
}
svc.rw.Unlock()

resp, err := svc.ListTemplates(ctx, &alerting.ListTemplatesRequest{})
assert.Nil(t, resp)
require.Error(t, err)
assert.Contains(t, err.Error(), "alerting template severity 2147483648 is out of range for int32")
})

t.Run("SeverityUnderflow", func(t *testing.T) {
svc.rw.Lock()
svc.templates = map[string]models.Template{
"underflow": {
Name: "underflow",
Severity: math.MinInt32 - 1,
},
}
svc.rw.Unlock()

resp, err := svc.ListTemplates(ctx, &alerting.ListTemplatesRequest{})
assert.Nil(t, resp)
require.Error(t, err)
assert.Contains(t, err.Error(), "alerting template severity -2147483649 is out of range for int32")
})
}

func TestListTemplatesPagination(t *testing.T) {
ctx := t.Context()
sqlDB := testdb.Open(t, models.SkipFixtures, nil)
t.Cleanup(func() {
require.NoError(t, sqlDB.Close())
})
db := reform.NewDB(sqlDB, postgresql.Dialect, nil)

svc, err := NewService(db, nil)
require.NoError(t, err)

svc.rw.Lock()
svc.templates = map[string]models.Template{
"t1": {Name: "t1"},
"t2": {Name: "t2"},
"t3": {Name: "t3"},
}
svc.rw.Unlock()

t.Run("FullPage", func(t *testing.T) {
resp, err := svc.ListTemplates(ctx, &alerting.ListTemplatesRequest{
PageSize: new(int32(2)),
})
require.NoError(t, err)
assert.Equal(t, int32(2), resp.TotalPages)
assert.Equal(t, int32(3), resp.TotalItems)
assert.Len(t, resp.Templates, 2)
})

t.Run("LastPage", func(t *testing.T) {
resp, err := svc.ListTemplates(ctx, &alerting.ListTemplatesRequest{
PageSize: new(int32(2)),
PageIndex: new(int32(1)),
})
require.NoError(t, err)
assert.Equal(t, int32(2), resp.TotalPages)
assert.Len(t, resp.Templates, 1)
assert.Equal(t, "t3", resp.Templates[0].Name)
})
}
12 changes: 9 additions & 3 deletions managed/services/backup/pitr_timerange_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"context"
"errors"
"fmt"
"math"
"path"
"sort"
"strconv"
Expand Down Expand Up @@ -231,10 +232,15 @@ func pitrParseTS(tstr string) *primitive.Timestamp {
// just skip this file
return nil
}
ts := primitive.Timestamp{T: uint32(t.Unix())}
unix := t.Unix()
if unix < 0 || unix > math.MaxUint32 {
return nil
}
ts := primitive.Timestamp{T: uint32(unix)}

if len(tparts) > 1 {
ti, err := strconv.Atoi(tparts[1])
if err != nil {
ti, err := strconv.ParseUint(tparts[1], 10, 32)
if err != nil || ti > math.MaxUint32 {
// just skip this file
return nil
}
Expand Down
Loading
Loading