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

Draft: chore: std.GetCaller #666

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions examples/gno.land/p/demo/tests/tests.gno
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,17 @@ func ModifyTestRealmObject2b() {
func ModifyTestRealmObject2c() {
SomeValue3.Field = "modified"
}

func GetCaller() std.Address {
return std.GetCaller()
}

func PrintCallers() {
println("p/TEST : ORIGCALL:", std.GetOrigCaller())
println("p/TEST : PKG ADDR:", std.GetOrigPkgAddr())
println("p/TEST : CALLER :", std.GetCaller())
}

func Exec(fn func()) {
fn()
}
111 changes: 111 additions & 0 deletions examples/gno.land/r/demo/tests/fake20/fake20.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package fake20

import (
"std"
"strings"

"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/users"
)

var (
foo *grc20.AdminToken
admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // TODO: helper to change admin
)

func init() {
foo = grc20.NewAdminToken("Fake", "FAKE", 4)
foo.Mint(admin, 1000000*10000) // @administrator (1M)
foo.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k)
}

// method proxies as public functions.
//

// getters.

func TotalSupply() uint64 {
return foo.TotalSupply()
}

func BalanceOf(owner users.AddressOrName) uint64 {
balance, err := foo.BalanceOf(owner.Resolve())
if err != nil {
panic(err)
}
return balance
}

func Allowance(owner, spender users.AddressOrName) uint64 {
allowance, err := foo.Allowance(owner.Resolve(), spender.Resolve())
if err != nil {
panic(err)
}
return allowance
}

// setters.

func Transfer(to users.AddressOrName, amount uint64) {
caller := std.GetCaller()
foo.Transfer(caller, to.Resolve(), amount)
}

func Approve(spender users.AddressOrName, amount uint64) {
caller := std.GetCaller()
foo.Approve(caller, spender.Resolve(), amount)
}

func TransferFrom(from, to users.AddressOrName, amount uint64) {
caller := std.GetCaller()
foo.TransferFrom(caller, from.Resolve(), to.Resolve(), amount)
}

// faucet.

func Faucet() {
// FIXME: add limits?
// FIXME: add payment in gnot?
caller := std.GetCaller()
foo.Mint(caller, 1000*10000) // 1k
}

// administration.

func Mint(address users.AddressOrName, amount uint64) {
caller := std.GetCaller()
assertIsAdmin(caller)
foo.Mint(address.Resolve(), amount)
}

func Burn(address users.AddressOrName, amount uint64) {
caller := std.GetCaller()
assertIsAdmin(caller)
foo.Burn(address.Resolve(), amount)
}

// render.
//

func Render(path string) string {
parts := strings.Split(path, "/")
c := len(parts)

switch {
case path == "":
return foo.RenderHome()
case c == 2 && parts[0] == "balance":
owner := users.AddressOrName(parts[1])
balance, _ := foo.BalanceOf(owner.Resolve())
return ufmt.Sprintf("%d\n", balance)
default:
return "404\n"
}
}

func assertIsAdmin(address std.Address) {
if address != admin {
panic("restricted access")
}
}
4 changes: 4 additions & 0 deletions examples/gno.land/r/demo/tests/phishing/phishing.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package phising

func GetMillionaire() {
}
17 changes: 17 additions & 0 deletions examples/gno.land/r/demo/tests/subtests/subtests.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package subtests

import (
"std"
)

func CurrentRealmPath() string {
return std.CurrentRealmPath()
}

func GetCaller() std.Address {
return std.GetCaller()
}

func Exec(fn func()) {
fn()
}
30 changes: 29 additions & 1 deletion examples/gno.land/r/demo/tests/tests.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package tests

import "std"
import (
"std"

"gno.land/r/demo/tests/subtests"
)

func CurrentRealmPath() string {
return std.CurrentRealmPath()
Expand Down Expand Up @@ -51,3 +55,27 @@ func ModTestNodes() {
func PrintTestNodes() {
println(gTestNode2.Child.Name)
}

func GetCaller() std.Address {
return std.GetCaller()
}

func GetSubtestsCaller() std.Address {
return subtests.GetCaller()
}

func ExecFromTest() {
Exec(func() {
println("ExecFromTest", std.GetCaller())
})
}

func Exec(fn func()) {
fn()
}

func PrintCallers() {
println("p/TEST : ORIGCALL:", std.GetOrigCaller())
println("p/TEST : PKG ADDR:", std.GetOrigPkgAddr())
println("p/TEST : CALLER :", std.GetCaller())
}
44 changes: 44 additions & 0 deletions examples/gno.land/r/demo/tests/unsaferealm/unsaferealm.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package unsaferealm

import (
"std"

"gno.land/p/demo/grc/grc20"
)

var foo *grc20.AdminToken

func init() {
foo = grc20.NewAdminToken("Fake", "FAKE", 4)

// std.TestDerivePkgAddr("gno.land/r/demo/tests/unsaferealm")
foo.Mint("g1lpnflsxpr84dsqkznw85yd5wdzenkj89vsptmf", 1000000*10000)
// foo.Mint(std.GetOrigPkgAddr(), 1000000*10000)
}

/*
** Some grc20 functions
*/

func BalanceOf(owner std.Address) uint64 {
balance, err := foo.BalanceOf(owner)
if err != nil {
panic(err)
}

return balance
}

func Transfer(to std.Address, amount uint64) {
caller := std.GetCaller()
println("transfering", amount, "from:", caller, "to:", to)
foo.Transfer(caller, to, amount)
}

/*
** Realm unsafe functions
*/

func Do(fn func()) {
fn()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package unsaferealm

import (
"testing"
)

func TestUnsafeRealm(t *testing.T) {
println("Hello")
}
2 changes: 2 additions & 0 deletions pkgs/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) {
SetNodeLocations(pn.PkgPath, string(fn.Name), fn)
fn.InitStaticBlock(fn, pn)
}

// NOTE: much of what follows is duplicated for a single *FileNode
// in the main Preprocess translation function. Keep synced.

Expand All @@ -41,6 +42,7 @@ func PredefineFileSet(store Store, pn *PackageNode, fset *FileSet) {
}
}
}

// Predefine all type decls decls.
for _, fn := range fset.Files {
for i := 0; i < len(fn.Decls); i++ {
Expand Down
33 changes: 33 additions & 0 deletions stdlibs/stdlibs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package stdlibs

import (
"fmt"
"math"
"reflect"
"strconv"
Expand Down Expand Up @@ -257,14 +258,46 @@ func InjectPackage(store gno.Store, pn *gno.PackageNode) {
m.PushValue(res0)
},
)
pn.DefineNative("GetCaller",
gno.Flds( // params
),
gno.Flds( // results
"", "Address",
),
func(m *gno.Machine) {
ctx := m.Context.(ExecContext)

lastCaller := ctx.OrigCaller

for i := m.NumFrames() - 1; i > 0; i-- {
frameA := m.Frames[i]
frameB := m.Frames[i-1]
if frameA.LastPackage.GetPkgAddr().String() != frameB.LastPackage.GetPkgAddr().String() {
lastCaller = frameB.LastPackage.GetPkgAddr().Bech32()
break
}
}

res0 := gno.Go2GnoValue(
m.Alloc,
m.Store,
reflect.ValueOf(lastCaller),
)
addrT := store.GetType(gno.DeclaredTypeID("std", "Address"))
res0.T = addrT
m.PushValue(res0)
},
)
pn.DefineNative("GetOrigPkgAddr",
gno.Flds( // params
),
gno.Flds( // results
"", "Address",
),
func(m *gno.Machine) {
fmt.Printf("GetOrigPkgAddr: %#v\n", m.Package)
ctx := m.Context.(ExecContext)

res0 := gno.Go2GnoValue(
m.Alloc,
m.Store,
Expand Down
46 changes: 46 additions & 0 deletions tests/files/zrealm_crossrealm11.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// PKGPATH: gno.land/r/crossrealm_test
package crossrealm_test

import (
"std"

ptests "gno.land/p/demo/tests"
rtests "gno.land/r/demo/tests"
)

func lol() {
println("HACK1", std.GetCaller())
println("HACK2", rtests.GetCaller())
}

func main() {
println(`[DEBUG]
user1.gno: g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm
crossrealm_test: g1vla5mffzum6060t99u4xhm8mnhgxr0sz4k574p
gno.land/r/demo/tests: g1gz4ycmx0s6ln2wdrsh4e00l9fsel2wskqa3snq
gno.land/p/demo/tests: g1lc7c8nv62nqyyhhxe88tpxx786gwq68prx3f6e
`)

println("user1.gno -> gno.land/r/crossrealm_test: caller:", std.GetCaller())
println("user1.gno -> gno.land/r/crossrealm_test -> gno.land/p/demo/tests: caller:", ptests.GetCaller())
println("user1.gno -> gno.land/r/crossrealm_test -> gno.land/r/demo/tests: caller:", rtests.GetCaller()) // crossrealm -> gno.land/r/demo/tests

rtests.Exec(func() {
println("r/EXEC1", std.GetCaller()) // ??
println("r/EXEC2", ptests.GetCaller()) // ??
})
rtests.Exec(lol)

ptests.Exec(func() {
println("p/EXEC1", std.GetCaller()) // ??
println("p/EXEC2", ptests.GetCaller()) // ??
})
ptests.Exec(lol)

println("3.c subtestsCaller", rtests.GetSubtestsCaller()) // gno.land/r/demo/tests -> gno.land/r/demo/tests/subtests
rtests.ExecFromTest()
println("4. main :", std.GetCaller())
}

// Output:
// struct{("modified" string)}
25 changes: 25 additions & 0 deletions tests/files/zrealm_crossrealm_exploit1_stdlibs.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// PKGPATH: gno.land/r/crossrealm_test
package crossrealm_test

import (
"std"

"gno.land/r/demo/tests"
"gno.land/r/demo/tests/unsaferealm"
)

func main() {
addr := std.GetCaller()
println("balance:", unsaferealm.BalanceOf(addr))

// Test to exploit from the Do function steal money from unsaferealm treasury
unsaferealm.Do(func() {
println("transfering", std.GetCaller())
unsaferealm.Transfer(addr, 100000)
})

println("balance:", unsaferealm.BalanceOf(addr))
}

// Output:
// N/A