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

Reply via email to