Skip to content
Draft
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
7 changes: 7 additions & 0 deletions doc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ All notable changes to the project are documented in this file.

### Fixes

- Constrain Wi-Fi mesh-id and NAS identifier, and validate access-point and mesh passphrases as strictly as station
- Apply syslog configuration changes at runtime, not only after reboot
- Restrict the allowed characters in keystore key and certificate names
- Reject control characters and double quotes in syslog property-filter value and pattern-match
- Reject control characters and commas in DHCP server static-host match values
- Restrict the allowed characters in a container `command` override
- Restrict the allowed characters in a hardware component `name`
- Fix #1619: Raspberry Pi kernel panic when configure Wi-Fi
- WebUI: "Save" in the interface editor and "OK" in Add Interface
did nothing for Wi-Fi and WireGuard interfaces. The inline "+ New"
Expand Down
42 changes: 42 additions & 0 deletions src/confd/share/migrate/1.10/20-hardware-component-name.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/sh
# ietf-hardware component names are now restricted to a safe character set:
# letters, digits, '_', '.', '-' and '@', not starting with '.' or '-'.
# Sanitize any configured component name that would no longer validate
# and update the leaves that reference it: the Wi-Fi radio of an interface
# and the GPS receiver of an NTP reference-clock source. Probed names
# (radioN, gpsN) never match, so this is a safety net for hand-edited
# configs.

file=$1
temp=${file}.tmp

# Everything the identifier type does not allow.
bad='[^a-zA-Z0-9_.@-]'

jq --arg bad "$bad" '
["ietf-hardware:hardware", "component"] as $hw
| if getpath($hw) == null then . else
( [ getpath($hw)[]
| (.name | gsub($bad; "") | sub("^[.-]+"; "")) as $new
| select($new != .name and $new != "")
| { key: .name, value: $new } ]
| from_entries ) as $ren
| if ($ren | length) == 0 then . else
setpath($hw; getpath($hw)
| map(if $ren[.name] != null then .name = $ren[.name] else . end))
| ["ietf-interfaces:interfaces", "interface"] as $ifs
| (if getpath($ifs) != null then
setpath($ifs; getpath($ifs) | map(
((.["infix-interfaces:wifi"] // {}) | .radio // null) as $r
| if $r != null and $ren[$r] != null
then .["infix-interfaces:wifi"].radio = $ren[$r]
else . end))
else . end)
| ["ietf-ntp:ntp", "refclock-master", "infix-ntp:source"] as $src
| (if getpath($src) != null then
setpath($src; getpath($src) | map(
if $ren[.receiver] != null then .receiver = $ren[.receiver] else . end))
else . end)
end
end
' "$file" > "$temp" && mv "$temp" "$file"
2 changes: 1 addition & 1 deletion src/confd/share/migrate/1.10/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
migratedir = $(pkgdatadir)/migrate/1.10
dist_migrate_DATA = 10-software-update-url.sh
dist_migrate_DATA = 10-software-update-url.sh 20-hardware-component-name.sh
5 changes: 5 additions & 0 deletions src/confd/src/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,11 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv)
ERROR("Failed to subscribe to ietf-system");
goto err;
}
rc = subscribe_model("ietf-syslog", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ietf-syslog");
goto err;
}
rc = subscribe_model("ieee802-dot1ab-lldp", &confd, 0);
if (rc) {
ERROR("Failed to subscribe to ieee802-dot1ab-lldp");
Expand Down
54 changes: 42 additions & 12 deletions src/confd/src/if-wifi.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,28 @@
#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant-%s.conf"


int wifi_validate_secret(sr_session_ctx_t *session, struct lyd_node *cif)
/*
* Validate one wifi security block's referenced keystore secret. The
* decoded passphrase is written verbatim into wpa_supplicant/hostapd
* config, so it must be 8-63 printable characters (no newline, which
* would inject an unrelated directive). Applies to station, access
* point and mesh alike.
*/
static int validate_wifi_secret(sr_session_ctx_t *session, const char *ifname,
struct lyd_node *cif, struct lyd_node *security)
{
struct lyd_node *wifi, *station, *security, *secret_node;
const char *ifname, *secret_name, *security_mode, *b64;
const char *secret_name, *security_mode, *b64;
struct lyd_node *secret_node;
unsigned char *decoded;
size_t len;

ifname = lydx_get_cattr(cif, "name");
wifi = lydx_get_child(cif, "wifi");
if (!wifi)
return SR_ERR_OK;

station = lydx_get_child(wifi, "station");
if (!station)
if (!security)
return SR_ERR_OK;

security = lydx_get_child(station, "security");
security_mode = lydx_get_cattr(security, "mode");
secret_name = lydx_get_cattr(security, "secret");

if (!secret_name || !strcmp(security_mode, "disabled"))
if (!secret_name || (security_mode && !strcmp(security_mode, "disabled")))
return SR_ERR_OK;

secret_node = lydx_get_xpathf(cif,
Expand Down Expand Up @@ -77,6 +78,35 @@ int wifi_validate_secret(sr_session_ctx_t *session, struct lyd_node *cif)
return SR_ERR_OK;
}

int wifi_validate_secret(sr_session_ctx_t *session, struct lyd_node *cif)
{
static const char *const modes[] = {
"station", "access-point", "mesh-point"
};
const char *ifname;
struct lyd_node *wifi;

ifname = lydx_get_cattr(cif, "name");
wifi = lydx_get_child(cif, "wifi");
if (!wifi)
return SR_ERR_OK;

for (size_t i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
struct lyd_node *node = lydx_get_child(wifi, modes[i]);
int rc;

if (!node)
continue;

rc = validate_wifi_secret(session, ifname, cif,
lydx_get_child(node, "security"));
if (rc)
return rc;
}

return SR_ERR_OK;
}

wifi_mode_t wifi_get_mode(struct lyd_node *iface)
{
struct lyd_node *ap, *mesh, *wifi;
Expand Down
8 changes: 4 additions & 4 deletions src/confd/yang/confd.inc
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ MODULES=(
# NOTE: ietf-tls-client must be version matched with ietf-tls-server, used by netopeer2!
# "ietf-tls-client@2023-12-28.yang"
"ietf-syslog@2024-03-21.yang -e file-action -e file-limit-size -e remote-action -e select-adv-compare -e select-match"
"infix-syslog@2026-09-15.yang"
"infix-syslog@2026-09-24.yang"
"iana-hardware@2018-03-13.yang"
"ietf-hardware@2018-03-13.yang -e hardware-state -e hardware-sensor"
"infix-hardware@2026-07-02.yang"
"infix-hardware@2026-09-24.yang"
"ieee802-dot1q-types@2022-10-29.yang"
"infix-ip@2026-04-28.yang"
"infix-if-type@2026-01-07.yang"
Expand All @@ -37,7 +37,7 @@ MODULES=(
"infix-dhcp-common@2025-12-21.yang"
"infix-dhcp-client@2025-11-09.yang"
"infix-dhcpv6-client@2025-11-09.yang"
"infix-dhcp-server@2026-09-18.yang"
"infix-dhcp-server@2026-09-24.yang"
"infix-firewall@2026-07-02.yang"
"infix-firewall-services@2025-04-26.yang"
"infix-firewall-icmp-types@2025-04-26.yang"
Expand All @@ -53,7 +53,7 @@ MODULES=(
"infix-crypto-types@2026-02-14.yang"
"ietf-keystore -e symmetric-keys"
"infix-ntp@2026-06-11.yang"
"infix-keystore@2025-12-17.yang"
"infix-keystore@2026-09-24.yang"
"ieee1588-ptp-tt@2023-08-14.yang -e timestamp-correction"
"ieee802-dot1as-gptp@2025-12-10.yang"
"infix-ptp@2026-04-07.yang"
Expand Down
10 changes: 9 additions & 1 deletion src/confd/yang/confd/infix-containers.yang
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ module infix-containers {
prefix infix-sys;
}


revision 2026-09-24 {
description "Disallow shell expansion, quoting and command chaining
characters in the command override. Environment
variables are set with the env list.";
reference "internal";
}

revision 2026-04-20 {
description "Add cmdline operational leaf showing the full process command line
(entrypoint + args) from 'podman inspect'. Allow environment variable
Expand Down Expand Up @@ -264,7 +272,7 @@ module infix-containers {
leaf command {
description "Override ENTRYPOINT from image and run command + args.";
type string {
pattern '[a-zA-Z0-9_./ :=@%^,${}()+-]+';
pattern "[^\\p{Cc}\\\\;|&$`(){}<>*?!#~'\"\\[\\]]+";
}
}

Expand Down
23 changes: 21 additions & 2 deletions src/confd/yang/confd/infix-dhcp-server.yang
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ module infix-dhcp-server {
contact "kernelkit@googlegroups.com";
description "This module implements a DHCPv4 server";

revision 2026-09-24 {
description "Constrain static-host match hostname and client-id string:
no control characters or commas, at most 255 bytes.";
reference "internal";
}

revision 2026-09-18 {
description "Add network boot parameters (BOOTP siaddr/file, option 66/67)
at global, subnet, and host scope.";
Expand Down Expand Up @@ -283,7 +289,13 @@ module infix-dhcp-server {
case hostname {
leaf hostname {
description "Match on client hostname, DHCP option 12.";
type string;
reference "RFC 2132, sec. 3.14: Host Name Option. The
option length field is one octet, so the value
is at most 255 bytes.";
type string {
length "1..255";
pattern '[^\p{Cc},]+';
}
}
}

Expand All @@ -298,7 +310,14 @@ module infix-dhcp-server {
description "String value for text-based client-id.

Example: xyzzy";
type string;
reference "RFC 2132, sec. 9.14: Client-identifier
(option 61). The option length field is
one octet, so the value is at most 255
bytes.";
type string {
length "1..255";
pattern '[^\p{Cc},]+';
}
}
}
case hex {
Expand Down
17 changes: 17 additions & 0 deletions src/confd/yang/confd/infix-hardware.yang
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ module infix-hardware {
contact "kernelkit@googlegroups.com";
description "Vital Product Data augmentation of ieee-hardware and deviations.";

revision 2026-09-24 {
description "Constrain hardware component names to letters, digits,
'_', '.', '-' and '@', not starting with '.' or '-'.";
reference "internal";
}

revision 2026-07-02 {
description "Widen wifi max-interfaces ap/station to uint16, virtual
radios (mac80211_hwsim) report combinations up to 2048.";
Expand Down Expand Up @@ -163,6 +169,17 @@ module infix-hardware {
description "GPS/GNSS receiver for time synchronization";
}

deviation "/iehw:hardware/iehw:component/iehw:name" {
deviate replace {
type string {
pattern '[a-zA-Z0-9_][a-zA-Z0-9_.@-]*';
}
}
description "Component names are plain identifiers: letters, digits,
'_', '.', '-' and '@' (device-tree unit addresses such as
'sfp@9'), not starting with '.' or '-'.";
}

deviation "/iehw:hardware/iehw:component/iehw:state/iehw:admin-state" {
deviate add {
must ". = 'locked' or . = 'unlocked'" {
Expand Down
11 changes: 11 additions & 0 deletions src/confd/yang/confd/infix-if-wifi.yang
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ submodule infix-if-wifi {
- Security: WPA2/WPA3 with keystore integration
- Operational state: Connection status, RSSI, client lists";

revision 2026-09-24 {
description
"Constrain mesh-id to the SSID character set and nas-identifier
to letters, digits, '.', '_' and '-'.";
reference "internal";
}

revision 2026-07-01 {
description
"Add station 'bssid' operational leaf: the BSSID the station is
Expand Down Expand Up @@ -527,6 +534,7 @@ submodule infix-if-wifi {
}
type string {
length "1..253";
pattern '[a-zA-Z0-9._-]+';
}
}
default auto;
Expand Down Expand Up @@ -697,6 +705,9 @@ submodule infix-if-wifi {
leaf mesh-id {
type string {
length "1..32";
pattern '[^\x00-\x1f\x22\x5c\x7f]*' {
error-message "Mesh ID must not contain control characters, double quotes, or backslashes.";
}
}
mandatory true;
description
Expand Down
31 changes: 31 additions & 0 deletions src/confd/yang/confd/infix-keystore.yang
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ module infix-keystore {
prefix infix-ct;
}

revision 2026-09-24 {
description "Constrain asymmetric-key and certificate names: no control
characters, whitespace, '/', '\\' or shell metacharacters,
and no leading '.' or '-'.";
reference "internal";
}

revision 2025-12-17 {
description "Add WireGuard support, see infix-crypto-types.yang";
}
Expand All @@ -21,4 +28,28 @@ module infix-keystore {
revision 2025-02-04 {
description "Initial";
}

deviation "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key/ks:name" {
deviate replace {
type string {
pattern "[^\\p{Cc}\\s/\\\\;|&$`(){}<>*?!#~'\"\\[\\]]+";
pattern "[^.-].*";
}
}
description "Key names may not contain control characters, whitespace,
'/', '\\' or any of ; | & $ ` ( ) { } < > * ? ! # ~ ' \" [ ],
and may not start with '.' or '-'.";
}

deviation "/ks:keystore/ks:asymmetric-keys/ks:asymmetric-key/ks:certificates/ks:certificate/ks:name" {
deviate replace {
type string {
pattern "[^\\p{Cc}\\s/\\\\;|&$`(){}<>*?!#~'\"\\[\\]]+";
pattern "[^.-].*";
}
}
description "Certificate names may not contain control characters, whitespace,
'/', '\\' or any of ; | & $ ` ( ) { } < > * ? ! # ~ ' \" [ ],
and may not start with '.' or '-'.";
}
}
Loading
Loading