Skip to content
Closed

try #47

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contrib/zephyr/samples/server-client/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void server(void) {
break;

default:
/* Call the default CSP service handler, handle pings, buffer use, etc. */
/* This example exposes management services; see doc/security.md. */
csp_service_handler(packet);
break;
}
Expand Down
4 changes: 4 additions & 0 deletions doc/api/csp_cmp_h.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
CSP Management Protocol (CMP)
=============================

CMP PEEK and POKE intentionally provide memory access and assume that the
management service is restricted to trusted peers. See :ref:`cmp-peek-and-poke`
for their security model and deployment requirements.

.. autocmodule:: csp_cmp.h

.. contents::
Expand Down
6 changes: 6 additions & 0 deletions doc/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ simple server/client setup, where the client sends a request to the
server and receives a reply. The code can be compiled to an executable
using `./examples/buildall.py`.

The example servers bind to all CSP ports and pass default service requests to
`csp_service_handler()`. This exposes CMP management operations, including
PEEK and POKE. These examples demonstrate libcsp functionality; they are not
hardened services intended for exposure to an untrusted network. See
{ref}`cmp-peek-and-poke` for the security model and deployment requirements.

The example supports these drivers and interfaces in CSP:

- ZMQHUB: `-z <host name|ip>`
Expand Down
1 change: 1 addition & 0 deletions doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ mtu
outflow
protocolstack
topology
security
tunnel
hooks
```
Expand Down
54 changes: 54 additions & 0 deletions doc/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Security model and deployment assumptions

libcsp provides networking and management building blocks for embedded systems.
Applications and deployments decide which peers can reach a node, which services
the node handles, and which link or network protections are required. A service
must not be treated as an authentication or authorization boundary unless its
documentation explicitly defines it as one.

(cmp-peek-and-poke)=
## CMP PEEK and POKE

CSP Management Protocol (CMP) PEEK and POKE are remote management and debugging
operations. PEEK reads memory from a CSP node, and POKE writes memory on a CSP
node. This memory access is intentional and is powerful by design.

These operations are intended for deployments in which access to the relevant
CSP management services is already restricted to trusted peers. PEEK and POKE
do not implement authentication, access-control lists, capabilities, or another
authorization boundary. The CMP handler does not decide whether the requesting
peer is permitted to access memory. A peer permitted to issue functional PEEK
or POKE requests is therefore being given memory-access capability by design.

If an untrusted or compromised peer can reach functional CMP PEEK or POKE
operations, it may be able to read sensitive memory, modify memory, crash the
target, or otherwise compromise the node. Applications must not expose these
operations to untrusted peers and rely on the CMP handler to reject unauthorized
memory access.

When a CSP network crosses trust boundaries, the deployment must restrict
access using protections appropriate to its architecture. These may include
network isolation, routing restrictions, hardened gateways or firewalls,
authenticated or encrypted links, or other external controls. libcsp does not
require one universal deployment mechanism.

`csp_service_handler()` handles packets sent to the CMP port and dispatches PEEK
and POKE requests. Consequently, an application that accepts the CMP port and
passes those packets to `csp_service_handler()` exposes the operations to peers
that can reach that service.

The current implementations differ:

- Legacy PEEK and POKE are functional by default.
- PEEK v2 and POKE v2 do not access memory by default. They are functional only
when the platform or application provides the required implementation.

The intentional semantics above are distinct from an accidental implementation
defect. A report that a reachable, functional PEEK or POKE command performs its
documented memory read or write describes the capability itself. Out-of-bounds
accesses, incorrect length validation, use-after-free defects, parser bugs,
memory corruption, or bypasses of security properties that libcsp claims to
provide are separate issues. The existence of an intentionally powerful command
does not make such defects acceptable. Before reporting PEEK or POKE behavior as
a security defect, verify that the finding goes beyond the documented memory
access capability.
2 changes: 1 addition & 1 deletion examples/csp_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static void * server(void * param) {
break;

default:
/* Call the default CSP service handler, handle pings, buffer use, etc. */
/* This example exposes management services; see doc/security.md. */
csp_service_handler(packet);
break;
}
Expand Down
2 changes: 1 addition & 1 deletion examples/csp_server_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static void * server(void * param) {
break;

default:
/* Call the default CSP service handler, handle pings, buffer use, etc. */
/* This example exposes management services; see doc/security.md. */
csp_service_handler(packet);
break;
}
Expand Down
1 change: 1 addition & 0 deletions examples/csp_server_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def server_task(addr: int, port: int) -> None:
data=csp.packet_get_data(packet).decode('utf-8'))
)
else:
# This example exposes management services; see doc/security.md.
csp.service_handler(conn, packet)


Expand Down
3 changes: 2 additions & 1 deletion examples/python_bindings_example_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ def csp_server():
libcsp.sendto_reply(packet, reply, libcsp.CSP_O_NONE)

else:
# pass request on to service handler if the given packet is a service-request
# This example exposes management services; see doc/security.md.
# Pass request on to service handler if the given packet is a service-request
# (ie: destination port is [0-6] see "include\csp\csp_types.h" line 47-55)
# parameters: {connection} {packet}
# will handle and send reply packets if necessary
Expand Down
8 changes: 5 additions & 3 deletions src/csp_rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ static inline bool csp_rdp_should_ack(csp_conn_t * conn) {
int csp_rdp_check_ack(csp_conn_t * conn) {

/* Check RX queue for spare capacity */
if ((unsigned int) abs(CSP_CONN_RXQUEUE_LEN - csp_queue_size(conn->rx_queue)) < conn->rdp.window_size) {
if ((uint32_t)csp_queue_free(conn->rx_queue) <= conn->rdp.window_size) {
return CSP_ERR_NONE;
}

Expand Down Expand Up @@ -673,7 +673,7 @@ bool csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet) {
if (packet->length <= sizeof(rdp_header_t))
goto discard_open;

/* If message is not in sequence, send EACK and store packet */
/* If message is not in sequence, store packet for next flush */
if (rx_header->seq_nr != (uint16_t)(conn->rdp.rcv_cur + 1)) {
if (csp_rdp_rx_queue_add(conn, packet, rx_header->seq_nr) != CSP_ERR_NONE) {
csp_rdp_check_ack(conn);
Expand Down Expand Up @@ -737,7 +737,9 @@ bool csp_rdp_new_packet(csp_conn_t * conn, csp_packet_t * packet) {
* by sending a NULL pointer, user-space must close connection */
if (conn->dest_socket == NULL) {
csp_conn_close(conn, closed_by);
csp_conn_enqueue_packet(conn, NULL);
if (csp_conn_enqueue_packet(conn, NULL) != CSP_ERR_NONE) {
csp_rdp_error("RDP %p: Could not signal close to userspace, RX queue full\n", (void *)conn);
}
} else {
/* New connection, userspace doesn't know anything about it yet - so it can be completely closed */
csp_conn_close(conn, closed_by | CSP_RDP_CLOSED_BY_USERSPACE);
Expand Down
21 changes: 11 additions & 10 deletions src/csp_rdp_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ static int __csp_rdp_queue_flush(csp_queue_handle_t queue, csp_conn_t * conn) {
return ret;
}

static void csp_rdp_queue_add(csp_queue_handle_t queue, csp_conn_t * conn, csp_packet_t * packet) {
packet->conn = conn;
if (csp_queue_enqueue(queue, &packet, 0) != CSP_QUEUE_OK) {
csp_buffer_free(packet);
}
}

static csp_packet_t * csp_rdp_queue_get(csp_queue_handle_t queue, csp_conn_t * conn) {
csp_packet_t * packet;
int size = csp_queue_size(queue);
Expand All @@ -57,7 +50,9 @@ static csp_packet_t * csp_rdp_queue_get(csp_queue_handle_t queue, csp_conn_t * c
}

/* Put it back and check next */
csp_rdp_queue_add(queue, conn, packet);
if (csp_queue_enqueue(queue, &packet, 0) != CSP_QUEUE_OK) {
csp_buffer_free(packet);
}
}

return NULL;
Expand Down Expand Up @@ -97,7 +92,10 @@ int csp_rdp_queue_tx_size(void) {
}

void csp_rdp_queue_tx_add(csp_conn_t * conn, csp_packet_t * packet) {
csp_rdp_queue_add(tx_queue, conn, packet);
packet->conn = conn;
if (csp_queue_enqueue(tx_queue, &packet, 0) != CSP_QUEUE_OK) {
csp_buffer_free(packet);
}
}

csp_packet_t * csp_rdp_queue_tx_get(csp_conn_t * conn) {
Expand All @@ -109,7 +107,10 @@ int csp_rdp_queue_rx_size(void) {
}

void csp_rdp_queue_rx_add(csp_conn_t * conn, csp_packet_t * packet) {
csp_rdp_queue_add(rx_queue, conn, packet);
packet->conn = conn;
if (csp_queue_enqueue(rx_queue, &packet, 0) != CSP_QUEUE_OK) {
csp_buffer_free(packet);
}
}

csp_packet_t * csp_rdp_queue_rx_get(csp_conn_t * conn) {
Expand Down