From 8c7a68f3808a8d52f5cfc297a249ca4ef2480238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 16 Feb 2017 15:55:34 +0100 Subject: filename: Add safe_relative_path/1 Add safe_relative_path/1 to guard against directory traversal attacks. It either returns a shorter path without any ".." or "." components, or 'unsafe' if an ".." component would climb up above the root of the relative path. Here are a few examples: safe_relative_path("a/b/..") => "a" safe_relative_path("a/..") => "" safe_relative_path("a/../..") => unsafe safe_relative_path("/absolute/path") => unsafe The returned path can be used directly or combined with an absolute path using filename:join/2. --- lib/stdlib/src/filename.erl | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'lib/stdlib/src') diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl index c4586171ca..5d60b3837e 100644 --- a/lib/stdlib/src/filename.erl +++ b/lib/stdlib/src/filename.erl @@ -34,7 +34,8 @@ -export([absname/1, absname/2, absname_join/2, basename/1, basename/2, dirname/1, extension/1, join/1, join/2, pathtype/1, - rootname/1, rootname/2, split/1, nativename/1]). + rootname/1, rootname/2, split/1, nativename/1, + safe_relative_path/1]). -export([find_src/1, find_src/2, flatten/1]). -export([basedir/2, basedir/3]). @@ -750,6 +751,39 @@ separators() -> _ -> {false, false} end. +-spec safe_relative_path(Filename) -> 'unsafe' | SafeFilename when + Filename :: file:name_all(), + SafeFilename :: file:name_all(). + +safe_relative_path(Path) -> + case pathtype(Path) of + relative -> + Cs0 = split(Path), + safe_relative_path_1(Cs0, []); + _ -> + unsafe + end. + +safe_relative_path_1(["."|T], Acc) -> + safe_relative_path_1(T, Acc); +safe_relative_path_1([<<".">>|T], Acc) -> + safe_relative_path_1(T, Acc); +safe_relative_path_1([".."|T], Acc) -> + climb(T, Acc); +safe_relative_path_1([<<"..">>|T], Acc) -> + climb(T, Acc); +safe_relative_path_1([H|T], Acc) -> + safe_relative_path_1(T, [H|Acc]); +safe_relative_path_1([], []) -> + []; +safe_relative_path_1([], Acc) -> + join(lists:reverse(Acc)). + +climb(_, []) -> + unsafe; +climb(T, [_|Acc]) -> + safe_relative_path_1(T, Acc). + %% find_src(Module) -- -- cgit v1.2.3