Skip to content

Commit 6d9466a

Browse files
committed
strengthening the frame buffer handling
1 parent 5c96610 commit 6d9466a

File tree

1 file changed

+90
-7
lines changed

1 file changed

+90
-7
lines changed

ext/sockets/sockets.c

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,17 @@ PHP_FUNCTION(socket_bind)
14501450
return FAILURE; \
14511451
} \
14521452
} while (0)
1453+
1454+
static zend_result php_socket_get_chunk(zend_string *dst, const zend_string *src, size_t offset, size_t len) {
1455+
if (UNEXPECTED((offset > SIZE_MAX - len) || offset + len > ZSTR_LEN(src))) {
1456+
return FAILURE;
1457+
}
1458+
1459+
memcpy(ZSTR_VAL(dst), ZSTR_VAL(src) + offset, len);
1460+
ZSTR_LEN(dst) = len;
1461+
return SUCCESS;
1462+
}
1463+
14531464
static zend_result php_socket_afpacket_add_tcp(unsigned char *ipdata, struct sockaddr_ll sll, char *ifrname, zend_string *recv_buf,
14541465
size_t slen, zval *szpayload, zval *zpayload, zval *obj, zval *arg2, zval *arg5, zval *arg6) {
14551466
struct tcphdr a;
@@ -1614,7 +1625,7 @@ PHP_FUNCTION(socket_recvfrom)
16141625
}
16151626
#endif
16161627

1617-
recv_buf = zend_string_alloc(arg3 + 1, 0);
1628+
recv_buf = zend_string_alloc(arg3 + 1, false);
16181629

16191630
switch (php_sock->type) {
16201631
case AF_UNIX:
@@ -1700,6 +1711,7 @@ PHP_FUNCTION(socket_recvfrom)
17001711
zend_argument_value_error(1, "must be SOCK_RAW socket type");
17011712
RETURN_THROWS();
17021713
}
1714+
zend_string *dst_buf;
17031715
slen = sizeof(sll);
17041716
memset(&sll, 0, sizeof(sll));
17051717
sll.sll_family = AF_PACKET;
@@ -1726,7 +1738,18 @@ PHP_FUNCTION(socket_recvfrom)
17261738
RETURN_FALSE;
17271739
}
17281740

1729-
struct ethhdr *e = (struct ethhdr *)ZSTR_VAL(recv_buf);
1741+
dst_buf = zend_string_alloc(arg3, false);
1742+
1743+
if (php_socket_get_chunk(dst_buf, recv_buf, 0, ETH_HLEN) == FAILURE) {
1744+
zend_value_error("invalid ethernet frame buffer length");
1745+
zend_string_efree(dst_buf);
1746+
zend_string_efree(recv_buf);
1747+
RETURN_THROWS();
1748+
}
1749+
1750+
struct ethhdr a;
1751+
memcpy(&a, ZSTR_VAL(dst_buf), ETH_HLEN);
1752+
struct ethhdr *e = &a;
17301753
unsigned short protocol = ntohs(e->h_proto);
17311754
unsigned char *payload;
17321755

@@ -1739,7 +1762,13 @@ PHP_FUNCTION(socket_recvfrom)
17391762

17401763
switch (protocol) {
17411764
case ETH_P_IP: {
1742-
payload = ((unsigned char *)e + ETH_HLEN);
1765+
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, sizeof(struct iphdr)) == FAILURE) {
1766+
zend_value_error("invalid ipv4 frame buffer length");
1767+
zend_string_efree(dst_buf);
1768+
zend_string_efree(recv_buf);
1769+
RETURN_THROWS();
1770+
}
1771+
payload = ((unsigned char *)ZSTR_VAL(dst_buf));
17431772
struct iphdr a;
17441773
memcpy(&a, payload, sizeof(a));
17451774
struct iphdr *ip = &a;
@@ -1750,6 +1779,7 @@ PHP_FUNCTION(socket_recvfrom)
17501779
ZVAL_NULL(&zpayload);
17511780
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
17521781
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
1782+
zend_string_efree(dst_buf);
17531783
zend_string_efree(recv_buf);
17541784
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
17551785
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
@@ -1760,7 +1790,6 @@ PHP_FUNCTION(socket_recvfrom)
17601790
zend_value_error("invalid transport header length");
17611791
RETURN_THROWS();
17621792
}
1763-
unsigned char *ipdata = payload + tlayer;
17641793
struct in_addr s, d;
17651794
s.s_addr = ip->saddr;
17661795
d.s_addr = ip->daddr;
@@ -1773,13 +1802,31 @@ PHP_FUNCTION(socket_recvfrom)
17731802

17741803
switch (ip->protocol) {
17751804
case IPPROTO_TCP: {
1805+
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, sizeof(struct tcphdr)) == FAILURE) {
1806+
zend_value_error("invalid tcp frame buffer length");
1807+
zend_string_efree(dst_buf);
1808+
zend_string_efree(recv_buf);
1809+
RETURN_THROWS();
1810+
}
1811+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
17761812
if (php_socket_afpacket_add_tcp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
1813+
zend_string_efree(dst_buf);
1814+
zend_string_efree(recv_buf);
17771815
RETURN_THROWS();
17781816
}
17791817
break;
17801818
}
17811819
case IPPROTO_UDP: {
1820+
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, sizeof(struct udphdr)) == FAILURE) {
1821+
zend_value_error("invalid udp frame buffer length");
1822+
zend_string_efree(dst_buf);
1823+
zend_string_efree(recv_buf);
1824+
RETURN_THROWS();
1825+
}
1826+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
17821827
if (php_socket_afpacket_add_udp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
1828+
zend_string_efree(dst_buf);
1829+
zend_string_efree(recv_buf);
17831830
RETURN_THROWS();
17841831
}
17851832
break;
@@ -1788,6 +1835,7 @@ PHP_FUNCTION(socket_recvfrom)
17881835
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
17891836
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
17901837
zend_string_efree(recv_buf);
1838+
zend_string_efree(dst_buf);
17911839
Z_DELREF(zpayload);
17921840
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
17931841
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
@@ -1801,7 +1849,13 @@ PHP_FUNCTION(socket_recvfrom)
18011849
break;
18021850
}
18031851
case ETH_P_IPV6: {
1804-
payload = ((unsigned char *)e + ETH_HLEN);
1852+
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, sizeof(struct iphdr)) == FAILURE) {
1853+
zend_value_error("invalid ipv4 frame buffer length");
1854+
zend_string_efree(dst_buf);
1855+
zend_string_efree(recv_buf);
1856+
RETURN_THROWS();
1857+
}
1858+
payload = ((unsigned char *)ZSTR_VAL(dst_buf));
18051859
struct ipv6hdr a;
18061860
memcpy(&a, payload, sizeof(a));
18071861
struct ipv6hdr *ip = &a;
@@ -1811,6 +1865,7 @@ PHP_FUNCTION(socket_recvfrom)
18111865
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
18121866
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
18131867
zend_string_efree(recv_buf);
1868+
zend_string_efree(dst_buf);
18141869
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
18151870
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
18161871

@@ -1830,17 +1885,34 @@ PHP_FUNCTION(socket_recvfrom)
18301885
zend_update_property_long(Z_OBJCE(zpayload), Z_OBJ(zpayload), ZEND_STRL("headerSize"), totalip);
18311886
zend_update_property_stringl(Z_OBJCE(zpayload), Z_OBJ(zpayload), ZEND_STRL("rawPacket"), (char *)payload, totalip);
18321887
unsigned char ipprotocol = ip->nexthdr;
1833-
unsigned char *ipdata = payload + sizeof(*ip);
18341888

18351889
switch (ipprotocol) {
18361890
case IPPROTO_TCP: {
1891+
if (php_socket_get_chunk(dst_buf, recv_buf, sizeof(*ip), sizeof(struct tcphdr)) == FAILURE) {
1892+
zend_value_error("invalid tcp frame buffer length");
1893+
zend_string_efree(dst_buf);
1894+
zend_string_efree(recv_buf);
1895+
RETURN_THROWS();
1896+
}
1897+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18371898
if (php_socket_afpacket_add_tcp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
1899+
zend_string_efree(dst_buf);
1900+
zend_string_efree(recv_buf);
18381901
RETURN_THROWS();
18391902
}
18401903
break;
18411904
}
18421905
case IPPROTO_UDP: {
1906+
if (php_socket_get_chunk(dst_buf, recv_buf, sizeof(*ip), sizeof(struct udphdr)) == FAILURE) {
1907+
zend_value_error("invalid udp frame buffer length");
1908+
zend_string_efree(dst_buf);
1909+
zend_string_efree(recv_buf);
1910+
RETURN_THROWS();
1911+
}
1912+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18431913
if (php_socket_afpacket_add_udp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
1914+
zend_string_efree(dst_buf);
1915+
zend_string_efree(recv_buf);
18441916
RETURN_THROWS();
18451917
}
18461918
break;
@@ -1850,6 +1922,7 @@ PHP_FUNCTION(socket_recvfrom)
18501922
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
18511923
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
18521924
zend_string_efree(recv_buf);
1925+
zend_string_efree(dst_buf);
18531926
Z_DELREF(zpayload);
18541927
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
18551928
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
@@ -1863,10 +1936,17 @@ PHP_FUNCTION(socket_recvfrom)
18631936
break;
18641937
}
18651938
case ETH_P_LOOP: {
1866-
payload = ((unsigned char *)e + ETH_HLEN);
1939+
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, ETH_HLEN) == FAILURE) {
1940+
zend_value_error("invalid ethernet frame buffer length");
1941+
zend_string_efree(recv_buf);
1942+
zend_string_efree(dst_buf);
1943+
RETURN_THROWS();
1944+
}
1945+
payload = (unsigned char *)ZSTR_VAL(dst_buf);
18671946
struct ethhdr a;
18681947
if ((char *)payload + sizeof(a) < ZSTR_VAL(recv_buf) + slen) {
18691948
zend_string_efree(recv_buf);
1949+
zend_string_efree(dst_buf);
18701950
Z_DELREF(zpayload);
18711951
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
18721952
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
@@ -1895,6 +1975,8 @@ PHP_FUNCTION(socket_recvfrom)
18951975
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
18961976
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
18971977
zend_string_efree(recv_buf);
1978+
zend_string_efree(dst_buf);
1979+
18981980
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
18991981
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
19001982

@@ -1911,6 +1993,7 @@ PHP_FUNCTION(socket_recvfrom)
19111993
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
19121994
Z_DELREF(zpayload);
19131995
zend_string_efree(recv_buf);
1996+
zend_string_free(dst_buf);
19141997

19151998
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
19161999
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);

0 commit comments

Comments
 (0)