[PATCH] inet: fix getservbyname buffer overflow

Michael Santos <>
Fri Jul 23 17:29:20 CEST 2010


The byte holding the length of the interface name for the getservbyname/2
function is used in a signed context and can become negative, causing
the buffer to be overrun. Make the same change for getservbyport/2.

Test case:
inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp).
---
 erts/emulator/drivers/common/inet_drv.c |    6 +++---
 lib/kernel/test/inet_SUITE.erl          |   11 +++++++++--
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 72deedf..1a6a9dd 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -6847,13 +6847,13 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len,
 
 	if (len < 2)
 	    return ctl_error(EINVAL, rbuf, rsize);
-	n = buf[0]; buf++; len--;
+	n = get_int8(buf); buf++; len--;
 	if (n >= len) /* the = sign makes the test inklude next length byte */
 	    return ctl_error(EINVAL, rbuf, rsize);
 	memcpy(namebuf, buf, n);
 	namebuf[n] = '\0';
 	len -= n; buf += n;
-	n = buf[0]; buf++; len--;
+	n = get_int8(buf); buf++; len--;
 	if (n > len)
 	    return ctl_error(EINVAL, rbuf, rsize);
 	memcpy(protobuf, buf, n);
@@ -6876,7 +6876,7 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len,
 	port = get_int16(buf);
 	port = sock_htons(port);
 	buf += 2;
-	n = buf[0]; buf++; len -= 3;
+	n = get_int8(buf); buf++; len -= 3;
 	if (n > len)
 	    return ctl_error(EINVAL, rbuf, rsize);
 	memcpy(protobuf, buf, n);
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index d475ec7..86c2a0c 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -27,7 +27,7 @@
 	 ipv4_to_ipv6/1, host_and_addr/1, parse/1, t_gethostnative/1, 
 	 gethostnative_parallell/1, cname_loop/1, 
          gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1,
-	 getif_ifr_name_overflow/1]).
+	 getif_ifr_name_overflow/1,getservbyname_overflow/1]).
 
 -export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
 	 kill_gethost/0, parallell_gethost/0]).
@@ -40,7 +40,7 @@ all(suite) ->
      ipv4_to_ipv6, host_and_addr, parse,t_gethostnative, 
      gethostnative_parallell, cname_loop,
      gethostnative_debug_level,gethostnative_soft_restart,
-     getif,getif_ifr_name_overflow].
+     getif,getif_ifr_name_overflow,getservbyname_overflow].
 
 init_per_testcase(_Func, Config) ->
     Dog = test_server:timetrap(test_server:seconds(60)),
@@ -899,6 +899,13 @@ getif_ifr_name_overflow(Config) when is_list(Config) ->
     ?line {ok,[]} = inet:ifget(lists:duplicate(128, "x"), [addr]),
     ok.
 
+getservbyname_overflow(doc) ->
+    "Test long service names do not overrun buffer";
+getservbyname_overflow(Config) when is_list(Config) ->
+    %% emulator should not crash
+    ?line {error,einval} = inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp),
+    ok.
+
 %% Works just like lists:member/2, except that any {127,_,_,_} tuple
 %% matches any other {127,_,_,_}. We do this to handle Linux systems
 %% that use (for instance) 127.0.1.1 as the IP address for the hostname.
-- 
1.5.6.4


More information about the erlang-patches mailing list