texlive[69615] Build/source/texk/kpathsea: kpse_safe: allow /dir/.foo

commits+karl at tug.org commits+karl at tug.org
Sun Jan 28 00:45:25 CET 2024


Revision: 69615
          https://tug.org/svn/texlive?view=revision&revision=69615
Author:   karl
Date:     2024-01-28 00:45:24 +0100 (Sun, 28 Jan 2024)
Log Message:
-----------
kpse_safe: allow /dir/.foo if extended and matches TEXMF[SYS]VAR

Modified Paths:
--------------
    trunk/Build/source/texk/kpathsea/ChangeLog
    trunk/Build/source/texk/kpathsea/tests/kpsesafe.test
    trunk/Build/source/texk/kpathsea/tex-file.c

Modified: trunk/Build/source/texk/kpathsea/ChangeLog
===================================================================
--- trunk/Build/source/texk/kpathsea/ChangeLog	2024-01-27 22:48:16 UTC (rev 69614)
+++ trunk/Build/source/texk/kpathsea/ChangeLog	2024-01-27 23:45:24 UTC (rev 69615)
@@ -1,3 +1,11 @@
+2024-01-27  Karl Berry  <karl at freefriends.org>
+
+	* tex-file.c (kpathsea_name_ok): 
+	* tests/kpsesafe.test: kpse_expand (variable and ~ expansion)
+	input name when needed; don't reject /dir/.foo if extended
+	and it matches TEXMF[SYS]VAR, since TEXMFVAR=~/.texliveYYYY is the
+	case that matters in practice. Report from Marcel.
+
 2024-01-17  Karl Berry  <karl at freefriends.org>
 
 	* tex-file.c (kpse_{in,out}_name_ok{,_silent}_extended):

Modified: trunk/Build/source/texk/kpathsea/tests/kpsesafe.test
===================================================================
--- trunk/Build/source/texk/kpathsea/tests/kpsesafe.test	2024-01-27 22:48:16 UTC (rev 69614)
+++ trunk/Build/source/texk/kpathsea/tests/kpsesafe.test	2024-01-27 23:45:24 UTC (rev 69615)
@@ -21,21 +21,37 @@
 $_kpsewhich --safe-in-name=/ifoo.tex || exit 5
 $_kpsewhich --safe-out-name=/ofoo.tex && exit 6
 
+echo ".dotfile and .dotdir/file not ok for writing."
+$_kpsewhich --safe-out-name=.ifoo.tex && exit 7
+$_kpsewhich --safe-out-name=.idir/ifoo.tex && exit 8
+
 echo "TEXMF_OUTPUT_DIRECTORY and TEXMFOUTPUT ok for writing."
 TEXMF_OUTPUT_DIRECTORY=/xdir \
-  $_kpsewhich --safe-out-name=/xdir/ofoo.tex || exit 7
+  $_kpsewhich --safe-out-name=/xdir/ofoo.tex || exit 9
 TEXMFOUTPUT=/ydir \
-  $_kpsewhich --safe-out-name=/ydir/ofoo.tex || exit 8
+  $_kpsewhich --safe-out-name=/ydir/ofoo.tex || exit 10
 
-echo "TEXMFVAR and TEXMFSYSVAROUTPUT ok for writing only if extended."
+echo "TEXMF[SYS]VAR ok for writing only if extended."
 TEXMFVAR=/xvar \
-  $_kpsewhich --safe-out-name=/xvar/ofoo.tex && exit 9
+  $_kpsewhich --safe-out-name=/xvar/ofoo.tex && exit 11
 TEXMFSYSVAR=/yvar \
-  $_kpsewhich --safe-out-name=/yvar/ofoo.tex && exit 10
+  $_kpsewhich --safe-out-name=/yvar/ofoo.tex && exit 12
 #
 TEXMFVAR=/avar \
-  $_kpsewhich --safe-extended-out-name=/avar/ofoo.tex || exit 11
+  $_kpsewhich --safe-extended-out-name=/avar/ofoo.tex || exit 13
 TEXMFSYSVAR=/bvar \
-  $_kpsewhich --safe-extended-out-name=/bvar/ofoo.tex || exit 12
+  $_kpsewhich --safe-extended-out-name=/bvar/ofoo.tex || exit 14
 
+# In practice, TEXMFVAR=~/.texliveYYYY, so this is the case that matters,
+# but in principle it should work for TEXMFSYSVAR too.
+echo "TEXMF[SYS]VAR ok for writing when if set to ~/.something."
+TEXMFVAR='~/.xvar' \
+  $_kpsewhich --safe-extended-out-name='~/.xvar/ofoo.tex' || exit 15
+TEXMFSYSVAR='~/.yvar' \
+  $_kpsewhich --safe-extended-out-name='~/.yvar/ofoo.tex' || exit 16
+
+echo "~/.ssh not ok for writing if TEXMF[SYS]VAR is set ~/.foo."
+TEXMFVAR='~/.foo' \
+  $_kpsewhich --safe-extended-out-name='~/.ssh/ofoo.tex' && exit 17
+
 : # exit successfully if get to the end.

Modified: trunk/Build/source/texk/kpathsea/tex-file.c
===================================================================
--- trunk/Build/source/texk/kpathsea/tex-file.c	2024-01-27 22:48:16 UTC (rev 69614)
+++ trunk/Build/source/texk/kpathsea/tex-file.c	2024-01-27 23:45:24 UTC (rev 69615)
@@ -1200,7 +1200,7 @@
     checkdir             /* checkdir must be non-null */
     && *checkdir != '\0' /* checkdir must be non-empty */
     && fname == strstr (fname, checkdir)      /* fname must begin checkdir */
-    && IS_DIR_SEP (fname[strlen (checkdir)]); /* and be followed by /. */
+    && IS_DIR_SEP (fname[strlen (checkdir)]); /* and be followed by / */
 }
 
 /* Here is the general internal subroutine, kpathsea_name_ok, for
@@ -1226,6 +1226,8 @@
                   const_string default_choice, ok_type action,
                   boolean silent, boolean extended)
 {
+  const_string expanded_fname = NULL;
+
   /* We distinguish three cases:
      'a' (any)        allows any file to be opened.
      'r' (restricted) means disallowing special filenames.
@@ -1251,17 +1253,34 @@
   if (*open_choice == 'a' || *open_choice == 'y' || *open_choice == '1')
     return true;
 
+  /* Now we need to expand FNAME before doing the absolute-path checks,
+     since TEXMFVAR is typically ~/.texliveYYYY, and we want to allow it.  */
+  expanded_fname = kpathsea_expand (kpse, fname);
+
 #if defined (unix) && !defined (MSDOS)
   {
     /* Disallow .rhosts, .login, .ssh/, ..somefile, ..somedir/somefile,
-       etc.  But allow .tex (for base LaTeX).  */
+       etc.  But allow .tex (for base LaTeX).  Also specially allow
+       /foo/.whatever if extended, since it might match against
+       TEXMF[SYS]VAR below.  */
     const_string q;
     const_string qq = fname;
-    while ((q = strchr (qq, '.'))) {            /* at each dot */
+    while ((q = strchr (qq, '.'))) {            /* at each dot              */
       if ((q == fname || IS_DIR_SEP (*(q - 1))) /* start or / precedes dot? */
-          && !IS_DIR_SEP (*(q + 1))             /* ok if /./ */
-          && !(*(q + 1) == '.' && IS_DIR_SEP (*(q + 2))) /* ok  if /../ */
-          && !STREQ (q, ".tex")) {              /* specially allow .tex */
+          && !IS_DIR_SEP (*(q + 1))             /* ok if /./                */
+          && !(*(q + 1) == '.' && IS_DIR_SEP (*(q + 2))) /* ok if /../      */
+          && !STREQ (q, ".tex")                 /* specially allow .tex     */
+          && !(extended && kpathsea_absolute_p (kpse, expanded_fname, false))
+               /* Don't quit if EXTENDED and the input is absolute,
+                  because we want to allow TEXMFVAR=~/.texliveYYYY.  This
+                  is safe because absolute input paths will be checked
+                  below, and relative input paths will still be rejected here.
+                     
+                  This does not allow the case where TEXMFVAR=.foo and
+                  the input is .foo/bar, which in principle should be
+                  accepted, but since that's not useful in practice,
+                  let's not worry about it.  */
+         ) {
         goto not_ok;
       }
       qq = q + 1;
@@ -1276,23 +1295,23 @@
   if (*open_choice == 'r' || *open_choice == 'n' || *open_choice == '0')
     return true;
 
-  if (kpathsea_absolute_p (kpse, fname, false)) {
+  if (kpathsea_absolute_p (kpse, expanded_fname, false)) {
     /* We'll check TEXMF_OUTPUT_DIRECTORY first.  This must be an
        environment variable, not a configuration file setting.  */
     const_string texmfoutdir = getenv ("TEXMF_OUTPUT_DIRECTORY");
-    if (!abs_fname_ok (fname, texmfoutdir)) {
+    if (!abs_fname_ok (expanded_fname, texmfoutdir)) {
       /* That failed. Next, check TEXMFOUTPUT, but this can be in the
          configuration file (i.e., call kpse_var_value instead of getenv).  */
       const_string texmfoutput = kpathsea_var_value (kpse, "TEXMFOUTPUT");
-      if (!abs_fname_ok (fname, texmfoutput)) {
+      if (!abs_fname_ok (expanded_fname, texmfoutput)) {
         /* That failed too.  If `extended' is set, try TEXMFVAR and
            TEXMFSYSVAR.  */
         if (extended) {
           const_string texmfvar = kpathsea_var_value (kpse, "TEXMFVAR");
-          if (!abs_fname_ok (fname, texmfvar)) {
+          if (!abs_fname_ok (expanded_fname, texmfvar)) {
             const_string texmfsysvar
               = kpathsea_var_value (kpse, "TEXMFSYSVAR");
-            if (!abs_fname_ok (fname, texmfsysvar)) {
+            if (!abs_fname_ok (expanded_fname, texmfsysvar)) {
               goto not_ok; /* nothing left to check.  */
             }
           }
@@ -1302,6 +1321,11 @@
       }
     }
   }
+  /* else {
+      fprintf (stderr, "kpathsea_name_ok: not absolute %s\n", expanded_fname);
+    }
+  fprintf (stderr, "passed check abs_fname_ok(%s)\n", expanded_fname);
+  */
 
   /* For all pathnames, we disallow "../" at the beginning or "/../"
      anywhere. We need to check this for absolute paths, so fall through
@@ -1309,7 +1333,10 @@
      
      We don't try to resolve relative path elements and see if we end up
      in an acceptable directory, but rather simply consider the value as
-     a string. (It's ok if other programs do such resolution, though.)  */
+     a string. (It's ok if other programs do such resolution, though.)
+     
+     Here it does not matter in practice if we check against the
+     original or expanded FNAME, so just use the original.  */
   if (fname[0] == '.' && fname[1] == '.' && IS_DIR_SEP(fname[2]))
     goto not_ok;
   else {
@@ -1327,6 +1354,7 @@
   }
 
   /* We passed all tests.  */
+  if (expanded_fname) free ((void *) expanded_fname);
   return true;
 
  not_ok: /* Some test failed.  */
@@ -1334,6 +1362,7 @@
     fprintf (stderr, "\n%s: Not %s %s (%s = %s; %s extended check).\n",
              kpse->invocation_name, ok_type_name[action], fname,
              check_var, open_choice, extended ? "" : "no ");
+  if (expanded_fname) free ((void *) expanded_fname);
   return false;
 }
 



More information about the tex-live-commits mailing list.