Merge branch 'get-set-name-string-validity' into 'master'

module-avb: SET_NAME string validity checks

Closes #5286

See merge request pipewire/pipewire!2838
This commit is contained in:
Nils Tonnätt 2026-05-25 07:55:03 +00:00
commit 6a4403abce
5 changed files with 191 additions and 11 deletions

View file

@ -828,7 +828,8 @@ if build_module_avb
'module-avb/msrp.c',
'module-avb/mvrp.c',
'module-avb/srp.c',
'module-avb/stream.c'
'module-avb/stream.c',
'module-avb/strings.c'
],
include_directories : [configinc],
install : true,

View file

@ -12,6 +12,7 @@
#include "../aecp-aem.h"
#include "../aecp-aem-state.h"
#include "../aecp-aem-descriptors.h"
#include "../strings.h"
#include "cmd-get-set-name.h"
@ -145,7 +146,6 @@ int handle_cmd_get_name_common(struct aecp *aecp, int64_t now,
/**
* IEEE 1722.1-2021 7.4.17 SET_NAME
* For now this is not handling UTF characters, only ASCII
*/
int handle_cmd_set_name_common(struct aecp *aecp, int64_t now,
const void *m, int len)
@ -156,7 +156,7 @@ int handle_cmd_set_name_common(struct aecp *aecp, int64_t now,
const struct avb_packet_aecp_aem_setget_name *cmd;
struct descriptor *desc;
uint16_t desc_type, desc_id, name_index;
char *name_ptr;
unsigned char *name_ptr;
int rc;
cmd = (const struct avb_packet_aecp_aem_setget_name *)p->payload;
@ -169,7 +169,7 @@ int handle_cmd_set_name_common(struct aecp *aecp, int64_t now,
return reply_status(aecp,
AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
name_ptr = get_name_ptr(desc_type, descriptor_body(desc), name_index);
name_ptr = (unsigned char *)get_name_ptr(desc_type, descriptor_body(desc), name_index);
if (name_ptr == NULL)
return reply_status(aecp,
AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len);
@ -181,14 +181,17 @@ int handle_cmd_set_name_common(struct aecp *aecp, int64_t now,
/**
* IEEE 1722.1-2021: 7.4.17.1: The name does not contain a trailing NULL
* but if the name is less than 64 bytes in length then it is zero
* padded
* padded.
*/
memcpy(name_ptr, cmd->name, 64);
if (check_zero_padding(cmd->name, 64) == -1)
return reply_status(aecp,
AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len);
/** TODO: According to the specification, the string should alwasy be 0
* terminated, the goal would be to check whether a string is UTF-8 and
* that it is correctly zero terminitaed if less than 64 char, if not
* then a simple memcpy is enough */
if (validate_utf8(cmd->name, 64) == -1)
return reply_status(aecp,
AVB_AECP_AEM_STATUS_BAD_ARGUMENTS, m, len);
memcpy(name_ptr, cmd->name, 64);
rc = reply_success(aecp, m, len);
if (rc < 0)

View file

@ -250,7 +250,7 @@ struct avb_packet_aecp_aem_setget_name {
uint16_t descriptor_index;
uint16_t name_index;
uint16_t configuration_index;
char name[64];
unsigned char name[64];
} __attribute__ ((__packed__));
struct avb_packet_aecp_aem_setget_association_id {

View file

@ -0,0 +1,162 @@
/* SPDX-FileCopyrightText: Copyright © 2026 Nils Tonnaett
* Nils Tonnaett <ntonnatt@ccrma.stanford.edu> */
/* SPDX-License-Identifier: MIT */
#include "strings.h"
#include <stdbool.h>
typedef enum {
ST_START,
ST_A,
ST_B,
ST_C,
ST_D,
ST_E,
ST_F,
ST_G,
} UTF8_STATE;
/*
* IEEE 1722.1 Section 7.4.17.1
*
* We need to check if the buffer str of length len is valid UTF-8.
* The algorithm implemented here is based on the state machine by Frank Yung-Fong Tang
* described here at
* https://unicode.org/mail-arch/unicode-ml/y2003-m02/att-0467/01-The_Algorithm_to_Valide_an_UTF-8_String
*/
int validate_utf8 (const unsigned char *str, size_t len)
{
UTF8_STATE state = ST_START;
bool err = false;
for (unsigned int i = 0; i < len; ++i)
{
switch (state)
{
case ST_START:
if (str[i] <= 0x7F)
{
continue;
}
else if (str[i] >= 0xC2 && str[i] <= 0xDF)
{
state = ST_A;
}
else if (str[i] >= 0xE1 && str[i] <= 0xEC)
{
state = ST_B;
}
else if (str[i] >= 0xEE && str[i] <= 0xEF)
{
state = ST_B;
}
else if (str[i] == 0xE0)
{
state = ST_C;
}
else if (str[i] == 0xED)
{
state = ST_D;
}
else if (str[i] >= 0xF1 && str[i] <= 0xF3)
{
state = ST_E;
}
else if (str[i] == 0xF0)
{
state = ST_F;
}
else if (str[i] >= 0xF4)
{
state = ST_G;
}
else
{
err = true;
}
break;
case ST_A:
if (str[i] >= 0x80 && str[i] <= 0xBF)
state = ST_START;
else
err = true;
break;
case ST_B:
if (str[i] >= 0x80 && str[i] <= 0xBF)
state = ST_A;
else
err = true;
break;
case ST_C:
if (str[i] >= 0xA0 && str[i] <= 0xBF)
state = ST_A;
else
err = true;
break;
case ST_D:
if (str[i] >= 0x80 && str[i] <= 0x9F)
state = ST_A;
else
err = true;
break;
case ST_E:
if (str[i] >= 0x80 && str[i] <= 0xBF)
state = ST_B;
else
err = true;
break;
case ST_F:
if (str[i] >= 0x90 && str[i] <= 0xBF)
state = ST_B;
else
err = true;
break;
case ST_G:
if (str[i] >= 0x80 && str[i] <= 0x8F)
state = ST_B;
else
err = true;
break;
}
if (err == true)
{
return -1;
}
}
if (state != ST_START)
{
return -1;
}
else
{
return 0;
}
}
/*
* For SET_NAME, strings need to be zero-padded if shorter than 64 bytes. A
* string of 64 bytes would NOT be nul-terminated.
*
* IEEE 1722.1 Section 7.4.17.1
*/
int check_zero_padding (const unsigned char *str, size_t len)
{
size_t str_len = strnlen ((char *)str, len);
/* String doesn't need to be null-terminated. Return success if there is no
* null in str */
if (str_len == len)
{
return 0;
}
for (unsigned int i = str_len; i < len; ++i)
{
if (str[i] != 0x00)
{
return -1;
}
}
return 0;
}

View file

@ -0,0 +1,14 @@
/* SPDX-FileCopyrightText: Copyright © 2026 Nils Tonnaett*/
/* SPDX-License-Identifier: MIT */
#ifndef AVB_STRINGS_H
#define AVB_STRINGS_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
int check_zero_padding(const unsigned char *str, size_t len);
int validate_utf8(const unsigned char *str, size_t len);
#endif /* AVB_STRINGS_H */