Skip to content

Commit ac62db0

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

File tree

1 file changed

+79
-7
lines changed

1 file changed

+79
-7
lines changed

ext/sockets/sockets.c

+79-7
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;
@@ -1760,7 +1789,6 @@ PHP_FUNCTION(socket_recvfrom)
17601789
zend_value_error("invalid transport header length");
17611790
RETURN_THROWS();
17621791
}
1763-
unsigned char *ipdata = payload + tlayer;
17641792
struct in_addr s, d;
17651793
s.s_addr = ip->saddr;
17661794
d.s_addr = ip->daddr;
@@ -1773,12 +1801,26 @@ PHP_FUNCTION(socket_recvfrom)
17731801

17741802
switch (ip->protocol) {
17751803
case IPPROTO_TCP: {
1804+
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, sizeof(struct tcphdr)) == FAILURE) {
1805+
zend_value_error("invalid ipv4 frame buffer length");
1806+
zend_string_efree(dst_buf);
1807+
zend_string_efree(recv_buf);
1808+
RETURN_THROWS();
1809+
}
1810+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
17761811
if (php_socket_afpacket_add_tcp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
17771812
RETURN_THROWS();
17781813
}
17791814
break;
17801815
}
17811816
case IPPROTO_UDP: {
1817+
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, sizeof(struct udphdr)) == FAILURE) {
1818+
zend_value_error("invalid ipv4 frame buffer length");
1819+
zend_string_efree(dst_buf);
1820+
zend_string_efree(recv_buf);
1821+
RETURN_THROWS();
1822+
}
1823+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
17821824
if (php_socket_afpacket_add_udp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
17831825
RETURN_THROWS();
17841826
}
@@ -1788,6 +1830,7 @@ PHP_FUNCTION(socket_recvfrom)
17881830
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
17891831
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
17901832
zend_string_efree(recv_buf);
1833+
zend_string_efree(dst_buf);
17911834
Z_DELREF(zpayload);
17921835
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
17931836
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
@@ -1801,7 +1844,13 @@ PHP_FUNCTION(socket_recvfrom)
18011844
break;
18021845
}
18031846
case ETH_P_IPV6: {
1804-
payload = ((unsigned char *)e + ETH_HLEN);
1847+
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, sizeof(struct iphdr)) == FAILURE) {
1848+
zend_value_error("invalid ipv4 frame buffer length");
1849+
zend_string_efree(dst_buf);
1850+
zend_string_efree(recv_buf);
1851+
RETURN_THROWS();
1852+
}
1853+
payload = ((unsigned char *)ZSTR_VAL(dst_buf));
18051854
struct ipv6hdr a;
18061855
memcpy(&a, payload, sizeof(a));
18071856
struct ipv6hdr *ip = &a;
@@ -1830,16 +1879,29 @@ PHP_FUNCTION(socket_recvfrom)
18301879
zend_update_property_long(Z_OBJCE(zpayload), Z_OBJ(zpayload), ZEND_STRL("headerSize"), totalip);
18311880
zend_update_property_stringl(Z_OBJCE(zpayload), Z_OBJ(zpayload), ZEND_STRL("rawPacket"), (char *)payload, totalip);
18321881
unsigned char ipprotocol = ip->nexthdr;
1833-
unsigned char *ipdata = payload + sizeof(*ip);
18341882

18351883
switch (ipprotocol) {
18361884
case IPPROTO_TCP: {
1885+
if (php_socket_get_chunk(dst_buf, recv_buf, sizeof(*ip), sizeof(struct tcphdr)) == FAILURE) {
1886+
zend_value_error("invalid ipv4 frame buffer length");
1887+
zend_string_efree(dst_buf);
1888+
zend_string_efree(recv_buf);
1889+
RETURN_THROWS();
1890+
}
1891+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18371892
if (php_socket_afpacket_add_tcp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
18381893
RETURN_THROWS();
18391894
}
18401895
break;
18411896
}
18421897
case IPPROTO_UDP: {
1898+
if (php_socket_get_chunk(dst_buf, recv_buf, sizeof(*ip), sizeof(struct udphdr)) == FAILURE) {
1899+
zend_value_error("invalid ipv4 frame buffer length");
1900+
zend_string_efree(dst_buf);
1901+
zend_string_efree(recv_buf);
1902+
RETURN_THROWS();
1903+
}
1904+
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18431905
if (php_socket_afpacket_add_udp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, arg2, arg5, arg6) == FAILURE) {
18441906
RETURN_THROWS();
18451907
}
@@ -1850,6 +1912,7 @@ PHP_FUNCTION(socket_recvfrom)
18501912
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
18511913
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
18521914
zend_string_efree(recv_buf);
1915+
zend_string_efree(dst_buf);
18531916
Z_DELREF(zpayload);
18541917
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
18551918
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
@@ -1863,7 +1926,13 @@ PHP_FUNCTION(socket_recvfrom)
18631926
break;
18641927
}
18651928
case ETH_P_LOOP: {
1866-
payload = ((unsigned char *)e + ETH_HLEN);
1929+
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, ETH_HLEN) == FAILURE) {
1930+
zend_value_error("invalid ethernet frame buffer length");
1931+
zend_string_efree(dst_buf);
1932+
zend_string_efree(recv_buf);
1933+
RETURN_THROWS();
1934+
}
1935+
payload = (unsigned char *)ZSTR_VAL(dst_buf);
18671936
struct ethhdr a;
18681937
if ((char *)payload + sizeof(a) < ZSTR_VAL(recv_buf) + slen) {
18691938
zend_string_efree(recv_buf);
@@ -1895,6 +1964,8 @@ PHP_FUNCTION(socket_recvfrom)
18951964
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
18961965
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
18971966
zend_string_efree(recv_buf);
1967+
zend_string_efree(dst_buf);
1968+
18981969
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
18991970
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
19001971

@@ -1911,6 +1982,7 @@ PHP_FUNCTION(socket_recvfrom)
19111982
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
19121983
Z_DELREF(zpayload);
19131984
zend_string_efree(recv_buf);
1985+
zend_string_free(dst_buf);
19141986

19151987
ZEND_TRY_ASSIGN_REF_VALUE(arg2, &obj);
19161988
ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);

0 commit comments

Comments
 (0)