From 0163d9c0ee5a03e0f15c3ff7815f18b8d80bdde4 Mon Sep 17 00:00:00 2001 From: Ankit raj sharma Date: Thu, 8 Oct 2026 20:22:46 +0530 Subject: [PATCH] gosec: address G115 integer overflow conversions and re-enable linter Address G115 (integer overflow conversion) warnings across the codebase with bounds checks and #nosec annotations for safe conversions, and re-enable the G115 rule in .golangci.yml. Fixes #5584 Signed-off-by: Ankit raj sharma --- .golangci.yml | 1 - cli/command/container/cp.go | 2 +- cli/command/container/opts.go | 2 +- cli/command/container/stats_helpers.go | 10 +++++++--- cli/command/image/tree.go | 4 ++-- cli/command/service/logs.go | 2 +- cli/command/service/progress/progress.go | 10 +++++----- cli/command/swarm/unlock.go | 2 +- cli/compose/convert/service.go | 4 ++-- opts/swarmopts/port.go | 4 ++-- 10 files changed, 22 insertions(+), 19 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index ad5a06f1d831..744227eccbb8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -109,7 +109,6 @@ linters: gosec: excludes: - G104 # G104: Errors unhandled; (TODO: reduce unhandled errors, or explicitly ignore) - - G115 # G115: integer overflow conversion; (TODO: verify these: https://github.com/docker/cli/issues/5584) - G117 # G117: Exported struct field matches secret pattern (false positives for legitimate field names) - G118 # G118: Goroutine uses context.Background/TODO while request-scoped context is available (TODO: evaluate these) - G122 # G122: Filesystem operation in filepath.Walk/WalkDir callback uses race-prone path (TODO: evaluate these) diff --git a/cli/command/container/cp.go b/cli/command/container/cp.go index fbce9df646e5..c6f77ef4bfe6 100644 --- a/cli/command/container/cp.go +++ b/cli/command/container/cp.go @@ -108,7 +108,7 @@ func copyProgress(ctx context.Context, dst io.Writer, header string, total *int6 } // Write to the buffer first to avoid flickering and context switching - fmt.Fprint(buf, aec.Column(uint(len(header)+1))) + fmt.Fprint(buf, aec.Column(uint(len(header)+1))) // #nosec G115 -- length is non-negative fmt.Fprint(buf, aec.EraseLine(aec.EraseModes.Tail)) fmt.Fprint(buf, progressHumanSize(n)) diff --git a/cli/command/container/opts.go b/cli/command/container/opts.go index 94b8dffa34a6..db5ccaf936ba 100644 --- a/cli/command/container/opts.go +++ b/cli/command/container/opts.go @@ -639,7 +639,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con BlkioDeviceReadIOps: copts.deviceReadIOps.GetList(), BlkioDeviceWriteIOps: copts.deviceWriteIOps.GetList(), IOMaximumIOps: copts.ioMaxIOps, - IOMaximumBandwidth: uint64(copts.ioMaxBandwidth), + IOMaximumBandwidth: uint64(copts.ioMaxBandwidth), // #nosec G115 -- bandwidth bytes are non-negative Ulimits: copts.ulimits.GetList(), DeviceCgroupRules: copts.deviceCgroupRules.GetSlice(), Devices: deviceMappings, diff --git a/cli/command/container/stats_helpers.go b/cli/command/container/stats_helpers.go index 66571b530942..d168365fea7f 100644 --- a/cli/command/container/stats_helpers.go +++ b/cli/command/container/stats_helpers.go @@ -200,10 +200,14 @@ func calculateCPUPercentUnix(previousCPU container.CPUStats, curCPUStats contain } func calculateCPUPercentWindows(v *container.StatsResponse) float64 { + ns := v.Read.Sub(v.PreRead).Nanoseconds() + if ns <= 0 { + return 0.0 + } // Max number of 100ns intervals between the previous time read and now - possIntervals := uint64(v.Read.Sub(v.PreRead).Nanoseconds()) // Start with number of ns intervals - possIntervals /= 100 // Convert to number of 100ns intervals - possIntervals *= uint64(v.NumProcs) // Multiply by the number of processors + possIntervals := uint64(ns) // #nosec G115 -- guarded above: ns is positive + possIntervals /= 100 // Convert to number of 100ns intervals + possIntervals *= uint64(v.NumProcs) // Multiply by the number of processors // Percentage avoiding divide-by-zero if possIntervals > 0 { diff --git a/cli/command/image/tree.go b/cli/command/image/tree.go index cd053c2f4bb1..b5226aad4925 100644 --- a/cli/command/image/tree.go +++ b/cli/command/image/tree.go @@ -351,7 +351,7 @@ func printImageTree(outs command.Streams, view treeView) { // available for image names and removes any columns that would be too narrow // to display their content. func adjustColumns(width uint, columns []imgColumn, images []topImage) []imgColumn { - nameWidth := int(width) + nameWidth := int(width) // #nosec G115 -- terminal width fits in int if nameWidth > 0 { for idx, h := range columns { if h.Width == 0 { @@ -391,7 +391,7 @@ func generateLegend(out tui.Output, width uint) string { } legend += legendSb371.String() - r := max(int(width)-tui.Width(legend), 0) + r := max(int(width)-tui.Width(legend), 0) // #nosec G115 -- terminal width fits in int legend = strings.Repeat(" ", r) + legend return legend } diff --git a/cli/command/service/logs.go b/cli/command/service/logs.go index 79908b865758..8dabae455bac 100644 --- a/cli/command/service/logs.go +++ b/cli/command/service/logs.go @@ -130,7 +130,7 @@ func runLogs(ctx context.Context, dockerCli command.Cli, opts *logsOptions) erro if service.Service.Spec.Mode.Replicated != nil && service.Service.Spec.Mode.Replicated.Replicas != nil { // if replicas are initialized, figure out if we need to pad them replicas := *service.Service.Spec.Mode.Replicated.Replicas - maxLength = getMaxLength(int(replicas)) + maxLength = getMaxLength(int(replicas)) // #nosec G115 -- replicas count fits in int for length calculation } // we can't prettify tty logs. tell the user that this is the case. diff --git a/cli/command/service/progress/progress.go b/cli/command/service/progress/progress.go index ef191fce33ac..613ecb8433b9 100644 --- a/cli/command/service/progress/progress.go +++ b/cli/command/service/progress/progress.go @@ -301,7 +301,7 @@ func (u *replicatedProgressUpdater) update(service swarm.Service, tasks []swarm. u.slotMap = make(map[int]int) // Draw progress bars in order - writeOverallProgress(u.progressOut, 0, int(replicas), rollback) + writeOverallProgress(u.progressOut, 0, int(replicas), rollback) // #nosec G115 -- replicas count fits in int if replicas <= maxProgressBars { for i := uint64(1); i <= replicas; i++ { @@ -340,7 +340,7 @@ func (u *replicatedProgressUpdater) update(service swarm.Service, tasks []swarm. } if !u.done { - writeOverallProgress(u.progressOut, int(running), int(replicas), rollback) + writeOverallProgress(u.progressOut, int(running), int(replicas), rollback) // #nosec G115 -- task counts fit in int if running == replicas { u.done = true @@ -383,7 +383,7 @@ func (*replicatedProgressUpdater) tasksBySlot(tasks []swarm.Task, activeNodes ma } func (u *replicatedProgressUpdater) writeTaskProgress(task swarm.Task, mappedSlot int, replicas uint64) { - if u.done || replicas > maxProgressBars || uint64(mappedSlot) > replicas { + if u.done || replicas > maxProgressBars || mappedSlot < 0 || uint64(mappedSlot) > replicas { // #nosec G115 -- mappedSlot is non-negative slot index return } @@ -572,8 +572,8 @@ type replicatedJobProgressUpdater struct { } func newReplicatedJobProgressUpdater(service swarm.Service, progressOut progress.Output) *replicatedJobProgressUpdater { - concurrent := int(*service.Spec.Mode.ReplicatedJob.MaxConcurrent) - total := int(*service.Spec.Mode.ReplicatedJob.TotalCompletions) + concurrent := int(*service.Spec.Mode.ReplicatedJob.MaxConcurrent) // #nosec G115 -- job concurrency fits in int + total := int(*service.Spec.Mode.ReplicatedJob.TotalCompletions) // #nosec G115 -- job completions fit in int return &replicatedJobProgressUpdater{ progressOut: progressOut, diff --git a/cli/command/swarm/unlock.go b/cli/command/swarm/unlock.go index bf15ed2868c7..6cc939f30cfa 100644 --- a/cli/command/swarm/unlock.go +++ b/cli/command/swarm/unlock.go @@ -69,7 +69,7 @@ func runUnlock(ctx context.Context, dockerCLI command.Cli) error { func readKey(in *streams.In, prompt string) (string, error) { if in.IsTerminal() { fmt.Print(prompt) - dt, err := term.ReadPassword(int(in.FD())) + dt, err := term.ReadPassword(int(in.FD())) // #nosec G115 -- file descriptor fits in int fmt.Println() return string(dt), err } diff --git a/cli/compose/convert/service.go b/cli/compose/convert/service.go index d30597451a7d..59e9010926e4 100644 --- a/cli/compose/convert/service.go +++ b/cli/compose/convert/service.go @@ -458,7 +458,7 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container startInterval = time.Duration(*healthcheck.StartInterval) } if healthcheck.Retries != nil { - retries = int(*healthcheck.Retries) + retries = int(*healthcheck.Retries) // #nosec G115 -- retries count fits in int } return &container.HealthConfig{ Test: healthcheck.Test, @@ -500,7 +500,7 @@ func convertRestartPolicy(restart string, restartPolicy *composetypes.RestartPol if i <= 0 { return nil } - return new(uint64(i)) + return new(uint64(i)) // #nosec G115 -- maximum retry count is verified non-negative } switch policy.Name { diff --git a/opts/swarmopts/port.go b/opts/swarmopts/port.go index 589c12795900..87b3d48ef596 100644 --- a/opts/swarmopts/port.go +++ b/opts/swarmopts/port.go @@ -174,8 +174,8 @@ func ConvertPortToPortConfig( ports = append(ports, swarm.PortConfig{ // TODO Name: ? Protocol: portProto.Proto(), - TargetPort: uint32(portProto.Num()), - PublishedPort: uint32(p.Num()), + TargetPort: uint32(portProto.Num()), // #nosec G115 -- port number is uint16 + PublishedPort: uint32(p.Num()), // #nosec G115 -- port number is uint16 PublishMode: swarm.PortConfigPublishModeIngress, }) }