Skip to content

Commit

Permalink
fix potential crash in unixfs directory (#798)
Browse files Browse the repository at this point in the history
Fix potential crash in sizeBelowThreshold when modifying children in a directory.

Closes #675
  • Loading branch information
gammazero authored Jan 21, 2025
1 parent bcf475c commit afe6e24
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The following emojis are used to highlight certain changes:

- `gateway` Fix redirect URLs for subdirectories with characters that need escaping. [#779](https://github.com/ipfs/boxo/pull/779)
- `ipns` Fix `ipns` protobuf namespace conflicts by using full package name `github.com/ipfs/boxo/ipns/pb/record.proto` instead of the generic `record.proto` [#794](https://github.com/ipfs/boxo/pull/794)
- `unixfs` Fix possible crash when modifying directory [#798](https://github.com/ipfs/boxo/pull/798)

### Security

Expand Down
29 changes: 21 additions & 8 deletions ipld/unixfs/io/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,33 +489,46 @@ func (d *HAMTDirectory) needsToSwitchToBasicDir(ctx context.Context, name string
// until we either reach a value above the threshold (in that case no need
// to keep counting) or an error occurs (like the context being canceled
// if we take too much time fetching the necessary shards).
func (d *HAMTDirectory) sizeBelowThreshold(ctx context.Context, sizeChange int) (below bool, err error) {
func (d *HAMTDirectory) sizeBelowThreshold(ctx context.Context, sizeChange int) (bool, error) {
if HAMTShardingSize == 0 {
panic("asked to compute HAMT size with HAMTShardingSize option off (0)")
}

// We don't necessarily compute the full size of *all* shards as we might
// end early if we already know we're above the threshold or run out of time.
partialSize := 0
var err error
below := true

// We stop the enumeration once we have enough information and exit this function.
ctx, cancel := context.WithCancel(ctx)
defer cancel()
linkResults := d.EnumLinksAsync(ctx)

for linkResult := range d.EnumLinksAsync(ctx) {
for linkResult := range linkResults {
if linkResult.Err != nil {
return false, linkResult.Err
below = false
err = linkResult.Err
break
}

partialSize += linksize.LinkSizeFunction(linkResult.Link.Name, linkResult.Link.Cid)
if partialSize+sizeChange >= HAMTShardingSize {
// We have already fetched enough shards to assert we are
// above the threshold, so no need to keep fetching.
return false, nil
// We have already fetched enough shards to assert we are above the
// threshold, so no need to keep fetching.
below = false
break
}
}
cancel()

// We enumerated *all* links in all shards and didn't reach the threshold.
if !below {
// Wait for channel to close so links are not being read after return.
for range linkResults {
}
return false, err
}

// Enumerated all links in all shards before threshold reached.
return true, nil
}

Expand Down

0 comments on commit afe6e24

Please sign in to comment.