diff options
| -rw-r--r-- | mesonbuild/interpreter/interpreter.py | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index a118b3c59..dd91474eb 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -292,6 +292,7 @@ class Interpreter(InterpreterBase, HoldableObject): self.sanity_check_ast() self.builtin.update({'meson': MesonMain(self.build, self)}) self.processed_buildfiles: T.Set[str] = set() + self.validated_cache: T.Set[str] = set() self.project_args_frozen = False self.global_args_frozen = False # implies self.project_args_frozen self.subprojects: T.Dict[str, SubprojectHolder] = {} @@ -3129,27 +3130,37 @@ class Interpreter(InterpreterBase, HoldableObject): # subproject files, as long as they are scheduled to be installed. if validate_installable_file(norm): return - norm = Path(os.path.abspath(Path(srcdir, subdir, fname))) - if os.path.isdir(norm): - inputtype = 'directory' - else: - inputtype = 'file' - if InterpreterRuleRelaxation.ALLOW_BUILD_DIR_FILE_REFERENCES in self.relaxations and builddir in norm.parents: - return - if srcdir not in norm.parents: - # Grabbing files outside the source tree is ok. - # This is for vendor stuff like: - # - # /opt/vendorsdk/src/file_with_license_restrictions.c - return - project_root = Path(srcdir, self.root_subdir) - subproject_dir = project_root / self.subproject_dir - if norm == project_root: + + def do_validate_within_subproject(norm: Path) -> None: + if os.path.isdir(norm): + inputtype = 'directory' + else: + inputtype = 'file' + if InterpreterRuleRelaxation.ALLOW_BUILD_DIR_FILE_REFERENCES in self.relaxations and builddir in norm.parents: + return + if srcdir not in norm.parents: + # Grabbing files outside the source tree is ok. + # This is for vendor stuff like: + # + # /opt/vendorsdk/src/file_with_license_restrictions.c + return + project_root = Path(srcdir, self.root_subdir) + subproject_dir = project_root / self.subproject_dir + if norm == project_root: + return + if project_root not in norm.parents: + raise InterpreterException(f'Sandbox violation: Tried to grab {inputtype} {norm.name} outside current (sub)project.') + if subproject_dir == norm or subproject_dir in norm.parents: + raise InterpreterException(f'Sandbox violation: Tried to grab {inputtype} {norm.name} from a nested subproject.') + + fname = os.path.join(subdir, fname) + if fname in self.validated_cache: return - if project_root not in norm.parents: - raise InterpreterException(f'Sandbox violation: Tried to grab {inputtype} {norm.name} outside current (sub)project.') - if subproject_dir == norm or subproject_dir in norm.parents: - raise InterpreterException(f'Sandbox violation: Tried to grab {inputtype} {norm.name} from a nested subproject.') + + # Use os.path.abspath() to eliminate .. segments, but do not resolve symlinks + norm = Path(os.path.abspath(Path(srcdir, fname))) + do_validate_within_subproject(norm) + self.validated_cache.add(fname) @T.overload def source_strings_to_files(self, sources: T.List['mesonlib.FileOrString'], strict: bool = True) -> T.List['mesonlib.File']: ... |
