Skip to content

Commit 9a4f02c

Browse files
committed
[FAB-2997] don't invoke some scc thru cc2cc
This is the second of three fixes required for FAB-2997 (described in the discussion for that jira item). In this change set we prevent security-sensitive system chaincodes from being invoked through cc2cc invocations. Change-Id: Ie1be16243b2ea29d31cbaa0b19b5f08e9b0c12cc Signed-off-by: Alessandro Sorniotti <[email protected]>
1 parent a3efa2c commit 9a4f02c

File tree

6 files changed

+102
-9
lines changed

6 files changed

+102
-9
lines changed

core/chaincode/exectransaction_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,60 @@ func TestChaincodeQueryChaincodeUsingInvoke(t *testing.T) {
14751475
theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec2})
14761476
}
14771477

1478+
// test that invoking a security-sensitive system chaincode fails
1479+
func TestChaincodeInvokesForbiddenSystemChaincode(t *testing.T) {
1480+
chainID := util.GetTestChainID()
1481+
1482+
lis, err := initPeer(chainID)
1483+
if err != nil {
1484+
t.Fail()
1485+
t.Logf("Error creating peer: %s", err)
1486+
}
1487+
1488+
defer finitPeer(lis, chainID)
1489+
1490+
var ctxt = context.Background()
1491+
1492+
var nextBlockNumber uint64
1493+
1494+
// Deploy second chaincode
1495+
url := "github.com/hyperledger/fabric/examples/chaincode/go/passthru"
1496+
1497+
cID := &pb.ChaincodeID{Name: "pthru", Path: url, Version: "0"}
1498+
f := "init"
1499+
args := util.ToChaincodeArgs(f)
1500+
1501+
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1502+
1503+
cccid := ccprovider.NewCCContext(chainID, "pthru", "0", "", false, nil, nil)
1504+
1505+
_, err = deploy(ctxt, cccid, spec, nextBlockNumber)
1506+
nextBlockNumber++
1507+
ccID := spec.ChaincodeId.Name
1508+
if err != nil {
1509+
t.Fail()
1510+
t.Logf("Error initializing chaincode %s(%s)", ccID, err)
1511+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1512+
return
1513+
}
1514+
1515+
time.Sleep(time.Second)
1516+
1517+
// send an invoke to pass thru to invoke "escc" system chaincode
1518+
// this should fail
1519+
args = util.ToChaincodeArgs("escc/"+chainID, "getid", chainID, "pthru")
1520+
1521+
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1522+
// Invoke chaincode
1523+
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber)
1524+
if err == nil {
1525+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1526+
t.Logf("invoking <%s> should have failed", ccID)
1527+
t.Fail()
1528+
return
1529+
}
1530+
}
1531+
14781532
// Test the execution of a chaincode that invokes system chaincode
14791533
// uses the "pthru" chaincode to query "lscc" for the "pthru" chaincode
14801534
func TestChaincodeInvokesSystemChaincode(t *testing.T) {

core/chaincode/handler.go

+20-8
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
"github.com/hyperledger/fabric/common/util"
3030
"github.com/hyperledger/fabric/core/common/ccprovider"
3131
"github.com/hyperledger/fabric/core/common/sysccprovider"
32-
ccintf "github.com/hyperledger/fabric/core/container/ccintf"
32+
"github.com/hyperledger/fabric/core/container/ccintf"
3333
"github.com/hyperledger/fabric/core/ledger"
3434
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
3535
"github.com/hyperledger/fabric/core/peer"
@@ -238,12 +238,20 @@ func (handler *Handler) deleteQueryIterator(txContext *transactionContext, txid
238238
}
239239

240240
// Check if the transactor is allow to call this chaincode on this channel
241-
func (handler *Handler) checkACL(signedProp *pb.SignedProposal, proposal *pb.Proposal, calledCC *ccParts) *pb.ChaincodeMessage {
242-
// TODO: Decide what to pass in to verify that this transactor can access this
243-
// channel (chID) and chaincode (ccID). Very likely we need the signedProposal
244-
// which contains the sig and creator cert
241+
func (handler *Handler) checkACL(signedProp *pb.SignedProposal, proposal *pb.Proposal, calledCC *ccParts) error {
242+
// ensure that we don't invoke a system chaincode
243+
// that is not invokable through a cc2cc invocation
244+
if sysccprovider.GetSystemChaincodeProvider().IsSysCCAndNotInvokableCC2CC(calledCC.name) {
245+
return fmt.Errorf("System chaincode %s cannot be invoked with a cc2cc invocation", calledCC.name)
246+
}
247+
248+
// if we are here, all we know is that the invoked chaincode is either
249+
// - a system chaincode that *is* invokable through a cc2cc
250+
// (but we may still have to determine whether the invoker
251+
// can perform this invocation)
252+
// - an application chaincode (and we still need to determine
253+
// whether the invoker can invoke it)
245254

246-
// If error, return ChaincodeMessage with type ChaincodeMessage_ERROR
247255
return nil
248256
}
249257

@@ -1269,8 +1277,12 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
12691277
shorttxid(msg.Txid), calledCcParts.name, calledCcParts.suffix)
12701278
}
12711279

1272-
triggerNextStateMsg = handler.checkACL(txContext.signedProp, txContext.proposal, calledCcParts)
1273-
if triggerNextStateMsg != nil {
1280+
err := handler.checkACL(txContext.signedProp, txContext.proposal, calledCcParts)
1281+
if err != nil {
1282+
chaincodeLogger.Errorf("[%s] C-call-C %s on channel %s failed check ACL [%v]: [%s]",
1283+
shorttxid(msg.Txid), calledCcParts.name, calledCcParts.suffix, txContext.signedProp, err)
1284+
triggerNextStateMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR,
1285+
Payload: []byte(err.Error()), Txid: msg.Txid}
12741286
return
12751287
}
12761288

core/common/sysccprovider/sysccprovider.go

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ package sysccprovider
2323
type SystemChaincodeProvider interface {
2424
// IsSysCC returns true if the supplied chaincode is a system chaincode
2525
IsSysCC(name string) bool
26+
27+
// IsSysCCAndNotInvokableCC2CC returns true if the supplied chaincode
28+
// is a system chaincode and is not invokable through a cc2cc invocation
29+
IsSysCCAndNotInvokableCC2CC(name string) bool
2630
}
2731

2832
var sccFactory SystemChaincodeProviderFactory

core/scc/importsysccs.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ var systemChaincodes = []*SystemChaincode{
4141
Path: "github.com/hyperledger/fabric/core/scc/lscc",
4242
InitArgs: [][]byte{[]byte("")},
4343
Chaincode: &lscc.LifeCycleSysCC{},
44-
InvokableExternal: true, // lccc is invoked to deploy new chaincodes
44+
InvokableExternal: true, // lscc is invoked to deploy new chaincodes
45+
InvokableCC2CC: true, // lscc can be invoked by other chaincodes
4546
},
4647
{
4748
Enabled: true,
@@ -116,6 +117,18 @@ func IsSysCCAndNotInvokable(name string) bool {
116117
return false
117118
}
118119

120+
// IsSysCCAndNotInvokableCC2CC returns true if the chaincode
121+
// is a system chaincode and *CANNOT* be invoked through
122+
// a cc2cc invocation
123+
func IsSysCCAndNotInvokableCC2CC(name string) bool {
124+
for _, sysCC := range systemChaincodes {
125+
if sysCC.Name == name {
126+
return !sysCC.InvokableCC2CC
127+
}
128+
}
129+
return false
130+
}
131+
119132
// MockRegisterSysCCs is used only for testing
120133
// This is needed to break import cycle
121134
func MockRegisterSysCCs(mockSysCCs []*SystemChaincode) []*SystemChaincode {

core/scc/lscc/lscc_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ func (c *mocksccProviderImpl) IsSysCC(name string) bool {
5151
return true
5252
}
5353

54+
func (c *mocksccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool {
55+
return false
56+
}
57+
5458
func register(stub *shim.MockStub, ccname string) error {
5559
args := [][]byte{[]byte("register"), []byte(ccname)}
5660
if res := stub.MockInvoke("1", args); res.Status != shim.OK {

core/scc/sccproviderimpl.go

+6
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ type sccProviderImpl struct {
4444
func (c *sccProviderImpl) IsSysCC(name string) bool {
4545
return IsSysCC(name)
4646
}
47+
48+
// IsSysCCAndNotInvokableCC2CC returns true if the supplied chaincode is
49+
// ia system chaincode and it NOT nvokable through a cc2cc invocation
50+
func (c *sccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool {
51+
return IsSysCCAndNotInvokableCC2CC(name)
52+
}

0 commit comments

Comments
 (0)