commit bc7188bc292d7f41d7dd0567d535cf1614cee597
Author: Peter Lemenkov <lemenkov(a)gmail.com>
Date: Mon Nov 17 16:43:43 2014 +0300
Fixed CVE-2014-1693 (backported fix from ver. 17.x.x, see patch no. 17)
Signed-off-by: Peter Lemenkov <lemenkov(a)gmail.com>
erlang.spec | 9 +-
...rc-ftp-ftp.erl-Check-the-filenames-userna.patch | 430 ++++++++++++++++++++
2 files changed, 438 insertions(+), 1 deletions(-)
---
diff --git a/erlang.spec b/erlang.spec
index a221252..659fdbd 100644
--- a/erlang.spec
+++ b/erlang.spec
@@ -25,7 +25,7 @@
Name: erlang
Version: %{upstream_ver}
-Release: %{upstream_rel_for_rpm}.8%{?dist}
+Release: %{upstream_rel_for_rpm}.9%{?dist}
Summary: General-purpose programming language and runtime environment
Group: Development/Languages
@@ -104,6 +104,9 @@ Patch15: otp-0015-Expose-NIF-version.patch
# Fedora specific patch
# Split off webtool dependency from tools
Patch16: otp-0016-Split-off-webtool-dependency-from-tools.patch
+# Fedora specific patch
+# lib/inets/src/ftp/ftp.erl: Check the filenames, usernames,
+Patch17: otp-0017-lib-inets-src-ftp-ftp.erl-Check-the-filenames-userna.patch
# end of autogenerated patch tag list
BuildRequires: lksctp-tools-devel
@@ -985,6 +988,7 @@ Erlang mode for XEmacs (source lisp files).
%patch14 -p1 -b .Install_internal_hrl_files_when_necessary
%patch15 -p1 -b .Expose_NIF_version
%patch16 -p1 -b .Split_off_webtool_dependency_from_tools
+%patch17 -p1 -b .lib_inets_src_ftp_ftp_erl_Check_the_filenames_userna
# end of autogenerated prep patch list
# FIXME we should come up with a better solution
@@ -2316,6 +2320,9 @@ useradd -r -g epmd -d /tmp -s /sbin/nologin \
%changelog
+* Mon Nov 17 2014 Peter Lemenkov <lemenkov(a)gmail.com> - R16B-03.9
+- Fixed CVE-2014-1693 (backported fix from ver. 17.x.x, see patch no. 17)
+
* Tue Nov 11 2014 Peter Lemenkov <lemenkov(a)gmail.com> - R16B-03.8
- Trimmed dependency chain
- Cleaned up spec-file
diff --git a/otp-0017-lib-inets-src-ftp-ftp.erl-Check-the-filenames-userna.patch
b/otp-0017-lib-inets-src-ftp-ftp.erl-Check-the-filenames-userna.patch
new file mode 100644
index 0000000..7b7ad77
--- /dev/null
+++ b/otp-0017-lib-inets-src-ftp-ftp.erl-Check-the-filenames-userna.patch
@@ -0,0 +1,430 @@
+From: Sergei Golovan <sgolovan(a)gmail.com>
+Date: Sun, 9 Feb 2014 23:06:25 +0400
+Subject: [PATCH] lib/inets/src/ftp/ftp.erl: Check the filenames, usernames,
+ passwords etc. for <CR> and <LF> in them and return error if these
+ offending chars are found. See
+
http://erlang.org/pipermail/erlang-bugs/2014-January/003998.html for
+ details. lib/inets/test/ftp_suite_lib.erl: Added checks for <CR><LF> in
file
+ and directory names.
+
+
+diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
+index 520db1b..5674599 100644
+--- a/lib/inets/src/ftp/ftp.erl
++++ b/lib/inets/src/ftp/ftp.erl
+@@ -192,7 +192,12 @@ do_open(Pid, OpenOptions, TLSOpts) ->
+ 'ok' | {'error', Reason :: 'euser' | common_reason()}.
+
+ user(Pid, User, Pass) ->
+- call(Pid, {user, User, Pass}, atom).
++ case {is_name_sane(User), is_name_sane(Pass)} of
++ {true, true} ->
++ call(Pid, {user, User, Pass}, atom);
++ _ ->
++ {error, euser}
++ end.
+
+ -spec user(Pid :: pid(),
+ User :: string(),
+@@ -201,7 +206,12 @@ user(Pid, User, Pass) ->
+ 'ok' | {'error', Reason :: 'euser' | common_reason()}.
+
+ user(Pid, User, Pass, Acc) ->
+- call(Pid, {user, User, Pass, Acc}, atom).
++ case {is_name_sane(User), is_name_sane(Pass), is_name_sane(Acc)} of
++ {true, true, true} ->
++ call(Pid, {user, User, Pass, Acc}, atom);
++ _ ->
++ {error, euser}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -216,7 +226,12 @@ user(Pid, User, Pass, Acc) ->
+ 'ok' | {'error', Reason :: 'eacct' | common_reason()}.
+
+ account(Pid, Acc) ->
+- call(Pid, {account, Acc}, atom).
++ case is_name_sane(Acc) of
++ true ->
++ call(Pid, {account, Acc}, atom);
++ _ ->
++ {error, eacct}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -262,7 +277,12 @@ lpwd(Pid) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ cd(Pid, Dir) ->
+- call(Pid, {cd, Dir}, atom).
++ case is_name_sane(Dir) of
++ true ->
++ call(Pid, {cd, Dir}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -305,7 +325,12 @@ ls(Pid) ->
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+ ls(Pid, Dir) ->
+- call(Pid, {dir, long, Dir}, string).
++ case is_name_sane(Dir) of
++ true ->
++ call(Pid, {dir, long, Dir}, string);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -333,7 +358,12 @@ nlist(Pid) ->
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+ nlist(Pid, Dir) ->
+- call(Pid, {dir, short, Dir}, string).
++ case is_name_sane(Dir) of
++ true ->
++ call(Pid, {dir, short, Dir}, string);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -349,7 +379,12 @@ nlist(Pid, Dir) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ rename(Pid, Old, New) ->
+- call(Pid, {rename, Old, New}, string).
++ case {is_name_sane(Old), is_name_sane(New)} of
++ {true, true} ->
++ call(Pid, {rename, Old, New}, string);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -365,7 +400,12 @@ rename(Pid, Old, New) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ delete(Pid, File) ->
+- call(Pid, {delete, File}, string).
++ case is_name_sane(File) of
++ true ->
++ call(Pid, {delete, File}, string);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -380,7 +420,12 @@ delete(Pid, File) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ mkdir(Pid, Dir) ->
+- call(Pid, {mkdir, Dir}, atom).
++ case is_name_sane(Dir) of
++ true ->
++ call(Pid, {mkdir, Dir}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -395,7 +440,12 @@ mkdir(Pid, Dir) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ rmdir(Pid, Dir) ->
+- call(Pid, {rmdir, Dir}, atom).
++ case is_name_sane(Dir) of
++ true ->
++ call(Pid, {rmdir, Dir}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -437,7 +487,12 @@ recv(Pid, RemotFileName) ->
+ 'ok' | {'error', Reason :: term()}.
+
+ recv(Pid, RemotFileName, LocalFileName) ->
+- call(Pid, {recv, RemotFileName, LocalFileName}, atom).
++ case is_name_sane(RemotFileName) of
++ true ->
++ call(Pid, {recv, RemotFileName, LocalFileName}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -456,7 +511,12 @@ recv(Pid, RemotFileName, LocalFileName) ->
+ {'error', Reason :: restriction_reason() | common_reason()}.
+
+ recv_bin(Pid, RemoteFile) ->
+- call(Pid, {recv_bin, RemoteFile}, bin).
++ case is_name_sane(RemoteFile) of
++ true ->
++ call(Pid, {recv_bin, RemoteFile}, bin);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -473,7 +533,12 @@ recv_bin(Pid, RemoteFile) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ recv_chunk_start(Pid, RemoteFile) ->
+- call(Pid, {recv_chunk_start, RemoteFile}, atom).
++ case is_name_sane(RemoteFile) of
++ true ->
++ call(Pid, {recv_chunk_start, RemoteFile}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -521,7 +586,12 @@ send(Pid, LocalFileName) ->
+ shortage_reason()}.
+
+ send(Pid, LocalFileName, RemotFileName) ->
+- call(Pid, {send, LocalFileName, RemotFileName}, atom).
++ case is_name_sane(RemotFileName) of
++ true ->
++ call(Pid, {send, LocalFileName, RemotFileName}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -541,7 +611,12 @@ send(Pid, LocalFileName, RemotFileName) ->
+ shortage_reason()}.
+
+ send_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
+- call(Pid, {send_bin, Bin, RemoteFile}, atom);
++ case is_name_sane(RemoteFile) of
++ true ->
++ call(Pid, {send_bin, Bin, RemoteFile}, atom);
++ _ ->
++ {error, efnamena}
++ end;
+ send_bin(_Pid, _Bin, _RemoteFile) ->
+ {error, enotbinary}.
+
+@@ -559,7 +634,12 @@ send_bin(_Pid, _Bin, _RemoteFile) ->
+ 'ok' | {'error', Reason :: restriction_reason() | common_reason()}.
+
+ send_chunk_start(Pid, RemoteFile) ->
+- call(Pid, {send_chunk_start, RemoteFile}, atom).
++ case is_name_sane(RemoteFile) of
++ true ->
++ call(Pid, {send_chunk_start, RemoteFile}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -575,7 +655,12 @@ send_chunk_start(Pid, RemoteFile) ->
+ 'ok' | {'error', Reason :: term()}.
+
+ append_chunk_start(Pid, RemoteFile) ->
+- call(Pid, {append_chunk_start, RemoteFile}, atom).
++ case is_name_sane(RemoteFile) of
++ true ->
++ call(Pid, {append_chunk_start, RemoteFile}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -683,7 +768,12 @@ append(Pid, LocalFileName) ->
+ 'ok' | {'error', Reason :: term()}.
+
+ append(Pid, LocalFileName, RemotFileName) ->
+- call(Pid, {append, LocalFileName, RemotFileName}, atom).
++ case is_name_sane(RemotFileName) of
++ true ->
++ call(Pid, {append, LocalFileName, RemotFileName}, atom);
++ _ ->
++ {error, efnamena}
++ end.
+
+
+ %%--------------------------------------------------------------------------
+@@ -705,7 +795,12 @@ append(Pid, LocalFileName, RemotFileName) ->
+ shortage_reason()}.
+
+ append_bin(Pid, Bin, RemoteFile) when is_binary(Bin) ->
+- call(Pid, {append_bin, Bin, RemoteFile}, atom);
++ case is_name_sane(RemoteFile) of
++ true ->
++ call(Pid, {append_bin, Bin, RemoteFile}, atom);
++ _ ->
++ {error, efnamena}
++ end;
+ append_bin(_Pid, _Bin, _RemoteFile) ->
+ {error, enotbinary}.
+
+@@ -2302,6 +2397,15 @@ send_bin(State, Bin) ->
+ mk_cmd(Fmt, Args) ->
+ [io_lib:format(Fmt, Args)| [?CR, ?LF]]. % Deep list ok.
+
++is_name_sane([]) ->
++ true;
++is_name_sane([?CR| _]) ->
++ false;
++is_name_sane([?LF| _]) ->
++ false;
++is_name_sane([_| Rest]) ->
++ is_name_sane(Rest).
++
+ pwd_result(Lines) ->
+ {_, [?DOUBLE_QUOTE | Rest]} =
+ lists:splitwith(fun(?DOUBLE_QUOTE) -> false; (_) -> true end, Lines),
+diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl
+index 35f21cc..daee1bd 100644
+--- a/lib/inets/test/ftp_suite_lib.erl
++++ b/lib/inets/test/ftp_suite_lib.erl
+@@ -1266,6 +1266,8 @@ read_log_6035([]) ->
+ %%--------------------------------------------------------------------
+ do_user(Pid) ->
+ {error, euser} = ftp:user(Pid, ?BAD_USER, ?FTP_PASS),
++ {error, euser} = ftp:user(Pid, ?FTP_USER++"\r\nPASS "++?FTP_PASS,
?FTP_PASS),
++ {error, euser} = ftp:user(Pid, ?FTP_USER, ?FTP_PASS++"\r\nCWD ."),
+ ok = ftp:user(Pid, ?FTP_USER, ?FTP_PASS),
+ ok.
+
+@@ -1278,6 +1280,7 @@ do_pwd(Pid) ->
+ do_cd(Pid) ->
+ ok = ftp:cd(Pid, "/pub"),
+ {error, epath} = ftp:cd(Pid, ?BAD_DIR),
++ {error, efnamena} = ftp:cd(Pid, "/pub\r\nCWD ."),
+ ok.
+
+ do_lcd(Pid, Dir) ->
+@@ -1294,11 +1297,14 @@ do_ls(Pid) ->
+ %% directory, but can also be a filename or a group
+ %% of files (including wildcards).
+ {ok, _} = ftp:ls(Pid, "incom*"),
++ %% but \r\n can't be in the wildcard
++ {error, efnamena} = ftp:ls(Pid, "incoming\r\nCWD ."),
+ ok.
+
+ do_nlist(Pid, WildcardSupport) ->
+ {ok, _} = ftp:nlist(Pid),
+ {ok, _} = ftp:nlist(Pid, "incoming"),
++ {error, efnamena} = ftp:ls(Pid, "incoming\r\nCWD ."),
+ %% neither nlist nor ls operates on a directory
+ %% they operate on a pathname, which *can* be a
+ %% directory, but can also be a filename or a group
+@@ -1324,6 +1330,8 @@ do_rename(Pid, Config) ->
+ ftp:delete(Pid, NewLFile), % reset
+ ok = ftp:send(Pid, LFile),
+ {error, epath} = ftp:rename(Pid, NewLFile, LFile),
++ {error, efnamena} = ftp:rename(Pid, NewLFile++"\r\nRNTO
"++LFile++"\r\nRNFR "++NewLFile, LFile),
++ {error, efnamena} = ftp:rename(Pid, NewLFile, LFile++"\r\nCWD ."),
+ ok = ftp:rename(Pid, LFile, NewLFile),
+ ftp:delete(Pid, LFile), % cleanup
+ ftp:delete(Pid, NewLFile), % cleanup
+@@ -1338,6 +1346,7 @@ do_delete(Pid, Config) ->
+ ok = ftp:cd(Pid, "incoming"),
+ ok = ftp:lcd(Pid, PrivDir),
+ ftp:delete(Pid,LFile), % reset
++ {error, efnamena} = ftp:delete(Pid,LFile++"\r\nCWD ."),
+ ok = ftp:send(Pid, LFile),
+ ok = ftp:delete(Pid,LFile),
+ ok.
+@@ -1348,6 +1357,8 @@ do_mkdir(Pid) ->
+ integer_to_list(B) ++ "_" ++ integer_to_list(C),
+ ok = ftp:cd(Pid, "incoming"),
+ {ok, CurrDir} = ftp:pwd(Pid),
++ {error, efnamena} = ftp:mkdir(Pid, NewDir++"\r\nCWD ."),
++ {error, efnamena} = ftp:rmdir(Pid, NewDir++"\r\nCWD ."),
+ ok = ftp:mkdir(Pid, NewDir),
+ ok = ftp:cd(Pid, NewDir),
+ ok = ftp:cd(Pid, CurrDir),
+@@ -1363,6 +1374,7 @@ do_send(Pid, Config) ->
+ ok = file:write_file(AbsLFile, list_to_binary(Contents)),
+ ok = ftp:cd(Pid, "incoming"),
+ ok = ftp:lcd(Pid, PrivDir),
++ {error, efnamena} = ftp:send(Pid, LFile, RFile++"1\r\nCWD ."),
+ ok = ftp:send(Pid, LFile, RFile),
+ {ok, RFilesString} = ftp:nlist(Pid),
+ RFiles = split(RFilesString),
+@@ -1392,6 +1404,7 @@ do_append(Pid, Config) ->
+ ftp:delete(Pid, RFile),
+ ftp:delete(Pid, LFile),
+
++ {error, efnamena} = ftp:append(Pid, LFile, RFile++"1\r\nCWD ."),
+ ok = ftp:append(Pid, LFile, RFile),
+ ok = ftp:append(Pid, LFile, RFile),
+ ok = ftp:append(Pid, LFile),
+@@ -1413,6 +1426,7 @@ do_send_bin(Pid, Config) ->
+ Bin = list_to_binary(Contents),
+ ok = ftp:cd(Pid, "incoming"),
+ {error, enotbinary} = ftp:send_bin(Pid, Contents, File),
++ {error, efnamena} = ftp:send_bin(Pid, Bin, File++"1\r\nCWD ."),
+ ok = ftp:send_bin(Pid, Bin, File),
+ {ok, RFilesString} = ftp:nlist(Pid),
+ RFiles = split(RFilesString),
+@@ -1426,6 +1440,7 @@ do_append_bin(Pid, Config) ->
+ Bin = list_to_binary(Contents),
+ ok = ftp:cd(Pid, "incoming"),
+ {error, enotbinary} = ftp:append_bin(Pid, Contents, File),
++ {error, efnamena} = ftp:append_bin(Pid, Bin, File++"1\r\nCWD ."),
+ ok = ftp:append_bin(Pid, Bin, File),
+ ok = ftp:append_bin(Pid, Bin, File),
+ %% Control the contents of the file
+@@ -1438,6 +1453,7 @@ do_send_chunk(Pid, Config) ->
+ Contents = "ftp_SUITE test ...",
+ Bin = list_to_binary(Contents),
+ ok = ftp:cd(Pid, "incoming"),
++ {error, efnamena} = ftp:send_chunk_start(Pid, File++"1\r\nCWD ."),
+ ok = ftp:send_chunk_start(Pid, File),
+ {error, echunk} = ftp:cd(Pid, "incoming"),
+ {error, enotbinary} = ftp:send_chunk(Pid, Contents),
+@@ -1454,6 +1470,7 @@ do_append_chunk(Pid, Config) ->
+ File = ?config(file, Config),
+ Contents = ["ER","LE","RL"],
+ ok = ftp:cd(Pid, "incoming"),
++ {error, efnamena} = ftp:append_chunk_start(Pid, File++"1\r\nCWD ."),
+ ok = ftp:append_chunk_start(Pid, File),
+ {error, enotbinary} = ftp:append_chunk(Pid, lists:nth(1,Contents)),
+ ok = ftp:append_chunk(Pid,list_to_binary(lists:nth(1,Contents))),
+@@ -1480,6 +1497,7 @@ do_recv(Pid, Config) ->
+ ok = file:delete(AbsFile), % cleanup
+ test_server:sleep(100),
+ ok = ftp:lcd(Pid, PrivDir),
++ {error, efnamena} = ftp:recv(Pid, File++"\r\nCWD ."),
+ ok = ftp:recv(Pid, File),
+ {ok, Files} = file:list_dir(PrivDir),
+ true = lists:member(File, Files),
+@@ -1495,6 +1513,7 @@ do_recv_bin(Pid, Config) ->
+ ok = ftp:cd(Pid, "incoming"),
+ ok = ftp:send_bin(Pid, Bin1, File),
+ test_server:sleep(100),
++ {error, efnamena} = ftp:recv_bin(Pid, File++"\r\nCWD ."),
+ {ok, Bin2} = ftp:recv_bin(Pid, File),
+ ok = ftp:delete(Pid, File), % cleanup
+ Contents2 = binary_to_list(Bin2),
+@@ -1520,6 +1539,7 @@ do_recv_chunk(Pid, Config) ->
+ ok = ftp:send_bin(Pid, Bin1, File),
+ test_server:sleep(100),
+ {error, "ftp:recv_chunk_start/2 not called"} = recv_chunk(Pid,
<<>>),
++ {error, efnamena} = ftp:recv_chunk_start(Pid, File++"\r\nCWD ."),
+ ok = ftp:recv_chunk_start(Pid, File),
+ {ok, Contents2} = recv_chunk(Pid, <<>>),
+ ok = ftp:delete(Pid, File), % cleanup