From 0572ca3c61dc76a59c8f97b43876881d43f51520 Mon Sep 17 00:00:00 2001 From: meows Date: Wed, 18 Dec 2019 08:44:41 -0600 Subject: [PATCH 1/6] rpc: enforce rpc api module availability Fixes #20467 Signed-off-by: meows --- rpc/endpoints.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/rpc/endpoints.go b/rpc/endpoints.go index 8ca6d4eb0c6d..845acf849bb0 100644 --- a/rpc/endpoints.go +++ b/rpc/endpoints.go @@ -18,6 +18,7 @@ package rpc import ( "net" + "strings" "github.com/ethereum/go-ethereum/log" ) @@ -27,6 +28,29 @@ func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []str // Generate the whitelist based on the allowed modules whitelist := make(map[string]bool) for _, module := range modules { + apiExists := false + for _, api := range apis { + if module == api.Namespace { + apiExists = true + break + } + } + if !apiExists { + log.Crit("invalid api module", "module", module, "available", func() string { + available := []string{} + outer: + for _, api := range apis { + // Only include unique api names + for _, av := range available { + if av == api.Namespace { + continue outer + } + } + available = append(available, api.Namespace) + } + return strings.Join(available, ",") + }()) + } whitelist[module] = true } // Register all the APIs exposed by the services From ddaee90378be50f15eb82bd44ebfdd5acb23b3d6 Mon Sep 17 00:00:00 2001 From: meows Date: Wed, 18 Dec 2019 08:59:07 -0600 Subject: [PATCH 2/6] rpc: refactor to install module validity checker for WS server too Signed-off-by: meows --- rpc/endpoints.go | 55 ++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/rpc/endpoints.go b/rpc/endpoints.go index 845acf849bb0..dae5e0099b6c 100644 --- a/rpc/endpoints.go +++ b/rpc/endpoints.go @@ -23,34 +23,42 @@ import ( "github.com/ethereum/go-ethereum/log" ) +// mustAvailableModule enforces that requested api modules (eg. via --rpcapi) are actually +// available API services. If an invalid module is given (ie API "foo" wanted which does not exist), +// then log.Crit is used to cause program to exit, logging the invalid module and a list of available +// API service names. +func mustAvailableModule(module string, apis []API) { + apiExists := false + for _, api := range apis { + if module == api.Namespace { + apiExists = true + break + } + } + if !apiExists { + log.Crit("invalid api module", "module", module, "available", func() string { + available := []string{} + outer: + for _, api := range apis { + // Only include unique api names + for _, av := range available { + if av == api.Namespace { + continue outer + } + } + available = append(available, api.Namespace) + } + return strings.Join(available, ",") + }()) + } +} + // StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []string, vhosts []string, timeouts HTTPTimeouts) (net.Listener, *Server, error) { // Generate the whitelist based on the allowed modules whitelist := make(map[string]bool) for _, module := range modules { - apiExists := false - for _, api := range apis { - if module == api.Namespace { - apiExists = true - break - } - } - if !apiExists { - log.Crit("invalid api module", "module", module, "available", func() string { - available := []string{} - outer: - for _, api := range apis { - // Only include unique api names - for _, av := range available { - if av == api.Namespace { - continue outer - } - } - available = append(available, api.Namespace) - } - return strings.Join(available, ",") - }()) - } + mustAvailableModule(module, apis) whitelist[module] = true } // Register all the APIs exposed by the services @@ -81,6 +89,7 @@ func StartWSEndpoint(endpoint string, apis []API, modules []string, wsOrigins [] // Generate the whitelist based on the allowed modules whitelist := make(map[string]bool) for _, module := range modules { + mustAvailableModule(module, apis) whitelist[module] = true } // Register all the APIs exposed by the services From fb6453db1d87df942a46db7267b590a2c35cf809 Mon Sep 17 00:00:00 2001 From: meows Date: Wed, 18 Dec 2019 09:01:58 -0600 Subject: [PATCH 3/6] rpc: refactor for concision Signed-off-by: meows --- rpc/endpoints.go | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/rpc/endpoints.go b/rpc/endpoints.go index dae5e0099b6c..f7813e60def9 100644 --- a/rpc/endpoints.go +++ b/rpc/endpoints.go @@ -28,29 +28,25 @@ import ( // then log.Crit is used to cause program to exit, logging the invalid module and a list of available // API service names. func mustAvailableModule(module string, apis []API) { - apiExists := false for _, api := range apis { if module == api.Namespace { - apiExists = true - break + return } } - if !apiExists { - log.Crit("invalid api module", "module", module, "available", func() string { - available := []string{} - outer: - for _, api := range apis { - // Only include unique api names - for _, av := range available { - if av == api.Namespace { - continue outer - } + log.Crit("invalid api module", "module", module, "available", func() string { + available := []string{} + outer: + for _, api := range apis { + // Only include unique api names + for _, av := range available { + if av == api.Namespace { + continue outer } - available = append(available, api.Namespace) } - return strings.Join(available, ",") - }()) - } + available = append(available, api.Namespace) + } + return strings.Join(available, ",") + }()) } // StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules From 9b8f5cc143ca131ab44afb7586aeb9e2d4002286 Mon Sep 17 00:00:00 2001 From: meows Date: Wed, 18 Dec 2019 09:05:06 -0600 Subject: [PATCH 4/6] rpc: return a slice of strings, simpler and equivalent Signed-off-by: meows --- rpc/endpoints.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rpc/endpoints.go b/rpc/endpoints.go index f7813e60def9..297ab50fd8e4 100644 --- a/rpc/endpoints.go +++ b/rpc/endpoints.go @@ -18,7 +18,6 @@ package rpc import ( "net" - "strings" "github.com/ethereum/go-ethereum/log" ) @@ -33,8 +32,7 @@ func mustAvailableModule(module string, apis []API) { return } } - log.Crit("invalid api module", "module", module, "available", func() string { - available := []string{} + log.Crit("invalid api module", "module", module, "available", func() (available []string) { outer: for _, api := range apis { // Only include unique api names @@ -45,7 +43,7 @@ func mustAvailableModule(module string, apis []API) { } available = append(available, api.Namespace) } - return strings.Join(available, ",") + return }()) } From 3ac3773daed86cc31e8511041cc94587b35b58a9 Mon Sep 17 00:00:00 2001 From: meows Date: Tue, 14 Jan 2020 09:18:08 -0600 Subject: [PATCH 5/6] rpc: return error instead of log.Crit Resolves https://github.com/ethereum/go-ethereum/pull/20468/files#r366236052 Signed-off-by: meows --- rpc/endpoints.go | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/rpc/endpoints.go b/rpc/endpoints.go index 297ab50fd8e4..79886eb0dc7e 100644 --- a/rpc/endpoints.go +++ b/rpc/endpoints.go @@ -17,34 +17,37 @@ package rpc import ( + "fmt" "net" "github.com/ethereum/go-ethereum/log" ) -// mustAvailableModule enforces that requested api modules (eg. via --rpcapi) are actually +// isModuleAvailable enforces that requested api modules (eg. via --rpcapi) are actually // available API services. If an invalid module is given (ie API "foo" wanted which does not exist), // then log.Crit is used to cause program to exit, logging the invalid module and a list of available // API service names. -func mustAvailableModule(module string, apis []API) { +func isModuleAvailable(module string, apis []API) (err error) { for _, api := range apis { if module == api.Namespace { - return + return nil } } - log.Crit("invalid api module", "module", module, "available", func() (available []string) { - outer: - for _, api := range apis { - // Only include unique api names - for _, av := range available { - if av == api.Namespace { - continue outer - } + // Module did not find a matching api namespace: this is an invalid module. + // Collect list of available modules for user debugging. + available := []string{} +outer: + for _, api := range apis { + + // Only include unique api names + for _, av := range available { + if av == api.Namespace { + continue outer } - available = append(available, api.Namespace) } - return - }()) + available = append(available, api.Namespace) + } + return fmt.Errorf("invalid api module: module=%s available=%v", module, available) } // StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules @@ -52,7 +55,11 @@ func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []str // Generate the whitelist based on the allowed modules whitelist := make(map[string]bool) for _, module := range modules { - mustAvailableModule(module, apis) + + // Ensure the requested module is actually available. + if err := isModuleAvailable(module, apis); err != nil { + return nil, nil, err + } whitelist[module] = true } // Register all the APIs exposed by the services @@ -83,7 +90,11 @@ func StartWSEndpoint(endpoint string, apis []API, modules []string, wsOrigins [] // Generate the whitelist based on the allowed modules whitelist := make(map[string]bool) for _, module := range modules { - mustAvailableModule(module, apis) + + // Ensure the requested module is actually available. + if err := isModuleAvailable(module, apis); err != nil { + return nil, nil, err + } whitelist[module] = true } // Register all the APIs exposed by the services From 7296f49b3f1f35bc382f94d68f98b7e9a740f2f9 Mon Sep 17 00:00:00 2001 From: meows Date: Tue, 14 Jan 2020 09:23:23 -0600 Subject: [PATCH 6/6] rpc: name function and fix comment Function renamed from is_ to check_ to avoid the convention of is_ functions returning bools. Signed-off-by: meows --- rpc/endpoints.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rpc/endpoints.go b/rpc/endpoints.go index 79886eb0dc7e..e734f0c880b2 100644 --- a/rpc/endpoints.go +++ b/rpc/endpoints.go @@ -23,11 +23,11 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// isModuleAvailable enforces that requested api modules (eg. via --rpcapi) are actually +// checkModuleAvailable check that requested api modules (eg. via --rpcapi) are actually // available API services. If an invalid module is given (ie API "foo" wanted which does not exist), -// then log.Crit is used to cause program to exit, logging the invalid module and a list of available +// then an error is returned including the invalid module and a list of available // API service names. -func isModuleAvailable(module string, apis []API) (err error) { +func checkModuleAvailable(module string, apis []API) (err error) { for _, api := range apis { if module == api.Namespace { return nil @@ -57,7 +57,7 @@ func StartHTTPEndpoint(endpoint string, apis []API, modules []string, cors []str for _, module := range modules { // Ensure the requested module is actually available. - if err := isModuleAvailable(module, apis); err != nil { + if err := checkModuleAvailable(module, apis); err != nil { return nil, nil, err } whitelist[module] = true @@ -92,7 +92,7 @@ func StartWSEndpoint(endpoint string, apis []API, modules []string, wsOrigins [] for _, module := range modules { // Ensure the requested module is actually available. - if err := isModuleAvailable(module, apis); err != nil { + if err := checkModuleAvailable(module, apis); err != nil { return nil, nil, err } whitelist[module] = true