←back to thread

182 points yarapavan | 1 comments | | HN request time: 0s | source
Show context
amiga386 ◴[] No.43615234[source]
A lovely article, but one section definitely needs a [citation needed]

> (OpenSSL is written in C, so this mistake was incredibly easy to make and miss; in a memory-safe language with proper bounds checking, it would have been nearly impossible.)

    package main

    import "fmt"

    type CmdType int

    const (
        WriteMsg CmdType = iota
        ReadMsg
    )

    type Cmd struct {
        t CmdType
        d []byte
        l int
    }

    var buffer [256]byte

    var cmds = []Cmd{
        Cmd{WriteMsg, []byte("Rain. And a little ice. It's a damn good thing he doesn't know how much I hate his guts."), 88},
        Cmd{WriteMsg, []byte("Rain. And a little ice."), 23},
        Cmd{ReadMsg, nil, 23},
        Cmd{ReadMsg, nil, 88}, // oops!
    }

    func main() {
        for c := range cmds {
            if cmds[c].t == WriteMsg {
                copy(buffer[:], cmds[c].d[:cmds[c].l])
            } else if cmds[c].t == ReadMsg {
                fmt.Println(string(buffer[:cmds[c].l]))
            }
        }
    }
The heartbleed problem was that user-controlled input could say how long it was, separate from how long it actually was. OpenSSL then copied the (short) thing into a buffer, but returned the (long) thing, thus revealing all sorts of other data it was keeping in the same buffer.

It wasn't caught because OpenSSL had built its own buffer/memory management routines on top of the actual ones provided by the language (malloc, memcpy, realloc, free), and all sorts of unsafe manipulations were happening inside one big buffer. That buffer could be in a language with perfect memory safety, the same flaw would still be there.

replies(1): >>43615631 #
1. ◴[] No.43615631[source]