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

Add individual program length checks into updateApplication #2699

Merged
Merged
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
15 changes: 11 additions & 4 deletions ledger/apply/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,17 @@ func updateApplication(ac *transactions.ApplicationCallTxnFields, balances Balan
proto := balances.ConsensusParams()
// when proto.EnableExtraPageOnAppUpdate is false, WellFormed rejects all updates with a multiple-page program
if proto.EnableExtraPagesOnAppUpdate {
allowed := int(1+params.ExtraProgramPages) * proto.MaxAppTotalProgramLen
actual := len(ac.ApprovalProgram) + len(ac.ClearStateProgram)
if actual > allowed {
return fmt.Errorf("updateApplication app programs too long, %d. max total len %d bytes", actual, allowed)
lap := len(ac.ApprovalProgram)
lcs := len(ac.ClearStateProgram)
pages := int(1 + params.ExtraProgramPages)
if lap > pages*proto.MaxAppProgramLen {
return fmt.Errorf("updateApplication approval program too long. max len %d bytes", pages*proto.MaxAppProgramLen)
}
if lcs > pages*proto.MaxAppProgramLen {
return fmt.Errorf("updateApplication clear state program too long. max len %d bytes", pages*proto.MaxAppProgramLen)
}
if lap+lcs > pages*proto.MaxAppTotalProgramLen {
return fmt.Errorf("updateApplication app programs too long, %d. max total len %d bytes", lap+lcs, pages*proto.MaxAppTotalProgramLen)
}
}

Expand Down
70 changes: 45 additions & 25 deletions ledger/apply/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ func (b *testBalances) SetProto(name protocol.ConsensusVersion) {
b.proto = config.Consensus[name]
}

func (b *testBalances) SetParams(params config.ConsensusParams) {
b.proto = params
}

type testEvaluator struct {
pass bool
delta basics.EvalDelta
Expand Down Expand Up @@ -984,19 +988,12 @@ func TestAppCallApplyUpdate(t *testing.T) {
a.Equal([]byte{2}, br.AppParams[appIdx].ClearStateProgram)
a.Equal(basics.EvalDelta{}, ad.EvalDelta)

// check app program len
appr := make([]byte, 6050)
//check program len check happens in future consensus proto version
b.SetProto(protocol.ConsensusFuture)
proto = b.ConsensusParams()
ep.Proto = &proto

for i := range appr {
appr[i] = 2
}
appr[0] = 4
ac = transactions.ApplicationCallTxnFields{
ApplicationID: appIdx,
OnCompletion: transactions.UpdateApplicationOC,
ApprovalProgram: appr,
ClearStateProgram: []byte{2},
}
// check app program len
params = basics.AppParams{
ApprovalProgram: []byte{1},
StateSchemas: basics.StateSchemas{
Expand All @@ -1018,22 +1015,34 @@ func TestAppCallApplyUpdate(t *testing.T) {
b.balances[creator] = cp
b.appCreators = map[basics.AppIndex]basics.Address{appIdx: creator}

//check program len check happens in future consensus proto version
b.SetProto(protocol.ConsensusFuture)
proto = b.ConsensusParams()
ep.Proto = &proto

b.pass = true
err = ApplicationCall(ac, h, &b, ad, &ep, txnCounter)
a.Error(err)
a.Contains(err.Error(), "updateApplication app programs too long")

// check extraProgramPages is used
appr = make([]byte, 3072)
appr := make([]byte, 2*proto.MaxAppProgramLen+1)
appr[0] = 4 // version 4

var tests = []struct {
name string
approval []byte
clear []byte
}{
{"approval", appr, []byte{2}},
{"clear state", []byte{2}, appr},
}
for _, test := range tests {
ac = transactions.ApplicationCallTxnFields{
ApplicationID: appIdx,
OnCompletion: transactions.UpdateApplicationOC,
ApprovalProgram: test.approval,
ClearStateProgram: test.clear,
}

for i := range appr {
appr[i] = 2
b.pass = true
err = ApplicationCall(ac, h, &b, ad, &ep, txnCounter)
a.Error(err)
a.Contains(err.Error(), fmt.Sprintf("updateApplication %s program too long", test.name))
}

// check extraProgramPages allows length of proto.MaxAppProgramLen + 1
appr = make([]byte, proto.MaxAppProgramLen+1)
appr[0] = 4
ac = transactions.ApplicationCallTxnFields{
ApplicationID: appIdx,
Expand All @@ -1045,6 +1054,17 @@ func TestAppCallApplyUpdate(t *testing.T) {
err = ApplicationCall(ac, h, &b, ad, &ep, txnCounter)
a.NoError(err)

// check extraProgramPages is used and long sum rejected
ac = transactions.ApplicationCallTxnFields{
ApplicationID: appIdx,
OnCompletion: transactions.UpdateApplicationOC,
ApprovalProgram: appr,
ClearStateProgram: appr,
}
b.pass = true
err = ApplicationCall(ac, h, &b, ad, &ep, txnCounter)
a.Error(err)
a.Contains(err.Error(), "updateApplication app programs too long")
}

func TestAppCallApplyDelete(t *testing.T) {
Expand Down