Skip to content

Commit 389bd57

Browse files
Florian Grandelcarlescufi
authored andcommitted
net: ip: fix and consolidate cloning of ll addr
The net packet structure contains pointers to link-layer source and destination addresses. Usually, these structures do not point to separately allocated memory but directly into the packet's data buffer. In case of a deep package clone (which includes copying the buffer) the copy of the ll addresses continued to point into the old package (contrary to a rather misleading inline comment). This was proven by an additional failing unit test assertion. As the original package may be unreferenced while the cloned package is still being accessed, the ll address pointers of the cloned package may become invalid. The fix consists of two parts: * First it is determined whether a given ll address actually points into the buffer and if so at which logical cursor offset it is located. * If the address points into the package buffer then the cursor API is used to determine the corresponding physical memory location in the cloned package. The ll address of the cloned package is then patched to point to the cloned buffer. Additional assertions were introduced to the existing unit test to ensure that the newly generated address points to the correct content of the cloned package. The solution is implemented in a generic way so that the previously redundant implementations were consolidated into a single one. The code includes a check that ensures that the ll address check and manipulation will be skipped in case of shallow package copies. The change also addresses problems related to the "overwrite" flag of the package: * Package cloning assumes the overwrite flag to be set. Otherwise it will not work correctly. This was not ensured inside the clone method. * Package cloning manipulates the overwrite flag of the cloned package but does not reset it to represent the same state as the original package. The change introduces a fix and unit test assertions for both problems. Fixes: #51265 Signed-off-by: Florian Grandel <[email protected]>
1 parent 93647ed commit 389bd57

File tree

2 files changed

+90
-24
lines changed

2 files changed

+90
-24
lines changed

subsys/net/ip/net_pkt.c

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,46 @@ int net_pkt_copy(struct net_pkt *pkt_dst,
17631763
return 0;
17641764
}
17651765

1766+
static int32_t net_pkt_find_offset(struct net_pkt *pkt, uint8_t *ptr)
1767+
{
1768+
struct net_buf *buf = pkt->buffer;
1769+
uint32_t ret = -EINVAL;
1770+
uint16_t offset;
1771+
1772+
if (!(ptr && pkt && buf)) {
1773+
return ret;
1774+
}
1775+
1776+
offset = 0U;
1777+
while (buf) {
1778+
if (buf->data <= ptr && ptr <= (buf->data + buf->len)) {
1779+
ret = offset + (ptr - buf->data);
1780+
break;
1781+
}
1782+
offset += buf->len;
1783+
buf = buf->frags;
1784+
}
1785+
1786+
return ret;
1787+
}
1788+
1789+
static void clone_pkt_lladdr(struct net_pkt *pkt, struct net_pkt *clone_pkt,
1790+
struct net_linkaddr *lladdr)
1791+
{
1792+
int32_t ll_addr_offset;
1793+
1794+
if (!lladdr->addr)
1795+
return;
1796+
1797+
ll_addr_offset = net_pkt_find_offset(pkt, lladdr->addr);
1798+
1799+
if (ll_addr_offset >= 0) {
1800+
net_pkt_cursor_init(clone_pkt);
1801+
net_pkt_skip(clone_pkt, ll_addr_offset);
1802+
lladdr->addr = net_pkt_cursor_get_pos(clone_pkt);
1803+
}
1804+
}
1805+
17661806
static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt)
17671807
{
17681808
net_pkt_set_family(clone_pkt, net_pkt_family(pkt));
@@ -1773,10 +1813,29 @@ static void clone_pkt_attributes(struct net_pkt *pkt, struct net_pkt *clone_pkt)
17731813
net_pkt_set_priority(clone_pkt, net_pkt_priority(pkt));
17741814
net_pkt_set_orig_iface(clone_pkt, net_pkt_orig_iface(pkt));
17751815
net_pkt_set_captured(clone_pkt, net_pkt_is_captured(pkt));
1816+
17761817
net_pkt_set_l2_bridged(clone_pkt, net_pkt_is_l2_bridged(pkt));
17771818
net_pkt_set_l2_processed(clone_pkt, net_pkt_is_l2_processed(pkt));
17781819
net_pkt_set_ll_proto_type(clone_pkt, net_pkt_ll_proto_type(pkt));
17791820

1821+
if (pkt->buffer && clone_pkt->buffer) {
1822+
memcpy(net_pkt_lladdr_src(clone_pkt), net_pkt_lladdr_src(pkt),
1823+
sizeof(struct net_linkaddr));
1824+
memcpy(net_pkt_lladdr_dst(clone_pkt), net_pkt_lladdr_dst(pkt),
1825+
sizeof(struct net_linkaddr));
1826+
/* The link header pointers are usable as-is if we
1827+
* shallow-copied the buffer even if they point
1828+
* into the fragment memory of the buffer,
1829+
* otherwise we have to set the ll address pointer
1830+
* relative to the new buffer to avoid dangling
1831+
* pointers into the source packet.
1832+
*/
1833+
if (pkt->buffer != clone_pkt->buffer) {
1834+
clone_pkt_lladdr(pkt, clone_pkt, net_pkt_lladdr_src(clone_pkt));
1835+
clone_pkt_lladdr(pkt, clone_pkt, net_pkt_lladdr_dst(clone_pkt));
1836+
}
1837+
}
1838+
17801839
if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
17811840
net_pkt_set_ipv4_ttl(clone_pkt, net_pkt_ipv4_ttl(pkt));
17821841
net_pkt_set_ipv4_opts_len(clone_pkt,
@@ -1816,8 +1875,9 @@ static struct net_pkt *net_pkt_clone_internal(struct net_pkt *pkt,
18161875
k_timeout_t timeout)
18171876
{
18181877
size_t cursor_offset = net_pkt_get_current_offset(pkt);
1819-
struct net_pkt *clone_pkt;
1878+
bool overwrite = net_pkt_is_being_overwritten(pkt);
18201879
struct net_pkt_cursor backup;
1880+
struct net_pkt *clone_pkt;
18211881

18221882
#if NET_LOG_LEVEL >= LOG_LEVEL_DBG
18231883
clone_pkt = pkt_alloc_with_buffer(slab, net_pkt_iface(pkt),
@@ -1833,36 +1893,29 @@ static struct net_pkt *net_pkt_clone_internal(struct net_pkt *pkt,
18331893
return NULL;
18341894
}
18351895

1896+
net_pkt_set_overwrite(pkt, true);
18361897
net_pkt_cursor_backup(pkt, &backup);
18371898
net_pkt_cursor_init(pkt);
18381899

18391900
if (net_pkt_copy(clone_pkt, pkt, net_pkt_get_len(pkt))) {
18401901
net_pkt_unref(clone_pkt);
18411902
net_pkt_cursor_restore(pkt, &backup);
1903+
net_pkt_set_overwrite(pkt, overwrite);
18421904
return NULL;
18431905
}
1844-
1845-
if (clone_pkt->buffer) {
1846-
/* The link header pointers are only usable if there is
1847-
* a buffer that we copied because those pointers point
1848-
* to start of the fragment which we do not have right now.
1849-
*/
1850-
memcpy(&clone_pkt->lladdr_src, &pkt->lladdr_src,
1851-
sizeof(clone_pkt->lladdr_src));
1852-
memcpy(&clone_pkt->lladdr_dst, &pkt->lladdr_dst,
1853-
sizeof(clone_pkt->lladdr_dst));
1854-
}
1906+
net_pkt_set_overwrite(clone_pkt, true);
18551907

18561908
clone_pkt_attributes(pkt, clone_pkt);
18571909

18581910
net_pkt_cursor_init(clone_pkt);
18591911

18601912
if (cursor_offset) {
1861-
net_pkt_set_overwrite(clone_pkt, true);
18621913
net_pkt_skip(clone_pkt, cursor_offset);
18631914
}
1915+
net_pkt_set_overwrite(clone_pkt, overwrite);
18641916

18651917
net_pkt_cursor_restore(pkt, &backup);
1918+
net_pkt_set_overwrite(pkt, overwrite);
18661919

18671920
NET_DBG("Cloned %p to %p", pkt, clone_pkt);
18681921

@@ -1895,17 +1948,6 @@ struct net_pkt *net_pkt_shallow_clone(struct net_pkt *pkt, k_timeout_t timeout)
18951948

18961949
net_pkt_frag_ref(buf);
18971950

1898-
if (pkt->buffer) {
1899-
/* The link header pointers are only usable if there is
1900-
* a buffer that we copied because those pointers point
1901-
* to start of the fragment which we do not have right now.
1902-
*/
1903-
memcpy(&clone_pkt->lladdr_src, &pkt->lladdr_src,
1904-
sizeof(clone_pkt->lladdr_src));
1905-
memcpy(&clone_pkt->lladdr_dst, &pkt->lladdr_dst,
1906-
sizeof(clone_pkt->lladdr_dst));
1907-
}
1908-
19091951
clone_pkt_attributes(pkt, clone_pkt);
19101952

19111953
net_pkt_cursor_restore(clone_pkt, &pkt->cursor);

tests/net/net_pkt/src/main.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,16 @@ ZTEST(net_pkt_test_suite, test_net_pkt_clone)
776776
zassert_true(sizeof(buf) - 6 == net_pkt_remaining_data(pkt),
777777
"Pkt remaining data mismatch");
778778

779+
net_pkt_lladdr_src(pkt)->addr = pkt->buffer->data;
780+
net_pkt_lladdr_src(pkt)->len = NET_LINK_ADDR_MAX_LENGTH;
781+
net_pkt_lladdr_src(pkt)->type = NET_LINK_ETHERNET;
782+
zassert_mem_equal(net_pkt_lladdr_src(pkt)->addr, buf, NET_LINK_ADDR_MAX_LENGTH);
783+
net_pkt_lladdr_dst(pkt)->addr = net_pkt_cursor_get_pos(pkt);
784+
net_pkt_lladdr_dst(pkt)->len = NET_LINK_ADDR_MAX_LENGTH;
785+
net_pkt_lladdr_dst(pkt)->type = NET_LINK_ETHERNET;
786+
zassert_mem_equal(net_pkt_lladdr_dst(pkt)->addr, &buf[6], NET_LINK_ADDR_MAX_LENGTH);
787+
788+
net_pkt_set_overwrite(pkt, false);
779789
cloned_pkt = net_pkt_clone(pkt, K_NO_WAIT);
780790
zassert_true(cloned_pkt != NULL, "Pkt not cloned");
781791

@@ -788,6 +798,20 @@ ZTEST(net_pkt_test_suite, test_net_pkt_clone)
788798
zassert_true(sizeof(buf) - 6 == net_pkt_remaining_data(cloned_pkt),
789799
"Cloned pkt remaining data mismatch");
790800

801+
zassert_false(net_pkt_is_being_overwritten(cloned_pkt),
802+
"Cloned pkt overwrite flag not restored");
803+
804+
zassert_false(net_pkt_is_being_overwritten(pkt),
805+
"Pkt overwrite flag not restored");
806+
807+
zassert_mem_equal(net_pkt_lladdr_src(cloned_pkt)->addr, buf, NET_LINK_ADDR_MAX_LENGTH);
808+
zassert_true(net_pkt_lladdr_src(cloned_pkt)->addr == cloned_pkt->buffer->data,
809+
"Cloned pkt ll src addr mismatch");
810+
811+
zassert_mem_equal(net_pkt_lladdr_dst(cloned_pkt)->addr, &buf[6], NET_LINK_ADDR_MAX_LENGTH);
812+
zassert_true(net_pkt_lladdr_dst(cloned_pkt)->addr == net_pkt_cursor_get_pos(cloned_pkt),
813+
"Cloned pkt ll dst addr mismatch");
814+
791815
net_pkt_unref(pkt);
792816
net_pkt_unref(cloned_pkt);
793817
}

0 commit comments

Comments
 (0)