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

Blacklist some config sections from HTTP PUT/DELETE operations #914

Merged
merged 1 commit into from
Oct 25, 2017
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ else
endif
@rm -rf dev/lib
@dev/run -n 1 -q --with-admin-party-please \
--enable-erlang-views \
-c 'startup_jitter=0' \
'test/javascript/run --suites "$(suites)" \
--ignore "$(ignore_js_suites)"'
Expand Down
11 changes: 11 additions & 0 deletions dev/run
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ def setup_argparse():
dest='with_admin_party', default=False,
action='store_true',
help='Runs a dev cluster with admin party mode on')
parser.add_option('--enable-erlang-views',
action='store_true',
help='Enables the Erlang view server')
parser.add_option('--no-join',
dest='no_join', default=False,
action='store_true',
Expand All @@ -135,6 +138,7 @@ def setup_context(opts, args):
return {'N': opts.nodes,
'no_join': opts.no_join,
'with_admin_party': opts.with_admin_party,
'enable_erlang_views': opts.enable_erlang_views,
'admin': opts.admin.split(':', 1) if opts.admin else None,
'nodes': ['node%d' % (i + opts.node_number) for i in range(opts.nodes)],
'node_number': opts.node_number,
Expand Down Expand Up @@ -274,6 +278,13 @@ def hack_default_ini(ctx, node, contents):
repl = toposixpath("coffeescript = %s %s" % (couchjs, coffeejs))
contents = re.sub("(?m)^coffeescript.*$", repl, contents)

if ctx['enable_erlang_views']:
contents = re.sub(
"^\[native_query_servers\]$",
"[native_query_servers]\nerlang = {couch_native_process, start_link, []}",
contents,
flags=re.MULTILINE)

return contents


Expand Down
2 changes: 2 additions & 0 deletions src/chttpd/src/chttpd_misc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ handle_node_req(#httpd{path_parts=[_, _Node, <<"_config">>, _Section]}=Req) ->
% PUT /_node/$node/_config/Section/Key
% "value"
handle_node_req(#httpd{method='PUT', path_parts=[_, Node, <<"_config">>, Section, Key]}=Req) ->
couch_util:check_config_blacklist(Section),
Value = chttpd:json_body(Req),
Persist = chttpd:header_value(Req, "X-Couch-Persist") /= "false",
OldValue = call_node(Node, config, get, [Section, Key, ""]),
Expand All @@ -271,6 +272,7 @@ handle_node_req(#httpd{method='GET', path_parts=[_, Node, <<"_config">>, Section
end;
% DELETE /_node/$node/_config/Section/Key
handle_node_req(#httpd{method='DELETE',path_parts=[_, Node, <<"_config">>, Section, Key]}=Req) ->
couch_util:check_config_blacklist(Section),
Persist = chttpd:header_value(Req, "X-Couch-Persist") /= "false",
case call_node(Node, config, get, [Section, Key, undefined]) of
undefined ->
Expand Down
1 change: 1 addition & 0 deletions src/couch/src/couch_httpd_misc_handlers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ handle_config_req(#httpd{method='POST', path_parts=[_, <<"_reload">>]}=Req) ->
handle_config_req(#httpd{method=Method, path_parts=[_, Section, Key]}=Req)
when (Method == 'PUT') or (Method == 'DELETE') ->
ok = couch_httpd:verify_is_server_admin(Req),
couch_util:check_config_blacklist(Section),
Persist = couch_httpd:header_value(Req, "X-Couch-Persist") /= "false",
case config:get("httpd", "config_whitelist", undefined) of
undefined ->
Expand Down
22 changes: 22 additions & 0 deletions src/couch/src/couch_util.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,25 @@
-export([with_proc/4]).
-export([process_dict_get/2, process_dict_get/3]).
-export([unique_monotonic_integer/0]).
-export([check_config_blacklist/1]).

-include_lib("couch/include/couch_db.hrl").

% arbitrarily chosen amount of memory to use before flushing to disk
-define(FLUSH_MAX_MEM, 10000000).

-define(BLACKLIST_CONFIG_SECTIONS, [
<<"daemons">>,
<<"external">>,
<<"httpd_design_handlers">>,
<<"httpd_db_handlers">>,
<<"httpd_global_handlers">>,
<<"native_query_servers">>,
<<"os_daemons">>,
<<"query_servers">>
]).


priv_dir() ->
case code:priv_dir(couch) of
{error, bad_name} ->
Expand Down Expand Up @@ -640,3 +653,12 @@ unique_monotonic_integer() ->
erlang:unique_integer([monotonic, positive]).

-endif.

check_config_blacklist(Section) ->
case lists:member(Section, ?BLACKLIST_CONFIG_SECTIONS) of
true ->
Msg = <<"Config section blacklisted for modification over HTTP API.">>,
throw({forbidden, Msg});
_ ->
ok
end.
8 changes: 8 additions & 0 deletions test/javascript/tests/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,12 @@ couchTests.config = function(debug) {
headers: {"X-Couch-Persist": "false"}
});
TEquals(200, xhr.status, "Reset config whitelist to undefined");

// Confirm that the blacklist is functional
["daemons", "external", "httpd_design_handlers", "httpd_db_handlers", "native_query_servers", "os_daemons", "query_servers"].forEach(function(section) {
xhr = CouchDB.request("PUT", "/_node/[email protected]/_config/" + section + "/wohali",{
body: "\"rules\""
});
TEquals(403, xhr.status, "Blacklisted config section " + section);
});
};
4 changes: 1 addition & 3 deletions test/javascript/tests/erlang_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ couchTests.erlang_views = function(debug) {
if (debug) debugger;

run_on_modified_server(
[{section: "native_query_servers",
key: "erlang",
value: "{couch_native_process, start_link, []}"}],
[],
function() {
// Note we just do some basic 'smoke tests' here - the
// test/query_server_spec.rb tests have more comprehensive tests
Expand Down
2 changes: 2 additions & 0 deletions test/javascript/tests/view_sandboxing.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ couchTests.view_sandboxing = function(debug) {
// cleanup
db.deleteDb();

/* TODO: re-enable this test once --no-eval is the default
// test that runtime code evaluation can be prevented
var couchjs_command_xhr = CouchDB.request(
"GET", "_node/[email protected]/_config/query_servers/javascript");
Expand Down Expand Up @@ -179,6 +180,7 @@ couchTests.view_sandboxing = function(debug) {

TEquals(0, results.rows.length);
});
*/

// cleanup
CouchDB.request("POST", "_reload_query_servers");
Expand Down