diff options
author | Karl Berry <karl@freefriends.org> | 2024-01-27 23:45:24 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-01-27 23:45:24 +0000 |
commit | b61ce1e994d76bc20ebdbc201c187bd9d1ae943a (patch) | |
tree | c339a33a454bf74023cd90c9d633d3687c4f83fb /Build/source/texk/kpathsea | |
parent | 9513319f6e942568566a4e53e084a28786639d6a (diff) |
kpse_safe: allow /dir/.foo if extended and matches TEXMF[SYS]VAR
git-svn-id: svn://tug.org/texlive/trunk@69615 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/kpathsea')
-rw-r--r-- | Build/source/texk/kpathsea/ChangeLog | 8 | ||||
-rwxr-xr-x | Build/source/texk/kpathsea/tests/kpsesafe.test | 30 | ||||
-rw-r--r-- | Build/source/texk/kpathsea/tex-file.c | 53 |
3 files changed, 72 insertions, 19 deletions
diff --git a/Build/source/texk/kpathsea/ChangeLog b/Build/source/texk/kpathsea/ChangeLog index 624632621eb..c76e4c69ab2 100644 --- a/Build/source/texk/kpathsea/ChangeLog +++ b/Build/source/texk/kpathsea/ChangeLog @@ -1,3 +1,11 @@ +2024-01-27 Karl Berry <karl@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@freefriends.org> * tex-file.c (kpse_{in,out}_name_ok{,_silent}_extended): diff --git a/Build/source/texk/kpathsea/tests/kpsesafe.test b/Build/source/texk/kpathsea/tests/kpsesafe.test index 11853ac046c..99b85c15b14 100755 --- a/Build/source/texk/kpathsea/tests/kpsesafe.test +++ b/Build/source/texk/kpathsea/tests/kpsesafe.test @@ -21,21 +21,37 @@ echo "/rootdir ok for reading, not writing." $_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. diff --git a/Build/source/texk/kpathsea/tex-file.c b/Build/source/texk/kpathsea/tex-file.c index 203841075ee..a9f7c4977be 100644 --- a/Build/source/texk/kpathsea/tex-file.c +++ b/Build/source/texk/kpathsea/tex-file.c @@ -1200,7 +1200,7 @@ abs_fname_ok (const_string fname, const_string checkdir) 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 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, 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 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, 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 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, 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 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, } } } + /* 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 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, 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 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, } /* We passed all tests. */ + if (expanded_fname) free ((void *) expanded_fname); return true; not_ok: /* Some test failed. */ @@ -1334,6 +1362,7 @@ kpathsea_name_ok (kpathsea kpse, const_string fname, const_string check_var, 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; } |