8000 Added startup option `--javascript.user-defined-functions`. (#18048) · olegrok/arangodb@53db9db · GitHub
[go: up one dir, main page]

Skip to content

Commit 53db9db

Browse files
authored
Added startup option --javascript.user-defined-functions. (arangodb#18048)
1 parent 2d4b99d commit 53db9db

File tree

5 files changed

+126
-11
lines changed

5 files changed

+126
-11
lines changed

CHANGELOG

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
devel
22
-----
33

4+
* Added startup option `--javascript.user-defined-functions`.
5+
This option controls whether JavaScript user-defined functions (UDFs) can
6+
be used in AQL queries. The option defaults to `true`. The option can be
7+
set to `false` to disallow using JavaScript UDFs from inside AQL queries.
8+
In that case, a parse error will be thrown when trying to run a query that
9+
invokes a UDF.
10+
411
* Updated transitive JS dependency hoek to @hapi/hoek@8.5.1 to resolve
512
CVE-2020-36604 in joi.
613

714
* Updated JS dependency minimatch to 3.1.2 to resolve CVE-2022-3517.
815

916
* Updated JS dependency qs to 6.11.0 to resolve CVE-2022-24999.
1017

11-
* Deleted customizable Pregel (AIR) and Greenspun library
12-
1318
* Allowing enabling/disabling supervision maintenance mode also via followers
1419
in active failover mode. Previously the supervision maintenance mode could
1520
only be enabled/disabled by making a call to the active failover leader.

arangod/Aql/Ast.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "Utilities/NameValidator.h"
5858
#include "VocBase/LogicalCollection.h"
5959
#include "VocBase/LogicalView.h"
60+
#include "V8Server/V8DealerFeature.h"
6061

6162
#include <absl/strings/str_cat.h>
6263

@@ -1884,12 +1885,26 @@ AstNode* Ast::createNodeFunctionCall(std::string_view functionName,
18841885
_functionsMayAccessDocuments = true;
18851886
}
18861887
} else {
1887-
// user-defined function
1888+
// user-defined function (UDF)
1889+
if (_query.vocbase().server().hasFeature<V8DealerFeature>() &&
1890+
!_query.vocbase()
1891+
.server()
1892+
.getFeature<V8DealerFeature>()
1893+
.allowJavaScriptUdfs()) {
1894+
// usage of user-defined functions is disallowed
1895+
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE,
1896+
"usage of AQL user-defined functions "
1897+
"(UDFs) is disallowed via configuration");
1898+
}
1899+
18881900
node = createNode(NODE_TYPE_FCALL_USER);
18891901
// register the function name
18901902
char* fname = _resources.registerString(normalized);
18911903
node->setStringValue(fname, normalized.size());
18921904

1905+
// a JavaScript user-defined function can potentially read documents
1906+
// via JavaScript document or AQL APIs. we don't know for sure, so we
1907+
// need to assume the worst case here.
18931908
_functionsMayAccessDocuments = true;
18941909
}
18951910

arangod/V8Server/V8DealerFeature.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,14 @@ V8DealerFeature::V8DealerFeature(Server& server)
127127
_gcFrequency(60.0),
128128
_gcInterval(2000),
129129
_maxContextAge(60.0),
130-
_copyInstallation(false),
131130
_nrMaxContexts(0),
132131
_nrMinContexts(0),
133132
_nrInflightContexts(0),
134133
_maxContextInvocations(0),
134+
_copyInstallation(false),
135135
_allowAdminExecute(false),
136136
_allowJavaScriptTransactions(true),
137+
_allowJavaScriptUdfs(true),
137138
_allowJavaScriptTasks(true),
138139
_enableJS(true),
139140
_nextId(0),
@@ -328,6 +329,17 @@ or teardown commands for execution on the server.)");
328329
arangodb::options::Flags::OnSingle))
329330
.setIntroducedIn(30800);
330331

332+
options
333+
->addOption(
334+
"--javascript.user-defined-functions",
335+
"Enable JavaScript user-defined functions (UDFs) in AQL queries.",
336+
new BooleanParameter(&_allowJavaScriptUdfs),
337+
arangodb::options::makeFlags(
338+
arangodb::options::Flags::DefaultNoComponents,
339+
arangodb::options::Flags::OnCoordinator,
340+
arangodb::options::Flags::OnSingle))
341+
.setIntroducedIn(31004);
342+
331343
options
332344
->addOption("--javascript.tasks", "Enable JavaScript tasks.",
333345
new BooleanParameter(&_allowJavaScriptTasks),

arangod/V8Server/V8DealerFeature.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,35 @@ class V8DealerFeature final : public ArangodFeature {
8080
std::string _startupDirectory;
8181
std::string _nodeModulesDirectory;
8282
std::vector<std::string> _moduleDirectories;
83+
// maximum number of contexts to create
84+
uint64_t _nrMaxContexts;
85+
// minimum number of contexts to keep
86+
uint64_t _nrMinContexts;
87+
// number of contexts currently in creation
88+
uint64_t _nrInflightContexts;
89+
// maximum number of V8 context invocations
90+
uint64_t _maxContextInvocations;
91+
92+
// copy JavaScript files into database directory on startup
8393
bool _copyInstallation;
84-
uint64_t _nrMaxContexts; // maximum number of contexts to create
85-
uint64_t _nrMinContexts; // minimum number of contexts to keep
86-
uint64_t _nrInflightContexts; // number of contexts currently in creation
87-
uint64_t _maxContextInvocations; // maximum number of V8 context invocations
94+
// enable /_admin/execute API
8895
bool _allowAdminExecute;
96+
// allow JavaScript transactions?
8997
bool _allowJavaScriptTransactions;
98+
// allow JavaScript user-defined functions?
99+
bool _allowJavaScriptUdfs;
100+
// allow JavaScript tasks (tasks module)?
90101
bool _allowJavaScriptTasks;
102+
// enable JavaScript globally
91103
bool _enableJS;
92104

93105
public:
94< F438 span class="diff-text-marker">-
bool allowAdminExecute() const { return _allowAdminExecute; }
95-
bool allowJavaScriptTransactions() const {
106+
bool allowAdminExecute() const noexcept { return _allowAdminExecute; }
107+
bool allowJavaScriptTransactions() const noexcept {
96108
return _allowJavaScriptTransactions;
97109
}
98-
bool allowJavaScriptTasks() const { return _allowJavaScriptTasks; }
110+
bool allowJavaScriptUdfs() const noexcept { return _allowJavaScriptUdfs; }
111+
bool allowJavaScriptTasks() const noexcept { return _allowJavaScriptTasks; }
99112

100113
bool addGlobalContextMethod(std::string const&);
101114
void collectGarbage();
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*jshint globalstrict:false, strict:false */
2+
/*global assertEqual, getOptions, fail */
3+
4+
////////////////////////////////////////////////////////////////////////////////
5+
/// DISCLAIMER
6+
///
7+
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
8+
///
9+
/// Licensed under the Apache License, Version 2.0 (the "License");
10+
/// you may not use this file except in compliance with the License.
11+
/// You may obtain a copy of the License at
12+
///
13+
/// http://www.apache.org/licenses/LICENSE-2.0
14+
///
15+
/// Unless required by applicable law or agreed to in writing, software
16+
/// distributed under the License is distributed on an "AS IS" BASIS,
17+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
/// See the License for the specific language governing permissions and
19+
/// limitations under the License.
20+
///
21+
/// Copyright holder is triAGENS GmbH, Cologne, Germany
22+
///
23+
/// @author Jan Steemann
24+
/// @author Copyright 2023, triAGENS GmbH, Cologne, Germany
25+
////////////////////////////////////////////////////////////////////////////////
26+
27+
if (getOptions === true) {
28+
return {
29+
'javascript.user-defined-functions': 'false',
30+
};
31+
}
32+
33+
const jsunity = require("jsunity");
34+
const arangodb = require("@arangodb");
35+
const udf = require("@arangodb/aql/functions");
36+
const db = arangodb.db;
37+
const ERRORS = arangodb.errors;
38+
39+
function UserDefinedFunctionsTestSuite () {
40+
return {
41+
42+
setUpAll : function () {
43+
udf.register("some::func", function() { return 1; });
44+
},
45+
46+
tearDownAll : function () {
47+
udf.unregister("some::func");
48+
},
49+
50+
testUseUDF : function () {
51+
try {
52+
// invoking a UDF should fail with a parse error
53+
db._query("RETURN some::func()");
54+
fail();
55+
} catch (err) {
56+
assertEqual(err.errorNum, ERRORS.ERROR_QUERY_PARSE.code);
57+
}
58+
},
59+
60+
testNormalAqlFunction : function () {
61+
// invoking normal AQL functions should just work
62+
let res = db._query("RETURN MAX([1, 2, 3])");
63+
assertEqual([ 3 ], res.toArray());
64+
},
65+
};
66+
}
67+
68+
jsunity.run(UserDefinedFunctionsTestSuite);
69+
70+
return jsunity.done();

0 commit comments

Comments
 (0)
0