Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: errorCString can be used to read arbitrary memory #7084

Closed
ianlancetaylor opened this issue Jan 9, 2014 · 5 comments
Closed

runtime: errorCString can be used to read arbitrary memory #7084

ianlancetaylor opened this issue Jan 9, 2014 · 5 comments
Milestone

Comments

@ianlancetaylor
Copy link
Contributor

This cute little program demonstrates how to use runtime.errorCString to read arbitrary
contents of memory.  The key is that errorCString has a public method that does an
unsafe operation, and that errorCString is a uintptr so once one has a copy of an
errorCString value, one can use reflect to produce an errorCString with any value you
like.

This doesn't let you do anything you can't already do by importing unsafe, but it does
let you do it without, well, importing unsafe.  We should fix errorCString to prevent
this.

package main

import (
    "fmt"
    "reflect"
)

// Display a hex dump of myself! Without using the unsafe module!
// All we need is a C-string backed error object...
func memwalk(e error) {
    var addr uint64 = 0x400000 // Or use reflect.ValueOf(e).Uint() to start at e...
    mutableValue := reflect.New(reflect.ValueOf(e).Type()).Elem()
    for {
        fmt.Printf("%016x: ", addr)
        var i uint64
        for i = 0; i <= 0xF; i++ {
            mutableValue.SetUint(addr + i)
            s := mutableValue.Interface().(error).Error()
            var b uint8 = 0
            if len(s) > 15 {
                b = s[15]
            }
            fmt.Printf("%02x ", b)
        }
        fmt.Printf("| ")
        for i = 0; i <= 0xF; i++ {
            mutableValue.SetUint(addr + i)
            s := mutableValue.Interface().(error).Error()
            var b uint8 = 0
            if len(s) > 15 {
                b = s[15]
            }
            if b >= ' ' && b <= '~' {
                fmt.Printf("%c", b)
            } else {
                fmt.Print(".")
            }
        }
        fmt.Print("\n")
        addr += 0x10
    }
}

// The main program of the memory dumper.
func main() {
    defer func() {
        memwalk(recover().(error))
    }()
    // Produce a C string backed error somehow...
    c := make(chan int)
    close(c)
    c <- 42
}
@minux
Copy link
Member

minux commented Jan 9, 2014

Comment 1:

how about we change:
type errorCString uintptr
to
type errorCString struct { uintptr }
?

@ianlancetaylor
Copy link
Contributor Author

Comment 2:

Yes, I'm about to send out a change along those lines.

@ianlancetaylor
Copy link
Contributor Author

Comment 3:

This issue was closed by revision 7e639c0.

Status changed to Fixed.

@rsc
Copy link
Contributor

rsc commented Feb 14, 2014

Comment 4:

I'm not convinced this matters for Go 1.2.1. It's easy to avoid - don't use errorCString
that way.

@rsc
Copy link
Contributor

rsc commented Feb 16, 2014

Comment 5:

Labels changed: added release-go1.3, removed release-go1.2.1.

@rsc rsc added this to the Go1.3 milestone Apr 14, 2015
@rsc rsc removed the release-go1.3 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 25, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants