diff --git a/master_changes.md b/master_changes.md index bf17f725264..770c8577cb4 100644 --- a/master_changes.md +++ b/master_changes.md @@ -72,6 +72,7 @@ users) ## Opamfile * The `url` file now only supports the legacy opam 1.2 fields [#6827 @kit-ty-kate] + * Filter fields in .install files containing destinations with `..` or absolute filepaths as parse errors [#6897 @kit-ty-kate] ## External dependencies * Restore the distribution detection on Gentoo [#6886 @kit-ty-kate - fix #6887] @@ -154,6 +155,7 @@ users) * Add more tests for depexts behaviour with unknown family types [#6489 @arozovyk] * Add disabled depexts tests [#6489 @rjbou] * Add depexts tests with debug section that demostrate system availability polling [#6489 @arozovyk] + * Add a test showing the behaviour of .install files containing destination filepath trying to escape their scope [#6897 @rjbou @kit-ty-kate] ### Engine @@ -177,6 +179,7 @@ users) * Correct configure instruction in README [#6858 @gridbugs @kit-ty-kate] ## Security fixes + * Invalidate .install fields containing destination filepath trying to escape their scope [#6897 @kit-ty-kate] # API updates ## opam-client @@ -235,3 +238,4 @@ users) * `OpamCompat.Map.add_to_list`: was added [#6818 @dra27] * `OpamSystem`: add `is_dir_read_only` [#6489 @rjbou] * `OpamFilename`: add `is_dir_read_only` [#6489 @rjbou] + * `OpamFilename.might_escape`: ensure / is detected as a file separator when called with `~sep:Unspecified` on Windows [#6897 @kit-ty-kate] diff --git a/src/core/opamFilename.ml b/src/core/opamFilename.ml index f53b9e30ce9..5e984a07953 100644 --- a/src/core/opamFilename.ml +++ b/src/core/opamFilename.ml @@ -11,10 +11,14 @@ let might_escape ~sep path = let sep = + let real_sep = function + | `Unix -> Re.char '/' + | `Windows -> Re.alt Re.[ char '\\'; char '/' ] + in match sep with - | `Unix -> Re.char '/' - | `Windows -> Re.alt Re.[ char '\\'; char '/' ] - | `Unspecified -> Re.str Filename.dir_sep + | `Unspecified when Sys.win32 -> real_sep `Windows + | `Unspecified -> real_sep `Unix + | `Unix | `Windows as sep -> real_sep sep in List.exists (String.equal Filename.parent_dir_name) Re.(split (compile sep) path) diff --git a/src/format/opamFile.ml b/src/format/opamFile.ml index 716fd4ea727..fb48ec8fe0b 100644 --- a/src/format/opamFile.ml +++ b/src/format/opamFile.ml @@ -3824,8 +3824,15 @@ module Dot_installSyntax = struct Pp.V.map_list ~depth:1 @@ Pp.V.map_option (Pp.V.string -| pp_optional) (Pp.opt @@ - Pp.singleton -| Pp.V.string -| - Pp.of_module "rel-filename" (module OpamFilename.Base)) + Pp.singleton -| Pp.V.string -| Pp.pp ~name:"rel-filename" + (fun ~pos s -> + if OpamFilename.might_escape ~sep:`Unspecified s then + Pp.bad_format ~pos "%s references its parent directory." s + else if Filename.is_relative s then + OpamFilename.Base.of_string s + else + Pp.bad_format ~pos "%s is an absolute filename." s) + OpamFilename.Base.to_string) in let pp_misc = Pp.V.map_list ~depth:1 @@ Pp.V.map_option diff --git a/tests/reftests/dot-install.test b/tests/reftests/dot-install.test index ac0310cc329..2f21d47239d 100644 --- a/tests/reftests/dot-install.test +++ b/tests/reftests/dot-install.test @@ -359,3 +359,118 @@ OPAM/rem-dir/lib OPAM/rem-dir/lib/shared OPAM/rem-dir/lib/stublibs OPAM/rem-dir/lib/toplevel +### OPAMDEBUG=0 +### unset OPAMDEBUGSECTIONS +### : Escapability +### +opam-version: "2.0" +install: [ "echo" "hellow" ] +### +lib: [ + "a-file" { "../../a-file" } + "fichier" { "/ab/so/lute/path/fichier" } + "dosiero" { "/tmp/../middle/dosiero" } + "good" { "good" } + ] +bin: [ + "a-file" { "../../a-file" } + "fichier" { "/ab/so/lute/path/fichier" } + "dosiero" { "/tmp/../middle/dosiero" } + "good" { "good" } + ] +etc: [ + "a-file" { "../../a-file" } + "fichier" { "/ab/so/lute/path/fichier" } + "dosiero" { "/tmp/../middle/dosiero" } + "good" { "good" } + ] +share: [ + "a-file" { "../../a-file" } + "fichier" { "/ab/so/lute/path/fichier" } + "dosiero" { "/tmp/../middle/dosiero" } + "good" { "good" } + ] +misc: [ + "a-file" { "../../a-file" } + "fichier" { "/ab/so/lute/path/fichier" } + "dosiero" { "/tmp/../middle/dosiero" } + "good" { "good" } + ] +### +hellow +### +bonjour +### +saluton +### +hallo +### opam update + +<><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> +[default] no changes from file://${BASEDIR}/REPO +### opam switch create escapability --empty +### OPAMDEBUGSECTIONS="SYSTEM" OPAMDEBUG=-5 +### opam install eskape +FILE(config) Read ${BASEDIR}/OPAM/config in 0.000s +SYSTEM LOCK ${BASEDIR}/OPAM/lock (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/repo/state-magicv.cache (read => none) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => read) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (read => none) +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/backup +The following actions will be performed: +=== install 1 package + - install eskape 1 + +<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> +SYSTEM rmdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1 +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/eskape.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/a-file +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/fichier +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/fichier +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/dosiero +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/dosiero +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/good +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/good +[WARNING] Errors in ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install, some fields have been ignored: + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install:2:14-2:28:: + ../../a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install:8:14-8:28:: + ../../a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install:26:14-26:28:: + ../../a-file is not an absolute filename. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install:20:14-20:28:: + ../../a-file references its parent directory. + - At ${BASEDIR}/OPAM/escapability/.opam-switch/build/eskape.1/eskape.install:14:14-14:28:: + ../../a-file references its parent directory. + +-> installed eskape.1 +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1 +SYSTEM mkdir ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1/files +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/eskape.install +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1/files/eskape.install +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/a-file +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1/files/a-file +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/fichier +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1/files/fichier +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/dosiero +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1/files/dosiero +SYSTEM read ${BASEDIR}/OPAM/repo/default/packages/eskape/eskape.1/files/good +SYSTEM write ${BASEDIR}/OPAM/escapability/.opam-switch/packages/eskape.1/files/good +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (none => write) +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/packages/cache (write => none) +Done. +SYSTEM LOCK ${BASEDIR}/OPAM/escapability/.opam-switch/lock (write => none) +SYSTEM rm ${BASEDIR}/OPAM/escapability/.opam-switch/backup/state-today.export +SYSTEM LOCK ${BASEDIR}/OPAM/repo/lock (none => none) +SYSTEM LOCK ${BASEDIR}/OPAM/config.lock (none => none) +### ocaml cat.ml escapability eskape +==> eskape installed file +Not found: ${BASEDIR}/OPAM/escapability/share/eskape/a-file +==> eskape changes +opam-version: "2.0"