Skip to content

Commit

Permalink
chore: std.GetCaller
Browse files Browse the repository at this point in the history
  • Loading branch information
albttx committed Mar 28, 2023
1 parent 1a849dc commit 7eae128
Show file tree
Hide file tree
Showing 11 changed files with 334 additions and 1 deletion.
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

0 comments on commit 7eae128

Please sign in to comment.