diff --git a/cmd/batch-handlers.go b/cmd/batch-handlers.go index 454feb19adc4f..fb21d5ab9b5ef 100644 --- a/cmd/batch-handlers.go +++ b/cmd/batch-handlers.go @@ -1771,22 +1771,22 @@ func (a adminAPIHandlers) StartBatchJob(w http.ResponseWriter, r *http.Request) // Fill with default values if job.Replicate != nil { if job.Replicate.Source.Snowball.Disable == nil { - job.Replicate.Source.Snowball.Disable = ptr(false) + job.Replicate.Source.Snowball.Disable = new(false) } if job.Replicate.Source.Snowball.Batch == nil { - job.Replicate.Source.Snowball.Batch = ptr(100) + job.Replicate.Source.Snowball.Batch = new(100) } if job.Replicate.Source.Snowball.InMemory == nil { - job.Replicate.Source.Snowball.InMemory = ptr(true) + job.Replicate.Source.Snowball.InMemory = new(true) } if job.Replicate.Source.Snowball.Compress == nil { - job.Replicate.Source.Snowball.Compress = ptr(false) + job.Replicate.Source.Snowball.Compress = new(false) } if job.Replicate.Source.Snowball.SmallerThan == nil { - job.Replicate.Source.Snowball.SmallerThan = ptr("5MiB") + job.Replicate.Source.Snowball.SmallerThan = new("5MiB") } if job.Replicate.Source.Snowball.SkipErrs == nil { - job.Replicate.Source.Snowball.SkipErrs = ptr(true) + job.Replicate.Source.Snowball.SkipErrs = new(true) } } diff --git a/cmd/batchjobmetric_string.go b/cmd/batchjobmetric_string.go index a1697a19d623e..d2615681ef293 100644 --- a/cmd/batchjobmetric_string.go +++ b/cmd/batchjobmetric_string.go @@ -18,7 +18,7 @@ const _batchJobMetric_name = "ReplicationKeyRotationExpire" var _batchJobMetric_index = [...]uint8{0, 11, 22, 28} func (i batchJobMetric) String() string { - if i >= batchJobMetric(len(_batchJobMetric_index)-1) { + if i < 0 || i >= batchJobMetric(len(_batchJobMetric_index)-1) { return "batchJobMetric(" + strconv.FormatInt(int64(i), 10) + ")" } return _batchJobMetric_name[_batchJobMetric_index[i]:_batchJobMetric_index[i+1]] diff --git a/cmd/data-usage-cache.go b/cmd/data-usage-cache.go index 5752daae057f7..8f9547c90ad19 100644 --- a/cmd/data-usage-cache.go +++ b/cmd/data-usage-cache.go @@ -635,11 +635,12 @@ func (d *dataUsageCache) forceCompact(limit int) { // StringAll returns a detailed string representation of all entries in the cache. func (d *dataUsageCache) StringAll() string { // Remove bloom filter from print. - s := fmt.Sprintf("info:%+v\n", d.Info) + var s strings.Builder + s.WriteString(fmt.Sprintf("info:%+v\n", d.Info)) for k, v := range d.Cache { - s += fmt.Sprintf("\t%v: %+v\n", k, v) + s.WriteString(fmt.Sprintf("\t%v: %+v\n", k, v)) } - return strings.TrimSpace(s) + return strings.TrimSpace(s.String()) } // String returns a human readable representation of the string. diff --git a/cmd/decommetric_string.go b/cmd/decommetric_string.go index fb485ab016ca1..a0afe2f76c425 100644 --- a/cmd/decommetric_string.go +++ b/cmd/decommetric_string.go @@ -18,7 +18,7 @@ const _decomMetric_name = "DecommissionBucketDecommissionObjectDecommissionRemov var _decomMetric_index = [...]uint8{0, 18, 36, 60} func (i decomMetric) String() string { - if i >= decomMetric(len(_decomMetric_index)-1) { + if i < 0 || i >= decomMetric(len(_decomMetric_index)-1) { return "decomMetric(" + strconv.FormatInt(int64(i), 10) + ")" } return _decomMetric_name[_decomMetric_index[i]:_decomMetric_index[i+1]] diff --git a/cmd/dynamic-timeouts.go b/cmd/dynamic-timeouts.go index 9c4f297bbe3a6..7bcf4e4a544db 100644 --- a/cmd/dynamic-timeouts.go +++ b/cmd/dynamic-timeouts.go @@ -129,13 +129,10 @@ func (dt *dynamicTimeout) adjust(entries [dynamicTimeoutLogSize]time.Duration) { if failPct > dynamicTimeoutIncreaseThresholdPct { // We are hitting the timeout too often, so increase the timeout by 25% - timeout := min( + timeout := max( // Set upper cap. - atomic.LoadInt64(&dt.timeout)*125/100, int64(maxDynamicTimeout)) - // Safety, shouldn't happen - if timeout < dt.minimum { - timeout = dt.minimum - } + min(atomic.LoadInt64(&dt.timeout)*125/100, int64(maxDynamicTimeout)), + dt.minimum) atomic.StoreInt64(&dt.timeout, timeout) } else if failPct < dynamicTimeoutDecreaseThresholdPct { // We are hitting the timeout relatively few times, diff --git a/cmd/erasure-common.go b/cmd/erasure-common.go index 7146766ac2e74..acda124ea619e 100644 --- a/cmd/erasure-common.go +++ b/cmd/erasure-common.go @@ -26,17 +26,21 @@ import ( func (er erasureObjects) getOnlineDisks() (newDisks []StorageAPI) { disks := er.getDisks() + var wg sync.WaitGroup var mu sync.Mutex + newDisks = make([]StorageAPI, 0, len(disks)) + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for _, i := range r.Perm(len(disks)) { - wg.Add(1) - go func() { - defer wg.Done() - if disks[i] == nil { - return - } - di, err := disks[i].DiskInfo(context.Background(), DiskInfoOptions{}) + disk := disks[i] // avoids repeated indexing + if disk == nil { + // avoids spawning goroutines that immediately return + continue + } + wg.Go(func() { + di, err := disk.DiskInfo(context.Background(), DiskInfoOptions{}) if err != nil || di.Healing { // - Do not consume disks which are not reachable // unformatted or simply not accessible for some reason. @@ -48,10 +52,11 @@ func (er erasureObjects) getOnlineDisks() (newDisks []StorageAPI) { } mu.Lock() - newDisks = append(newDisks, disks[i]) + newDisks = append(newDisks, disk) mu.Unlock() - }() + }) } + wg.Wait() return newDisks } diff --git a/cmd/erasure.go b/cmd/erasure.go index 4e6674c35b1c8..652c3aac86331 100644 --- a/cmd/erasure.go +++ b/cmd/erasure.go @@ -285,16 +285,15 @@ func (er erasureObjects) getOnlineDisksWithHealingAndInfo(inclHealing bool) (new infos := make([]DiskInfo, len(disks)) r := rand.New(rand.NewSource(time.Now().UnixNano())) for _, i := range r.Perm(len(disks)) { - wg.Add(1) - go func() { - defer wg.Done() + disk := disks[i] + if disk == nil { + infos[i].Error = errDiskNotFound.Error() + continue + } - disk := disks[i] - if disk == nil { - infos[i].Error = errDiskNotFound.Error() - return - } + i, disk := i, disk + wg.Go(func() { di, err := disk.DiskInfo(context.Background(), DiskInfoOptions{}) infos[i] = di if err != nil { @@ -302,7 +301,7 @@ func (er erasureObjects) getOnlineDisksWithHealingAndInfo(inclHealing bool) (new // unformatted or simply not accessible for some reason. infos[i].Error = err.Error() } - }() + }) } wg.Wait() diff --git a/cmd/healingmetric_string.go b/cmd/healingmetric_string.go index 012fc7aa9304f..6573a1c22c8e6 100644 --- a/cmd/healingmetric_string.go +++ b/cmd/healingmetric_string.go @@ -18,7 +18,7 @@ const _healingMetric_name = "BucketObjectCheckAbandonedParts" var _healingMetric_index = [...]uint8{0, 6, 12, 31} func (i healingMetric) String() string { - if i >= healingMetric(len(_healingMetric_index)-1) { + if i < 0 || i >= healingMetric(len(_healingMetric_index)-1) { return "healingMetric(" + strconv.FormatInt(int64(i), 10) + ")" } return _healingMetric_name[_healingMetric_index[i]:_healingMetric_index[i+1]] diff --git a/cmd/iam-object-store.go b/cmd/iam-object-store.go index 7da764577778f..89931148d5761 100644 --- a/cmd/iam-object-store.go +++ b/cmd/iam-object-store.go @@ -576,7 +576,7 @@ func (iamOS *IAMObjectStore) loadAllFromObjStore(ctx context.Context, cache *iam if took := time.Since(listStartTime); took > maxIAMLoadOpTime { var s strings.Builder for k, v := range listedConfigItems { - fmt.Fprintf(&s, " %s: %d items\n", k, len(v)) + s.WriteString(fmt.Sprintf(" %s: %d items\n", k, len(v))) } logger.Info("listAllIAMConfigItems took %.2fs with contents:\n%s", took.Seconds(), s.String()) } diff --git a/cmd/lceventsrc_string.go b/cmd/lceventsrc_string.go index dd121abb461e5..ea3451b8188a3 100644 --- a/cmd/lceventsrc_string.go +++ b/cmd/lceventsrc_string.go @@ -26,7 +26,7 @@ const _lcEventSrc_name = "NoneHealScannerDecomRebals3HeadObjects3GetObjects3List var _lcEventSrc_index = [...]uint8{0, 4, 8, 15, 20, 25, 37, 48, 61, 72, 84, 109} func (i lcEventSrc) String() string { - if i >= lcEventSrc(len(_lcEventSrc_index)-1) { + if i < 0 || i >= lcEventSrc(len(_lcEventSrc_index)-1) { return "lcEventSrc(" + strconv.FormatInt(int64(i), 10) + ")" } return _lcEventSrc_name[_lcEventSrc_index[i]:_lcEventSrc_index[i+1]] diff --git a/cmd/metacache-stream.go b/cmd/metacache-stream.go index cf61895fe4d7b..f08f85054c020 100644 --- a/cmd/metacache-stream.go +++ b/cmd/metacache-stream.go @@ -769,8 +769,14 @@ type metacacheBlockWriter struct { // Each block is the size of the capacity of the input channel. // The caller should close to indicate the stream has ended. func newMetacacheBlockWriter(in <-chan metaCacheEntry, nextBlock func(b *metacacheBlock) error) *metacacheBlockWriter { + blockEntries := cap(in) + if blockEntries <= 0 { + blockEntries = 1 + } + w := metacacheBlockWriter{blockEntries: cap(in)} w.wg.Add(1) + //TODO: this looks messy go func() { defer w.wg.Done() var current metacacheBlock @@ -784,6 +790,7 @@ func newMetacacheBlockWriter(in <-chan metaCacheEntry, nextBlock func(b *metacac block := newMetacacheWriter(buf, 1<<20) defer block.Close() + finishBlock := func() { if err := block.Close(); err != nil { w.streamErr = err diff --git a/cmd/notification.go b/cmd/notification.go index 152856ac23085..2bfa0efca4963 100644 --- a/cmd/notification.go +++ b/cmd/notification.go @@ -267,19 +267,29 @@ func (sys *NotificationSys) LoadServiceAccount(ctx context.Context, accessKey st func (sys *NotificationSys) BackgroundHealStatus(ctx context.Context) ([]madmin.BgHealState, []NotificationPeerErr) { ng := WithNPeers(len(sys.peerClients)) states := make([]madmin.BgHealState, len(sys.peerClients)) + for idx, client := range sys.peerClients { + idx := idx client := client + + var host xnet.Host + if client != nil && client.host != nil { + host = *client.host + } + ng.Go(ctx, func() error { - if client == nil { + if client == nil || client.host == nil { return errPeerNotReachable } + st, err := client.BackgroundHealStatus(ctx) if err != nil { return err } + states[idx] = st return nil - }, idx, *client.host) + }, idx, host) } return states, ng.Wait() @@ -475,28 +485,48 @@ var errPeerNotReachable = errors.New("peer is not reachable") func (sys *NotificationSys) GetLocks(ctx context.Context, r *http.Request) []*PeerLocks { locksResp := make([]*PeerLocks, len(sys.peerClients)) g := errgroup.WithNErrs(len(sys.peerClients)) + for index, client := range sys.peerClients { + index := index client := client + + peerAddr := "" + if client != nil && client.host != nil { + peerAddr = client.host.String() + } + g.Go(func() error { if client == nil { return errPeerNotReachable } - serverLocksResp, err := sys.peerClients[index].GetLocks(ctx) + + serverLocksResp, err := client.GetLocks(ctx) if err != nil { return err } locksResp[index] = &PeerLocks{ - Addr: sys.peerClients[index].host.String(), + Addr: peerAddr, Locks: serverLocksResp, } return nil }, index) } for index, err := range g.Wait() { - reqInfo := (&logger.ReqInfo{}).AppendTags("peerAddress", - sys.peerClients[index].host.String()) + if err == nil { + continue + } + + client := sys.peerClients[index] + + peerAddr := "" + if client != nil && client.host != nil { + peerAddr = client.host.String() + } + + reqInfo := (&logger.ReqInfo{}).AppendTags("peerAddress", peerAddr) ctx := logger.SetReqInfo(ctx, reqInfo) - peersLogOnceIf(ctx, err, sys.peerClients[index].host.String()) + + peersLogOnceIf(ctx, err, peerAddr) } locksResp = append(locksResp, &PeerLocks{ Addr: getHostName(r), diff --git a/cmd/os-dirent_namelen_linux.go b/cmd/os-dirent_namelen_linux.go index 14c44239453cb..525a2e8185fcd 100644 --- a/cmd/os-dirent_namelen_linux.go +++ b/cmd/os-dirent_namelen_linux.go @@ -31,10 +31,7 @@ func direntNamlen(dirent *syscall.Dirent) (uint64, error) { const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) const nameBufLen = uint16(len(nameBuf)) - limit := dirent.Reclen - fixedHdr - if limit > nameBufLen { - limit = nameBufLen - } + limit := min(dirent.Reclen-fixedHdr, nameBufLen) // Avoid bugs in long file names // https://github.com/golang/tools/commit/5f9a5413737ba4b4f692214aebee582b47c8be74 nameLen := bytes.IndexByte(nameBuf[:limit], 0) diff --git a/cmd/postpolicyform.go b/cmd/postpolicyform.go index 1c2eeaf40c562..ad117f2eb67ee 100644 --- a/cmd/postpolicyform.go +++ b/cmd/postpolicyform.go @@ -186,7 +186,7 @@ func parsePostPolicyForm(r io.Reader) (PostPolicyForm, error) { for k, v := range condt { if !isString(v) { // Pre-check value type. // All values must be of type string. - return parsedPolicy, fmt.Errorf("Unknown type %s of conditional field value %s found in POST policy form", reflect.TypeOf(condt).String(), condt) + return parsedPolicy, fmt.Errorf("Unknown type %s of conditional field value %s found in POST policy form", reflect.TypeFor[map[string]any]().String(), condt) } // {"acl": "public-read" } is an alternate way to indicate - [ "eq", "$acl", "public-read" ] // In this case we will just collapse this into "eq" for all use cases. @@ -240,7 +240,7 @@ func parsePostPolicyForm(r io.Reader) (PostPolicyForm, error) { default: // Condition should be valid. return parsedPolicy, fmt.Errorf("Unknown type %s of conditional field value %s found in POST policy form", - reflect.TypeOf(condt).String(), condt) + reflect.TypeFor[[]any]().String(), condt) } default: return parsedPolicy, fmt.Errorf("Unknown field %s of type %s found in POST policy form", diff --git a/cmd/rebalancemetric_string.go b/cmd/rebalancemetric_string.go index 930e04341de39..e14b186049c0f 100644 --- a/cmd/rebalancemetric_string.go +++ b/cmd/rebalancemetric_string.go @@ -20,7 +20,7 @@ const _rebalanceMetric_name = "RebalanceBucketsRebalanceBucketRebalanceObjectReb var _rebalanceMetric_index = [...]uint8{0, 16, 31, 46, 67, 79} func (i rebalanceMetric) String() string { - if i >= rebalanceMetric(len(_rebalanceMetric_index)-1) { + if i < 0 || i >= rebalanceMetric(len(_rebalanceMetric_index)-1) { return "rebalanceMetric(" + strconv.FormatInt(int64(i), 10) + ")" } return _rebalanceMetric_name[_rebalanceMetric_index[i]:_rebalanceMetric_index[i+1]] diff --git a/cmd/rebalstatus_string.go b/cmd/rebalstatus_string.go index 0dc74b217aad8..06d2a2c02cc0f 100644 --- a/cmd/rebalstatus_string.go +++ b/cmd/rebalstatus_string.go @@ -20,7 +20,7 @@ const _rebalStatus_name = "NoneStartedCompletedStoppedFailed" var _rebalStatus_index = [...]uint8{0, 4, 11, 20, 27, 33} func (i rebalStatus) String() string { - if i >= rebalStatus(len(_rebalStatus_index)-1) { + if i < 0 || i >= rebalStatus(len(_rebalStatus_index)-1) { return "rebalStatus(" + strconv.FormatInt(int64(i), 10) + ")" } return _rebalStatus_name[_rebalStatus_index[i]:_rebalStatus_index[i+1]] diff --git a/cmd/scannermetric_string.go b/cmd/scannermetric_string.go index 32c7a4f891ca8..209e8fad87de0 100644 --- a/cmd/scannermetric_string.go +++ b/cmd/scannermetric_string.go @@ -37,7 +37,7 @@ const _scannerMetric_name = "ReadMetadataCheckMissingSaveUsageApplyAllApplyVersi var _scannerMetric_index = [...]uint8{0, 12, 24, 33, 41, 53, 65, 74, 77, 93, 98, 112, 127, 147, 157, 167, 186, 198, 208, 217, 232, 245, 249} func (i scannerMetric) String() string { - if i >= scannerMetric(len(_scannerMetric_index)-1) { + if i < 0 || i >= scannerMetric(len(_scannerMetric_index)-1) { return "scannerMetric(" + strconv.FormatInt(int64(i), 10) + ")" } return _scannerMetric_name[_scannerMetric_index[i]:_scannerMetric_index[i+1]] diff --git a/cmd/server-startup-msg.go b/cmd/server-startup-msg.go index ce98d0086b96c..75fb4403c4e33 100644 --- a/cmd/server-startup-msg.go +++ b/cmd/server-startup-msg.go @@ -152,11 +152,12 @@ func printLambdaTargets() { return } - arnMsg := color.Blue("Object Lambda ARNs: ") + var arnMsg strings.Builder + arnMsg.WriteString(color.Blue("Object Lambda ARNs: ")) for _, arn := range globalLambdaTargetList.List(globalSite.Region()) { - arnMsg += color.Bold(fmt.Sprintf("%s ", arn)) + arnMsg.WriteString(color.Bold(fmt.Sprintf("%s ", arn))) } - logger.Startup(arnMsg + "\n") + logger.Startup(arnMsg.String() + "\n") } // Prints bucket notification configurations. diff --git a/cmd/sftp-server-driver.go b/cmd/sftp-server-driver.go index 3ce7c0b43adf1..5a0e2662cadfe 100644 --- a/cmd/sftp-server-driver.go +++ b/cmd/sftp-server-driver.go @@ -285,8 +285,7 @@ func (f *sftpDriver) Filewrite(r *sftp.Request) (w io.WriterAt, err error) { r: pr, wg: &sync.WaitGroup{}, } - wa.wg.Add(1) - go func() { + wa.wg.Go(func() { oi, err := clnt.PutObject(r.Context(), bucket, object, pr, -1, minio.PutObjectOptions{ ContentType: mimedb.TypeByExtension(path.Ext(object)), DisableContentSha256: true, @@ -294,8 +293,7 @@ func (f *sftpDriver) Filewrite(r *sftp.Request) (w io.WriterAt, err error) { }) stopFn(oi.Size, err) pr.CloseWithError(err) - wa.wg.Done() - }() + }) return wa, nil } diff --git a/cmd/signature-v2.go b/cmd/signature-v2.go index 1fd42ba70233b..d494f611c6559 100644 --- a/cmd/signature-v2.go +++ b/cmd/signature-v2.go @@ -347,13 +347,7 @@ func canonicalizedResourceV2(encodedResource, encodedQuery string) string { queries := strings.Split(encodedQuery, "&") keyval := make(map[string]string) for _, query := range queries { - key := query - val := "" - index := strings.Index(query, "=") - if index != -1 { - key = query[:index] - val = query[index+1:] - } + key, val, _ := strings.Cut(query, "=") keyval[key] = val } diff --git a/cmd/site-replication-utils.go b/cmd/site-replication-utils.go index 192275845d97b..1618f1767cf20 100644 --- a/cmd/site-replication-utils.go +++ b/cmd/site-replication-utils.go @@ -177,11 +177,9 @@ func (sm *siteResyncMetrics) save(ctx context.Context) { } rs.LastSaved = UTCNow() sm.peerResyncMap[dID] = rs - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { saveSiteResyncMetadata(ctx, st, newObjectLayerFn()) - }() + }) } } wg.Wait() diff --git a/cmd/storage-rest-server.go b/cmd/storage-rest-server.go index d7ee11493ff03..940aececdf49b 100644 --- a/cmd/storage-rest-server.go +++ b/cmd/storage-rest-server.go @@ -254,15 +254,13 @@ func (s *storageRESTServer) NSScannerHandler(ctx context.Context, params *nsScan // Collect updates, stream them before the full cache is sent. updates := make(chan dataUsageEntry, 1) var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for update := range updates { resp := storageNSScannerRPC.NewResponse() resp.Update = &update out <- resp } - }() + }) ui, err := s.getStorage().NSScanner(ctx, *params.Cache, updates, madmin.HealScanMode(params.ScanMode), nil) wg.Wait() if err != nil { @@ -543,6 +541,14 @@ func (s *storageRESTServer) ReadPartsHandler(w http.ResponseWriter, r *http.Requ return } + // Reject path traversal smuggled through msgpack body (CVE-2026-42600). + for _, p := range preq.Paths { + if hasBadPathComponent(p) { + s.writeErrorResponse(w, errInvalidArgument) + return + } + } + done := keepHTTPResponseAlive(w) infos, err := s.getStorage().ReadParts(r.Context(), volume, preq.Paths...) done(nil) @@ -1278,6 +1284,14 @@ func (s *storageRESTServer) DeleteBulkHandler(w http.ResponseWriter, r *http.Req return } + // Reject path traversal smuggled through msgpack body (CVE-2026-42600). + for _, p := range req.Paths { + if hasBadPathComponent(p) { + s.writeErrorResponse(w, errInvalidArgument) + return + } + } + volume := r.Form.Get(storageRESTVolume) keepHTTPResponseAlive(w)(s.getStorage().DeleteBulk(r.Context(), volume, req.Paths...)) } diff --git a/cmd/storage-rest_test.go b/cmd/storage-rest_test.go index a601d7996a1d0..3f95e7c0f1b01 100644 --- a/cmd/storage-rest_test.go +++ b/cmd/storage-rest_test.go @@ -411,3 +411,26 @@ func TestStorageRESTClientRenameFile(t *testing.T) { testStorageAPIRenameFile(t, restClient) } + +// TestStorageRESTClientPathTraversal verifies that ReadMultiple, ReadParts, and +// DeleteBulk all reject ".." traversal sequences smuggled in the msgpack body +// (CVE-2026-42600). The global setRequestValidityMiddleware only inspects +// r.URL.Path and form values, so without handler-level checks a caller holding +// the cluster root JWT could escape the configured drive root. +func TestStorageRESTClientPathTraversal(t *testing.T) { + restClient := newStorageRESTHTTPServerClient(t) + + t.Run("ReadParts", func(t *testing.T) { + _, err := restClient.ReadParts(t.Context(), "foo", "../etc/passwd") + if err == nil { + t.Fatal("expected error for traversal in ReadParts paths, got nil") + } + }) + + t.Run("DeleteBulk", func(t *testing.T) { + err := restClient.DeleteBulk(t.Context(), "foo", "../etc/shadow") + if err == nil { + t.Fatal("expected error for traversal in DeleteBulk paths, got nil") + } + }) +} diff --git a/cmd/storagemetric_string.go b/cmd/storagemetric_string.go index 21fa89e1c3567..957d48b239fc5 100644 --- a/cmd/storagemetric_string.go +++ b/cmd/storagemetric_string.go @@ -46,7 +46,7 @@ const _storageMetric_name = "MakeVolBulkMakeVolListVolsStatVolDeleteVolWalkDirLi var _storageMetric_index = [...]uint16{0, 11, 18, 26, 33, 42, 49, 56, 64, 74, 84, 98, 108, 118, 128, 134, 148, 158, 166, 179, 192, 206, 217, 223, 230, 242, 262, 270, 280, 290, 299, 303} func (i storageMetric) String() string { - if i >= storageMetric(len(_storageMetric_index)-1) { + if i < 0 || i >= storageMetric(len(_storageMetric_index)-1) { return "storageMetric(" + strconv.FormatInt(int64(i), 10) + ")" } return _storageMetric_name[_storageMetric_index[i]:_storageMetric_index[i+1]] diff --git a/cmd/warm-backend-azure.go b/cmd/warm-backend-azure.go index bb087e749cca8..3ad5121207eda 100644 --- a/cmd/warm-backend-azure.go +++ b/cmd/warm-backend-azure.go @@ -26,7 +26,6 @@ import ( "strings" "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" @@ -63,7 +62,7 @@ func (az *warmBackendAzure) getDest(object string) string { func (az *warmBackendAzure) PutWithMeta(ctx context.Context, object string, r io.Reader, length int64, meta map[string]string) (remoteVersionID, error) { azMeta := map[string]*string{} for k, v := range meta { - azMeta[k] = to.Ptr(v) + azMeta[k] = new(v) } resp, err := az.clnt.UploadStream(ctx, az.Bucket, az.getDest(object), io.LimitReader(r, length), &azblob.UploadStreamOptions{ Concurrency: 4, diff --git a/cmd/xl-storage-format-v2_string.go b/cmd/xl-storage-format-v2_string.go index 61959f85d414b..622e878d277c2 100644 --- a/cmd/xl-storage-format-v2_string.go +++ b/cmd/xl-storage-format-v2_string.go @@ -20,7 +20,7 @@ const _VersionType_name = "invalidVersionTypeObjectTypeDeleteTypeLegacyTypelastV var _VersionType_index = [...]uint8{0, 18, 28, 38, 48, 63} func (i VersionType) String() string { - if i >= VersionType(len(_VersionType_index)-1) { + if i < 0 || i >= VersionType(len(_VersionType_index)-1) { return "VersionType(" + strconv.FormatInt(int64(i), 10) + ")" } return _VersionType_name[_VersionType_index[i]:_VersionType_index[i+1]] @@ -39,7 +39,7 @@ const _ErasureAlgo_name = "invalidErasureAlgoReedSolomonlastErasureAlgo" var _ErasureAlgo_index = [...]uint8{0, 18, 29, 44} func (i ErasureAlgo) String() string { - if i >= ErasureAlgo(len(_ErasureAlgo_index)-1) { + if i < 0 || i >= ErasureAlgo(len(_ErasureAlgo_index)-1) { return "ErasureAlgo(" + strconv.FormatInt(int64(i), 10) + ")" } return _ErasureAlgo_name[_ErasureAlgo_index[i]:_ErasureAlgo_index[i+1]] diff --git a/docs/debugging/inspect/go.mod b/docs/debugging/inspect/go.mod index a9e37e2f482a5..a892683a003e1 100644 --- a/docs/debugging/inspect/go.mod +++ b/docs/debugging/inspect/go.mod @@ -1,6 +1,6 @@ module github.com/minio/minio/docs/debugging/inspect -go 1.23.0 +go 1.24.0 toolchain go1.24.8 @@ -20,6 +20,6 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/pkg/v3 v3.0.28 // indirect github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/sys v0.30.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/sys v0.38.0 // indirect ) diff --git a/docs/debugging/inspect/go.sum b/docs/debugging/inspect/go.sum index 7bdafc1efff3d..7750d63ad613d 100644 --- a/docs/debugging/inspect/go.sum +++ b/docs/debugging/inspect/go.sum @@ -24,13 +24,13 @@ github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po= github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/docs/debugging/s3-verify/go.mod b/docs/debugging/s3-verify/go.mod index 37426446d5c8e..d673192d3c033 100644 --- a/docs/debugging/s3-verify/go.mod +++ b/docs/debugging/s3-verify/go.mod @@ -1,6 +1,6 @@ module github.com/minio/minio/docs/debugging/s3-verify -go 1.23.0 +go 1.24.0 toolchain go1.24.8 @@ -17,9 +17,9 @@ require ( github.com/minio/md5-simd v1.1.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/xid v1.6.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/docs/debugging/s3-verify/go.sum b/docs/debugging/s3-verify/go.sum index c8926fa12e8bd..e01f6791bc471 100644 --- a/docs/debugging/s3-verify/go.sum +++ b/docs/debugging/s3-verify/go.sum @@ -25,12 +25,16 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/docs/resiliency/docker-compose.yaml b/docs/resiliency/docker-compose.yaml index 842d766a144d2..aebb15fedbb83 100644 --- a/docs/resiliency/docker-compose.yaml +++ b/docs/resiliency/docker-compose.yaml @@ -80,10 +80,14 @@ services: - "9000:9000" - "9001:9001" depends_on: - - minio1 - - minio2 - - minio3 - - minio4 + minio1: + condition: service_healthy + minio2: + condition: service_healthy + minio3: + condition: service_healthy + minio4: + condition: service_healthy ## By default this config uses default local driver, ## For custom volumes replace with volume driver configuration. diff --git a/internal/arn/arn.go b/internal/arn/arn.go index 4f40748c715e5..b7e995c0655d0 100644 --- a/internal/arn/arn.go +++ b/internal/arn/arn.go @@ -50,7 +50,7 @@ type ARN struct { // Allows english letters, numbers, '.', '-', '_' and '/'. Starts with a // letter or digit. At least 1 character long. -var validResourceIDRegex = regexp.MustCompile(`[A-Za-z0-9_/\.-]+$`) +var validResourceIDRegex = regexp.MustCompile(`[A-Za-z0-9_./-]+$`) // NewIAMRoleARN - returns an ARN for a role in MinIO. func NewIAMRoleARN(resourceID, serverRegion string) (ARN, error) { diff --git a/internal/deadlineconn/deadlineconn_test.go b/internal/deadlineconn/deadlineconn_test.go index 6921e47b1e476..669289328d089 100644 --- a/internal/deadlineconn/deadlineconn_test.go +++ b/internal/deadlineconn/deadlineconn_test.go @@ -42,10 +42,7 @@ func TestBuffConnReadTimeout(t *testing.T) { } var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - + wg.Go(func() { tcpConn, terr := tcpListener.AcceptTCP() if terr != nil { t.Errorf("failed to accept new connection. %v", terr) @@ -89,7 +86,7 @@ func TestBuffConnReadTimeout(t *testing.T) { t.Errorf("failed to write to client. %v", terr) return } - }() + }) c, err := net.Dial("tcp", serverAddr) if err != nil { @@ -132,10 +129,7 @@ func TestBuffConnReadCheckTimeout(t *testing.T) { } var cerr error var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - + wg.Go(func() { tcpConn, terr := tcpListener.AcceptTCP() if terr != nil { cerr = fmt.Errorf("failed to accept new connection. %v", terr) @@ -171,7 +165,7 @@ func TestBuffConnReadCheckTimeout(t *testing.T) { cerr = fmt.Errorf("could read from client, expected error, got %v", terr) return } - }() + }) c, err := net.Dial("tcp", serverAddr) if err != nil { diff --git a/internal/grid/grid_test.go b/internal/grid/grid_test.go index 54002c38ba1d5..b6fab68c9e3cc 100644 --- a/internal/grid/grid_test.go +++ b/internal/grid/grid_test.go @@ -242,7 +242,7 @@ func TestSingleRoundtripGenerics(t *testing.T) { t.Errorf("want error %v(%T), got %v(%T)", RemoteErr(testPayload), RemoteErr(testPayload), err, err) } if resp != nil { - t.Errorf("want nil, got %#v", resp) + t.Errorf("want nil, got %v", resp) } h2.PutResponse(resp) t.Log("Roundtrip:", time.Since(start)) diff --git a/internal/logger/target/loggertypes/targettype_string.go b/internal/logger/target/loggertypes/targettype_string.go index 715a9fef142aa..08ea3f2efcd83 100644 --- a/internal/logger/target/loggertypes/targettype_string.go +++ b/internal/logger/target/loggertypes/targettype_string.go @@ -19,7 +19,7 @@ var _TargetType_index = [...]uint8{0, 7, 11, 16} func (i TargetType) String() string { i -= 1 - if i >= TargetType(len(_TargetType_index)-1) { + if i < 0 || i >= TargetType(len(_TargetType_index)-1) { return "TargetType(" + strconv.FormatInt(int64(i+1), 10) + ")" } return _TargetType_name[_TargetType_index[i]:_TargetType_index[i+1]] diff --git a/internal/logger/target/testlogger/testlogger.go b/internal/logger/target/testlogger/testlogger.go index 68f0f82dd7ddb..9cbac7a4f805c 100644 --- a/internal/logger/target/testlogger/testlogger.go +++ b/internal/logger/target/testlogger/testlogger.go @@ -150,14 +150,15 @@ func (t *testLogger) Send(ctx context.Context, entry any) error { if v.Trace == nil { logf("%s: %s", v.Level, v.Message) } else { - msg := fmt.Sprintf("%s: %+v", v.Level, v.Trace.Message) + var msg strings.Builder + msg.WriteString(fmt.Sprintf("%s: %+v", v.Level, v.Trace.Message)) for i, m := range v.Trace.Source { if i == 0 && strings.Contains(m, "logger.go:") { continue } - msg += fmt.Sprintf("\n%s", m) + msg.WriteString(fmt.Sprintf("\n%s", m)) } - logf("%s", msg) + logf("%s", msg.String()) } default: logf("%+v (%T)", v, v) diff --git a/internal/s3select/csv/reader_contrib_test.go b/internal/s3select/csv/reader_contrib_test.go index f2262f5e83e1e..247c54ed8a637 100644 --- a/internal/s3select/csv/reader_contrib_test.go +++ b/internal/s3select/csv/reader_contrib_test.go @@ -540,7 +540,7 @@ func BenchmarkReaderHuge(b *testing.B) { for n := range 11 { f := openTestFile(b, "nyc-taxi-data-100k.csv") want := 309 - for i := 0; i < n; i++ { + for range n { f = append(f, f...) want *= 2 } diff --git a/internal/s3select/select.go b/internal/s3select/select.go index 2bd7bab91f504..2cc227a169eba 100644 --- a/internal/s3select/select.go +++ b/internal/s3select/select.go @@ -437,6 +437,7 @@ func (s3Select *S3Select) Open(rsc io.ReadSeekCloser) error { if strings.EqualFold(s3Select.Input.JSONArgs.ContentType, "lines") { // PReader enforces the S3 Select per-record size limit while splitting lines. + //TODO: add simdj.NewReader s3Select.recordReader = json.NewPReader(s3Select.progressReader, &s3Select.Input.JSONArgs) } else { // Document mode.