Skip to content

Commit fbbbfe2

Browse files
khushboovashiakshay-joshi
authored andcommitted
Fixed a remote code execution issue in the validate binary path (CVE-2024-3116). #7326
1 parent 26b279c commit fbbbfe2

7 files changed

Lines changed: 59 additions & 10 deletions

File tree

‎docs/en_US/release_notes_8_5.rst‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ Bug fixes
5050
| `Issue #7305 <https://github.com/pgadmin-org/pgadmin4/issues/7305>`_ - Fix an issue in query tool where custom keyboard shortcuts are not working for some.
5151
| `Issue #7304 <https://github.com/pgadmin-org/pgadmin4/issues/7304>`_ - Fixed the issue where the update-user CLI command doesn't change the password.
5252
| `Issue #7308 <https://github.com/pgadmin-org/pgadmin4/issues/7308>`_ - Fixed issue related to email authentication of Two-factor authentication.
53-
53+
| `Issue #7326 <https://github.com/pgadmin-org/pgadmin4/issues/7326>`_ - Fixed a remote code execution issue in the validate binary path (CVE-2024-3116).

‎web/config.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,26 @@
469469
"ppas-16": ""
470470
}
471471

472+
##########################################################################
473+
474+
# Admin can specify fixed binary paths to prevent users from changing.
475+
# It will take precedence over DEFAULT_BINARY_PATHS.
476+
477+
FIXED_BINARY_PATHS = {
478+
"pg": "",
479+
"pg-12": "",
480+
"pg-13": "",
481+
"pg-14": "",
482+
"pg-15": "",
483+
"pg-16": "",
484+
"ppas": "",
485+
"ppas-12": "",
486+
"ppas-13": "",
487+
"ppas-14": "",
488+
"ppas-15": "",
489+
"ppas-16": ""
490+
}
491+
472492
##########################################################################
473493
# Test settings - used primarily by the regression suite, not for users
474494
##########################################################################

‎web/pgadmin/browser/server_groups/servers/static/js/binary_path.ui.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ export default class BinaryPathSchema extends BaseUISchema {
4949
{
5050
id: 'binaryPath', label: gettext('Binary Path'), cell: 'file', type: 'file',
5151
isvalidate: true,
52+
disabled: function (state) {
53+
// If Fixed path is assigned, user will not able to edit it.
54+
return state?.isFixed ? state.isFixed : false;
55+
},
5256
controlProps: {
5357
dialogType: 'select_folder',
5458
supportedTypes: ['*', 'sql', 'backup'],

‎web/pgadmin/browser/server_groups/servers/types.py‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import json
1212
import config
1313
import copy
14-
1514
from flask import render_template
1615
from flask_babel import gettext as _
1716
from pgadmin.utils.preferences import Preferences
@@ -240,15 +239,22 @@ def set_default_binary_path(bin_paths, server_type):
240239
"""
241240
is_default_path_set = ServerType.is_default_binary_path_set(bin_paths)
242241
for path in config.DEFAULT_BINARY_PATHS:
243-
path_value = config.DEFAULT_BINARY_PATHS[path]
242+
is_fixed_path = (path in config.FIXED_BINARY_PATHS and
243+
config.FIXED_BINARY_PATHS[path] != '' and
244+
config.FIXED_BINARY_PATHS[path] is not None)
245+
path_value = (is_fixed_path and config.FIXED_BINARY_PATHS[path]
246+
) or config.DEFAULT_BINARY_PATHS[path]
247+
244248
if path_value is not None and path_value != "" and \
245249
path.find(server_type) == 0 and len(path.split('-')) > 1:
246-
set_binary_path(path_value, bin_paths, server_type,
247-
path.split('-')[1])
250+
set_binary_path(
251+
path_value, bin_paths, server_type, path.split('-')[1],
252+
is_fixed_path=is_fixed_path)
248253
elif path_value is not None and path_value != "" and \
249254
path.find(server_type) == 0:
250255
set_binary_path(path_value, bin_paths, server_type,
251-
set_as_default=not is_default_path_set)
256+
set_as_default=not is_default_path_set,
257+
is_fixed_path=is_fixed_path)
252258

253259

254260
# Default Server Type

‎web/pgadmin/browser/templates/browser/js/utils.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ define('pgadmin.browser.utils',
6262
/* GET Binary Path Browse config */
6363
pgAdmin['enable_binary_path_browsing'] = '{{ current_app.config.get('ENABLE_BINARY_PATH_BROWSING') }}' == 'True';
6464

65+
pgAdmin['fixed_binary_paths'] = {{ current_app.config.get('FIXED_BINARY_PATHS') }};
66+
6567
/* GET the pgadmin server's locale */
6668
pgAdmin['pgadmin_server_locale'] = '{{pgadmin_server_locale}}';
6769

‎web/pgadmin/misc/__init__.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from flask.helpers import url_for
1515
from flask_babel import gettext
1616
from flask_security import login_required
17+
from pathlib import Path
1718
from pgadmin.utils import PgAdminModule, replace_binary_path, \
1819
get_binary_path_versions
1920
from pgadmin.utils.csrf import pgCSRFProtect
@@ -234,7 +235,11 @@ def validate_binary_path():
234235
data = json.loads(data)
235236

236237
version_str = ''
237-
if 'utility_path' in data and data['utility_path'] is not None:
238+
239+
# Do not allow storage dir as utility path
240+
if 'utility_path' in data and data['utility_path'] is not None and \
241+
Path(config.STORAGE_DIR) != Path(data['utility_path']) and \
242+
Path(config.STORAGE_DIR) not in Path(data['utility_path']).parents:
238243
binary_versions = get_binary_path_versions(data['utility_path'])
239244
for utility, version in binary_versions.items():
240245
if version is None:
@@ -248,7 +253,8 @@ def validate_binary_path():
248253
return make_json_response(data=gettext(version_str), status=200)
249254

250255

251-
@blueprint.route("/upgrade_check", endpoint="upgrade_check", methods=['GET'])
256+
@blueprint.route("/upgrade_check", endpoint="upgrade_check",
257+
methods=['GET'])
252258
@login_required
253259
def upgrade_check():
254260
# Get the current version info from the website, and flash a message if

‎web/pgadmin/utils/__init__.py‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
from collections import defaultdict
1515
from operator import attrgetter
1616

17+
from pathlib import Path
1718
from flask import Blueprint, current_app, url_for
1819
from flask_babel import gettext
1920
from flask_security import current_user, login_required
2021
from flask_security.utils import get_post_login_redirect, \
2122
get_post_logout_redirect
2223
from threading import Lock
23-
24+
import config
2425
from .paths import get_storage_directory
2526
from .preferences import Preferences
2627
from pgadmin.utils.constants import UTILITIES_ARRAY, USER_NOT_FOUND, \
@@ -308,11 +309,18 @@ def does_utility_exist(file):
308309
:return:
309310
"""
310311
error_msg = None
312+
311313
if file is None:
312314
error_msg = gettext("Utility file not found. Please correct the Binary"
313315
" Path in the Preferences dialog")
314316
return error_msg
315317

318+
if Path(config.STORAGE_DIR) == Path(file) or \
319+
Path(config.STORAGE_DIR) in Path(file).parents:
320+
error_msg = gettext("Please correct the Binary Path in the Preferences"
321+
" dialog. pgAdmin storage directory can not be a"
322+
" utility binary directory.")
323+
316324
if not os.path.exists(file):
317325
error_msg = gettext("'%s' file not found. Please correct the Binary"
318326
" Path in the Preferences dialog" % file)
@@ -364,7 +372,8 @@ def get_binary_path_versions(binary_path: str) -> dict:
364372

365373

366374
def set_binary_path(binary_path, bin_paths, server_type,
367-
version_number=None, set_as_default=False):
375+
version_number=None, set_as_default=False,
376+
is_fixed_path=False):
368377
"""
369378
This function is used to iterate through the utilities and set the
370379
default binary path.
@@ -394,6 +403,8 @@ def set_binary_path(binary_path, bin_paths, server_type,
394403
if path_with_dir is not None else binary_path
395404
if set_as_default:
396405
path['isDefault'] = True
406+
# Whether the fixed path in the config file exists or not
407+
path['isFixed'] = is_fixed_path
397408
break
398409
break
399410
except Exception:

0 commit comments

Comments
 (0)