In case we talk about different designs, I assume the following one: * `source name' searches the files in BASH_SOURCE_PATH, PATH, and the current working directory. * `source -i name', if it would be added, searches the files in BASH_SOURCE_PATH (excluding PATH and the current working directory unless `.' is included in BASH_SOURCE_PATH).
I think it is clearer to see the patches. I attach modified patches: 0001 adds BASH_SOURCE_PATH. 0002 is an optional patch if we are to add the command-line option to the `source' builtin. In rebasing the patches, I noticed the stub in the latest devel push. Should BASH_SOURCE_PATH be affected by `shopt -s sourcepath'? I think it is more useful to be able to control PATH (through sourcepath) and BASH_SOURCE_PATH (through whether its state is unset or empty) separately.
From c29cf5ec2a79ef40eb09dcec3ae7402142850838 Mon Sep 17 00:00:00 2001 From: Matheus Afonso Martins Moreira <matheus.a.m.moreira@gmail.com> Date: Mon, 13 May 2024 07:37:26 -0300 Subject: [PATCH 1/2] feat: support BASH_SOURCE_PATH * shell: restrict BASH_SOURCE_PATH when appropriate Make the BASH_SOURCE_PATH variable read-only and unsettable when the shell is operating in restricted mode. This variable should be restricted for the same reasons why PATH is restricted. Modifications: * When we are not in the POSIX mode, we consider BASH_SOURCE_PATH if present even without the new option `-i'. * The new variable BASH_SOURCE_PATH has been disabled at all in the restricted shell since this would introduce a new loophole in existing setups of the restricted shells. If the new variable were enabled in the restricted shells, all the existing setups would need to be updated to care about the variable BASH_SOURCE_PATH, which would be an unreasonable requirement. In addition, considering the purpose of the restricted shells, we would not need to provide the new feature to the restricted shells. Co-authored-by: Koichi Murase <myoga.murase@gmail.com> --- builtins/source.def | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/builtins/source.def b/builtins/source.def index 51dddec6..4498ac9e 100644 --- a/builtins/source.def +++ b/builtins/source.def @@ -116,7 +116,7 @@ int source_builtin (WORD_LIST *list) { int result; - char *filename, *debug_trap, *x; + char *filename, *source_path, *debug_trap, *x; if (no_options (list)) return (EX_USAGE); @@ -143,20 +143,15 @@ source_builtin (WORD_LIST *list) filename = savestring (list->word->word); else if (absolute_pathname (list->word->word)) filename = savestring (list->word->word); - else if (source_uses_path) - { -#if 0 - char *spath; + else if ( + !posixly_correct && #if defined (RESTRICTED_SHELL) - if (restricted == 0 && posixly_correct == 0 && (spath = path_value ("BASH_SOURCE_PATH", 1))) -#else - if (posixly_correct == 0 && (spath = path_value ("BASH_SOURCE_PATH", 1))) -#endif - filename = find_in_path (list->word->word, spath, FS_READABLE); - else + !restricted && #endif - filename = find_path_file (list->word->word); - } + (source_path = path_value ("BASH_SOURCE_PATH", 1)) != NULL) + filename = find_in_path (list->word->word, source_path, FS_READABLE); + if (filename == 0 && source_uses_path) + filename = find_path_file (list->word->word); if (filename == 0) { if (source_searches_cwd == 0) -- 2.43.0
From 172218c620adbbeca7a1dfda8eae759d38fecbc2 Mon Sep 17 00:00:00 2001 From: Matheus Afonso Martins Moreira <matheus.a.m.moreira@gmail.com> Date: Mon, 13 May 2024 07:37:23 -0300 Subject: [PATCH 2/2] feat: support "source -i" * builtins/source: parse the -i option Passing the -i option to the source builtin enables isolated sourcing mode which restricts its search path to the directories defined by the BASH_SOURCE_PATH variable. This also has the added benefit of not touching PATH at all. Modifications: * If the option is explicitly supplied, we try to use BASH_SOURCE_PATH exclusively even in POSIX mode. This is consistent with portable scripts because they are supposed not to specify the -i option. It has been Bash's convention to allow a non-POSIX feature even in POSIX mode when the script explicitly requests it. Co-authored-by: Koichi Murase <myoga.murase@gmail.com> --- builtins/source.def | 62 ++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/builtins/source.def b/builtins/source.def index 4498ac9e..251f6c02 100644 --- a/builtins/source.def +++ b/builtins/source.def @@ -117,9 +117,31 @@ source_builtin (WORD_LIST *list) { int result; char *filename, *source_path, *debug_trap, *x; + int opt, isolated_mode = 0; + + reset_internal_getopt (); + + while ((opt = internal_getopt (list, "i")) != -1) + { + switch (opt) + { + case 'i': +#if defined (RESTRICTED_SHELL) + if (restricted) + { + sh_restricted ("-i"); + return (EXECUTION_FAILURE); + } +#endif + isolated_mode = 1; + break; + CASE_HELPOPT; + default: + builtin_usage (); + return (EX_USAGE); + } + } - if (no_options (list)) - return (EX_USAGE); list = loptend; if (list == 0) @@ -144,31 +166,31 @@ source_builtin (WORD_LIST *list) else if (absolute_pathname (list->word->word)) filename = savestring (list->word->word); else if ( - !posixly_correct && + (!posixly_correct || isolated_mode) && #if defined (RESTRICTED_SHELL) !restricted && #endif (source_path = path_value ("BASH_SOURCE_PATH", 1)) != NULL) filename = find_in_path (list->word->word, source_path, FS_READABLE); - if (filename == 0 && source_uses_path) - filename = find_path_file (list->word->word); + if (filename == 0 && !isolated_mode) + { + if (source_uses_path) + filename = find_path_file (list->word->word); + if (filename == 0 && source_searches_cwd != 0) + filename = savestring (list->word->word); + } if (filename == 0) { - if (source_searches_cwd == 0) - { - x = printable_filename (list->word->word, 0); - builtin_error (_("%s: file not found"), x); - if (x != list->word->word) - free (x); - if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0) - { - last_command_exit_value = EXECUTION_FAILURE; - jump_to_top_level (EXITPROG); - } - return (EXECUTION_FAILURE); - } - else - filename = savestring (list->word->word); + x = printable_filename (list->word->word, 0); + builtin_error (_("%s: file not found"), x); + if (x != list->word->word) + free (x); + if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0) + { + last_command_exit_value = EXECUTION_FAILURE; + jump_to_top_level (EXITPROG); + } + return (EXECUTION_FAILURE); } begin_unwind_frame ("source"); -- 2.43.0