From 6cf5e7111b7dcd5928021d5104abd01b75ec6b97 Mon Sep 17 00:00:00 2001 From: Daniel Markstedt Date: Thu, 25 Jun 2026 22:08:07 +0200 Subject: [PATCH] CVE-2026-62319,CVE-2026-62320: libatalk: harden DSI frame parsing Reported-by: Alejandro Ramos Signed-off-by: Daniel Markstedt Reviewed-by: Andy Lemin (andylemin) --- libatalk/dsi/dsi_stream.c | 33 +++++++++++++++++++++++++-------- libatalk/dsi/dsi_tcp.c | 13 +++++++++++-- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/libatalk/dsi/dsi_stream.c b/libatalk/dsi/dsi_stream.c index 677186b28..a882af9a5 100644 --- a/libatalk/dsi/dsi_stream.c +++ b/libatalk/dsi/dsi_stream.c @@ -662,6 +662,8 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length) int dsi_stream_receive(DSI *dsi) { char block[DSI_BLOCKSIZ]; + uint32_t dsi_len; + uint32_t dsi_doff; LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: START"); if (dsi->flags & DSI_DISCONNECTED) { @@ -689,22 +691,37 @@ int dsi_stream_receive(DSI *dsi) memcpy(&dsi->header.dsi_len, block + 8, sizeof(dsi->header.dsi_len)); memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved)); dsi->clientID = ntohs(dsi->header.dsi_requestID); - /* make sure we don't over-write our buffers. */ - dsi->cmdlen = MIN(ntohl(dsi->header.dsi_len), dsi->server_quantum); - dsi->header.dsi_data.dsi_doff = MIN(dsi->header.dsi_data.dsi_doff, - dsi->server_quantum); + dsi_len = ntohl(dsi->header.dsi_len); + dsi_doff = dsi->header.dsi_data.dsi_doff; + + if (dsi_len > dsi->server_quantum) { + LOG(log_error, logtype_dsi, + "dsi_stream_receive: request payload too large: %u > %u", + (unsigned int)dsi_len, (unsigned int)dsi->server_quantum); + return 0; + } + + dsi->cmdlen = dsi_len; /* Work around bug in ASC 3.7.x when client sends a zero byte AFPWrite() */ if (dsi->header.dsi_command == DSIFUNC_WRITE - && !(dsi->header.dsi_data.dsi_doff)) { - dsi->header.dsi_data.dsi_doff = 12; + && !dsi_doff) { + dsi_doff = 12; + dsi->header.dsi_data.dsi_doff = dsi_doff; + } + + if (dsi->header.dsi_command == DSIFUNC_WRITE && dsi_doff > dsi_len) { + LOG(log_error, logtype_dsi, + "dsi_stream_receive: write data offset exceeds payload length: %u > %u", + (unsigned int)dsi_doff, (unsigned int)dsi_len); + return 0; } /* Receiving DSIWrite data is done in AFP function, not here */ if (dsi->header.dsi_command == DSIFUNC_WRITE - && dsi->header.dsi_data.dsi_doff) { + && dsi_doff) { LOG(log_maxdebug, logtype_dsi, "dsi_stream_receive: write request"); - dsi->cmdlen = dsi->header.dsi_data.dsi_doff; + dsi->cmdlen = dsi_doff; } if (dsi_stream_read(dsi, dsi->commands, dsi->cmdlen) != dsi->cmdlen) { diff --git a/libatalk/dsi/dsi_tcp.c b/libatalk/dsi/dsi_tcp.c index 9b0fbb0b6..b461d4bb9 100644 --- a/libatalk/dsi/dsi_tcp.c +++ b/libatalk/dsi/dsi_tcp.c @@ -150,6 +150,7 @@ static pid_t dsi_tcp_open(DSI *dsi) struct sigaction newact, oldact; uint8_t block[DSI_BLOCKSIZ]; size_t stored; + uint32_t dsi_len; /* reset signals */ server_reset_signal(); #ifndef DEBUGGING @@ -209,8 +210,16 @@ static pid_t dsi_tcp_open(DSI *dsi) memcpy(&dsi->header.dsi_reserved, block + 12, sizeof(dsi->header.dsi_reserved)); dsi->clientID = ntohs(dsi->header.dsi_requestID); - /* make sure we don't over-write our buffers. */ - dsi->cmdlen = min(ntohl(dsi->header.dsi_len), dsi->server_quantum); + dsi_len = ntohl(dsi->header.dsi_len); + + if (dsi_len > dsi->server_quantum) { + LOG(log_error, logtype_dsi, + "dsi_tcp_open: request payload too large: %u > %u", + (unsigned int)dsi_len, (unsigned int)dsi->server_quantum); + exit(EXITERR_CLNT); + } + + dsi->cmdlen = dsi_len; stored = 0; while (stored < dsi->cmdlen) {