Show Notes

120 - Another Kernel TIPC Bug, MySQL, and Buggy Go

The first issue, is an incorrect computation in golang impacting go-ethereum. Its an interesting case, because a base computation might lead to some issues but it usually isn’t a security issue. Being in go-ethereum and really I think any sort of VM implementation it can have some significant impacts as the VM would become desynchronized from the rest of the ecosystem.

The issue comes with using copy(dst, src) when dst and src overlap. This would be an obvious bug in many use cases the reaching of that copy was a bit non-intuitive. Starting with calling a contract that is built in to go-ethereum that is implemented by dataCopy. It then uses scope.Memory.Set(offset, size, value) with a contract/attacker controlled offset and size to write the ret. This can lead to the copy over part of the memory ret points to. I’d recommend taking a look at the code in the article for a better walkthrough.

The second issue is a bit more interest, and has to do with when anonymous functions capture the variables from the parent scope. Basically, they demonstrate a case where a function is created inside a for-loop. The developer intending to capture the k value from the range used in the loop.

for _, k := range keys {
    m[k] = true
    cleanupFs = append(cleanupFs, func() {
        fmt.Println("deleting", k)
        delete(m, k)
    })
}

The intent being to call delete(m,k) inside the cleanup function. What happens though is the value of k refers to the parent scope, which means all the functions created in the loop point to the same k value. Its an interesting, and rather non-intuitive case that you should be on the look out for. I could see this popping up in real code, though they do not demonstrate it.

A remotely reachable stack-based buffer overflow in the Linux Kernel’s TIPC module due to a not performing a bounds check in an edge case.

While ultimately the issue is due to a missing bounds check, the code is actually careful to ensure it allocates enough space for the backing buffer, there are several sanity checks at the start of tipc_mon_rcv:

  • Ensures the data length is atleast enough to hold an empty record
  • Ensures the length matches the expected length for the given number of internal members
  • Ensures the length matches the internal len field

Later, when it stores the record, if its replacing an old one it’ll check the previous record’s length and reallocate a larger one if necessary. The problem is that when updating the record, if there was a previous one, it’ll copy that old one into a stack local variaible dom_bef. The variable is allocated to hold the maximum number of possible internal members (MAX_MON_DOMAIN). The problem is that when allocating the record in the first place that value is never considered. So you can send a record that contains more internal members than the maximum value, and later when it gets replaced, the memcpy into that stack variable will overflow.