Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package lldpd for openSUSE:Factory checked in at 2026-05-15 23:54:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lldpd (Old) and /work/SRC/openSUSE:Factory/.lldpd.new.1966 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lldpd" Fri May 15 23:54:23 2026 rev:30 rq:1353324 version:1.0.22 Changes: -------- --- /work/SRC/openSUSE:Factory/lldpd/lldpd.changes 2026-03-15 14:33:08.317293999 +0100 +++ /work/SRC/openSUSE:Factory/.lldpd.new.1966/lldpd.changes 2026-05-15 23:54:41.436024453 +0200 @@ -1,0 +2,13 @@ +Fri May 15 05:55:46 UTC 2026 - Martin Hauke <[email protected]> + +- Update to version 1.0.22 + * Fix CVE-2026-46433, out-of-bound read access when removing + VLAN tag (#787). + * Reject 0-length management address in LLDP. + * Fix race condition when creating the control socket. + * Fix FDP MAC address. + * Fix memory leak in the BSD bridge query path. + * Fix duplicate management addresses when merging EDP VLAN + frames. + +------------------------------------------------------------------- Old: ---- lldpd-1.0.21.tar.gz lldpd-1.0.21.tar.gz.asc New: ---- lldpd-1.0.22.tar.gz lldpd-1.0.22.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lldpd.spec ++++++ --- /var/tmp/diff_new_pack.gWn4hO/_old 2026-05-15 23:54:43.432106619 +0200 +++ /var/tmp/diff_new_pack.gWn4hO/_new 2026-05-15 23:54:43.452107442 +0200 @@ -26,14 +26,14 @@ %define _fillupdir %{_localstatedir}/adm/fillup-templates %endif Name: lldpd -Version: 1.0.21 +Version: 1.0.22 Release: 0 Summary: Implementation of IEEE 802.1ab (LLDP) # We have some GPL linux headers in include/linux, they are used on # platforms where glibc headers are not recent enough License: GPL-2.0-or-later AND ISC Group: System/Daemons -URL: https://vincentbernat.github.io/ +URL: https://lldpd.github.io/ Source0: https://media.luffy.cx/files/lldpd/%{name}-%{version}.tar.gz Source1: lldpd.sysconfig Source2: https://media.luffy.cx/files/lldpd/%{name}-%{version}.tar.gz.gpg#/%{name}-%{version}.tar.gz.asc ++++++ lldpd-1.0.21.tar.gz -> lldpd-1.0.22.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/.dist-version new/lldpd-1.0.22/.dist-version --- old/lldpd-1.0.21/.dist-version 2026-03-14 22:20:46.000000000 +0100 +++ new/lldpd-1.0.22/.dist-version 2026-05-14 23:17:33.000000000 +0200 @@ -1 +1 @@ -1.0.21 +1.0.22 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/ChangeLog new/lldpd-1.0.22/ChangeLog --- old/lldpd-1.0.21/ChangeLog 2026-03-14 22:20:45.000000000 +0100 +++ new/lldpd-1.0.22/ChangeLog 2026-05-14 23:17:32.000000000 +0200 @@ -1,3 +1,44 @@ +1.0.22 [2026-05-14 23:16:28 +0200]: + + - [df8d7298598f] release: 1.0.22 (Vincent Bernat) + - [4192630d1b46] doc: update NEWS for the latest commit (Vincent Bernat) + - [ca931be63a9c] Fix heap OOB read in VLAN decapsulation memmove (TristanInSec) + - [7b40322ae691] doc: update NEWS with most notable changes (Vincent Bernat) + - [036564423277] daemon/lldpd: return NULL from lldpd_get_os_release on empty result (Vincent Bernat) + - [e408f527a737] daemon/edp: dedup management addresses against the destination list (Vincent Bernat) + - [b3233ca9b39c] daemon/interfaces-bsd: cap NetBSD aggregate port count (Vincent Bernat) + - [877498d75a2f] daemon/interfaces-bsd: free req in ifbsd_check_bridge (Vincent Bernat) + - [7875d4973307] daemon/priv-bsd: fix typos in asroot_iface_description_os (Vincent Bernat) + - [8d9565365d1a] marshal: use ssize_t for size accumulators in unserialize (Vincent Bernat) + - [1c91e281e27b] daemon/seccomp: use only async-signal-safe calls in SIGSYS handler (Vincent Bernat) + - [ab0f522ad63a] log: do not re-feed caller fmt as a format string to stderr (Vincent Bernat) + - [d527ddae3c5f] daemon/event: avoid double-free of client on send failure (Vincent Bernat) + - [b718c1536dfe] ctl: tighten umask around bind() for the control socket (Vincent Bernat) + - [5d93df6902d1] daemon/priv-linux: reject embedded NUL in authorized path (Vincent Bernat) + - [8fac206056fd] daemon/priv: mark monitored as volatile sig_atomic_t (Vincent Bernat) + - [6fcc94a5c6aa] client/lldpcli: guard argc>0 before indexing argv (Vincent Bernat) + - [ee7c2bec7edb] client/tokenizer: heap-allocate the work buffer (Vincent Bernat) + - [c096e5de3879] daemon/privsep_fd: bail out on failure or short read (Vincent Bernat) + - [f04e2b6c1c72] daemon/dmi-osx: handle CFStringGetCStringPtr returning NULL (Vincent Bernat) + - [b863453629d7] daemon/agent: guard against NULL/empty net-snmp log message (Vincent Bernat) + - [779bc1e37acf] lldpd-structs: bound custom TLV oui_info length (Vincent Bernat) + - [faf8fcab78c7] daemon/client: bound MED location data length (Vincent Bernat) + - [883afdb669d1] client/json: escape object keys (Vincent Bernat) + - [6f55f7afc870] client/json: escape control character 0x1F (Vincent Bernat) + - [71e23bb6f2f2] daemon/priv: fix ctlname parameter shadowing file-scope global (Vincent Bernat) + - [7ba39ef0cd5b] daemon/seccomp: fix out-of-bounds index of syscall_names (Vincent Bernat) + - [1d55036cb80a] daemon/lldp: reject zero-length management address (Vincent Bernat) + - [435fb46275a4] build: update docker actions (Vincent Bernat) + - [a8098a6fcf69] build: bump cross-platform-actions/action to v1.0.0 (Vincent Bernat) + - [50919c12d1c0] build: downgrade FreeBSD to 14.3 (Vincent Bernat) + - [fa27fef5d4a9] build: test on FreeBSD 15.0 (Vincent Bernat) + - [909e3793d7cd] daemon/cdp: fix another logic error when parsing FDP packets (Vincent Bernat) + - [89105ea86da6] daemon/cdp: fix FDP MAC address (Vincent Bernat) + - [b280f34719a3] build: bump pytest from 7.2.0 to 9.0.3 in /tests/integration (dependabot[bot]) + - [69f50b948eab] liblldpctl: Fix const correctness of the receive callback (Bartel Sielski) + - [1f4189b9ae2b] build: use a multi-stage build for Dockerfile (Vincent Bernat) + - [cd89d00dec81] build: untabify Dockerfile (Vincent Bernat) + 1.0.21 [2026-03-14 22:17:53 +0100]: - [25e90db27404] release: 1.0.21 (Vincent Bernat) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/NEWS new/lldpd-1.0.22/NEWS --- old/lldpd-1.0.21/NEWS 2026-03-11 08:01:51.000000000 +0100 +++ new/lldpd-1.0.22/NEWS 2026-05-14 23:07:47.000000000 +0200 @@ -1,3 +1,12 @@ +lldpd (1.0.22) + * Fix: + + Fix out-of-bound read access when removing VLAN tag (CVE-2026-46433, #787) + + Reject 0-length management address in LLDP + + Fix race condition when creating the control socket + + Fix FDP MAC address + + Fix memory leak in the BSD bridge query path + + Fix duplicate management addresses when merging EDP VLAN frames + lldpd (1.0.21) * Changes: + Add "configure lldp portdescription-source" to choose how to populate port description (#763) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/configure new/lldpd-1.0.22/configure --- old/lldpd-1.0.21/configure 2026-03-14 22:20:32.000000000 +0100 +++ new/lldpd-1.0.22/configure 2026-05-14 23:17:18.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for lldpd 1.0.21. +# Generated by GNU Autoconf 2.72 for lldpd 1.0.22. # # Report bugs to <https://github.com/lldpd/lldpd/issues>. # @@ -614,8 +614,8 @@ # Identity of this package. PACKAGE_NAME='lldpd' PACKAGE_TARNAME='lldpd' -PACKAGE_VERSION='1.0.21' -PACKAGE_STRING='lldpd 1.0.21' +PACKAGE_VERSION='1.0.22' +PACKAGE_STRING='lldpd 1.0.22' PACKAGE_BUGREPORT='https://github.com/lldpd/lldpd/issues' PACKAGE_URL='https://lldpd.github.io/' @@ -1559,7 +1559,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures lldpd 1.0.21 to adapt to many kinds of systems. +'configure' configures lldpd 1.0.22 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1630,7 +1630,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lldpd 1.0.21:";; + short | recursive ) echo "Configuration of lldpd 1.0.22:";; esac cat <<\_ACEOF @@ -1861,7 +1861,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lldpd configure 1.0.21 +lldpd configure 1.0.22 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2290,7 +2290,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by lldpd $as_me 1.0.21, which was +It was created by lldpd $as_me 1.0.22, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3781,7 +3781,7 @@ # Define the identity of the package. PACKAGE='lldpd' - VERSION='1.0.21' + VERSION='1.0.22' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -27131,7 +27131,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by lldpd $as_me 1.0.21, which was +This file was extended by lldpd $as_me 1.0.22, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -27200,7 +27200,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -lldpd config.status 1.0.21 +lldpd config.status 1.0.22 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/libevent/build-aux/ltmain.sh new/lldpd-1.0.22/libevent/build-aux/ltmain.sh --- old/lldpd-1.0.21/libevent/build-aux/ltmain.sh 2026-03-14 22:20:26.000000000 +0100 +++ new/lldpd-1.0.22/libevent/build-aux/ltmain.sh 2026-05-14 23:17:12.000000000 +0200 @@ -31,7 +31,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.5.4 Debian-2.5.4-9" +VERSION="2.5.4 Debian-2.5.4-11" package_revision=2.5.4 @@ -2218,7 +2218,7 @@ year=`date +%Y` cat <<EOF -$progname $scriptversion Debian-2.5.4-9 +$progname $scriptversion Debian-2.5.4-11 Copyright (C) $year Free Software Foundation, Inc. License GPLv2+: GNU GPL version 2 or later <https://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. @@ -2312,12 +2312,12 @@ compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname $scriptversion Debian-2.5.4-9 + version: $progname $scriptversion Debian-2.5.4-11 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to <[email protected]>. -GNU libtool home page: <https://www.gnu.org/s/libtool/>. +GNU libtool home page: <https://www.gnu.org/software/libtool/>. General help using GNU software: <https://www.gnu.org/gethelp/>." exit 0 } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/ltmain.sh new/lldpd-1.0.22/ltmain.sh --- old/lldpd-1.0.21/ltmain.sh 2026-03-14 22:20:29.000000000 +0100 +++ new/lldpd-1.0.22/ltmain.sh 2026-05-14 23:17:15.000000000 +0200 @@ -31,7 +31,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.5.4 Debian-2.5.4-9" +VERSION="2.5.4 Debian-2.5.4-11" package_revision=2.5.4 @@ -2218,7 +2218,7 @@ year=`date +%Y` cat <<EOF -$progname $scriptversion Debian-2.5.4-9 +$progname $scriptversion Debian-2.5.4-11 Copyright (C) $year Free Software Foundation, Inc. License GPLv2+: GNU GPL version 2 or later <https://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. @@ -2312,12 +2312,12 @@ compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname $scriptversion Debian-2.5.4-9 + version: $progname $scriptversion Debian-2.5.4-11 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to <[email protected]>. -GNU libtool home page: <https://www.gnu.org/s/libtool/>. +GNU libtool home page: <https://www.gnu.org/software/libtool/>. General help using GNU software: <https://www.gnu.org/gethelp/>." exit 0 } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/client/json_writer.c new/lldpd-1.0.22/src/client/json_writer.c --- old/lldpd-1.0.21/src/client/json_writer.c 2026-03-10 08:36:54.000000000 +0100 +++ new/lldpd-1.0.22/src/client/json_writer.c 2026-05-09 15:36:21.000000000 +0200 @@ -138,8 +138,8 @@ * replacement character */ fprintf(fh, "\\uFFFD"); s++; - } else if (c < 0x1f) { - /* 7-bit ASCII character */ + } else if (c <= 0x1f) { + /* C0 control character */ fprintf(fh, "\\u%04X", c); s++; } else { @@ -171,7 +171,10 @@ fprintf(fh, "%c\n%*s", pairs[(current->tag == ARRAY)][0], indent + 2, ""); TAILQ_FOREACH (el, ¤t->children, next) { - if (current->tag == OBJECT) fprintf(fh, "\"%s\": ", el->key); + if (current->tag == OBJECT) { + json_string_dump(fh, el->key); + fprintf(fh, ": "); + } json_element_dump(fh, el, indent + 2); if (TAILQ_NEXT(el, next)) fprintf(fh, ",\n%*s", indent + 2, ""); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/client/lldpcli.c new/lldpd-1.0.22/src/client/lldpcli.c --- old/lldpd-1.0.21/src/client/lldpcli.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/client/lldpcli.c 2026-05-09 15:36:21.000000000 +0200 @@ -216,7 +216,7 @@ char *compl = commands_complete(root, argc, (const char **)argv, all, is_privileged()); - if (compl &&strlen(argv[argc - 1]) < strlen(compl )) { + if (compl &&argc > 0 && strlen(argv[argc - 1]) < strlen(compl )) { if (rl_insert_text(compl +strlen(argv[argc - 1])) < 0) { free(compl ); goto end; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/client/tokenizer.c new/lldpd-1.0.22/src/client/tokenizer.c --- old/lldpd-1.0.21/src/client/tokenizer.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/client/tokenizer.c 2026-05-09 15:36:21.000000000 +0200 @@ -17,6 +17,7 @@ #include "client.h" +#include <stdlib.h> #include <string.h> /** * Tokenize the given line. We support quoted strings and escaped characters @@ -42,8 +43,9 @@ int escaped = 0; int ipos = 0; char quote = 0; - char input[2 * strlen(line) + 3]; /* 3 = 2 for '\n ' and 1 for \0 */ - memset(input, 0, 2 * strlen(line) + 3); + size_t input_len = 2 * strlen(line) + 3; /* 3 = 2 for '\n ' and 1 for \0 */ + char *input = calloc(1, input_len); + if (input == NULL) return -1; for (int pos = 0; line[pos]; pos++) { if (line[pos] == '#' && !escaped && !quote) break; if (!escaped && strchr(escapes, line[pos])) @@ -60,7 +62,10 @@ escaped = 0; } } - if (escaped || quote) return 1; + if (escaped || quote) { + free(input); + return 1; + } /* Trick to not have to handle \0 in a special way */ input[ipos++] = ifs[0]; input[ipos++] = ' '; @@ -100,9 +105,11 @@ *argc = iargc; *argv = iargv; + free(input); return 0; error: + free(input); tokenize_free(iargc, iargv); return -1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/ctl.c new/lldpd-1.0.22/src/ctl.c --- old/lldpd-1.0.21/src/ctl.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/ctl.c 2026-05-09 15:36:21.000000000 +0200 @@ -20,6 +20,7 @@ #include <fcntl.h> #include <errno.h> #include <sys/types.h> +#include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> #include <string.h> @@ -41,6 +42,9 @@ int s; struct sockaddr_un su; int rc; +#ifdef ENABLE_PRIVSEP + mode_t old_umask; +#endif log_debug("control", "create control socket %s", name); @@ -51,7 +55,16 @@ } su.sun_family = AF_UNIX; strlcpy(su.sun_path, name, sizeof(su.sun_path)); - if (bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) { +#ifdef ENABLE_PRIVSEP + /* Tighten the umask so the socket is not world-accessible between + * bind() and the subsequent chown()/chmod(). */ + old_umask = umask(S_IRWXO); +#endif + rc = bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)); +#ifdef ENABLE_PRIVSEP + umask(old_umask); +#endif + if (rc == -1) { rc = errno; close(s); errno = rc; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/agent.c new/lldpd-1.0.22/src/daemon/agent.c --- old/lldpd-1.0.21/src/daemon/agent.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/agent.c 2026-05-09 15:36:21.000000000 +0200 @@ -1852,12 +1852,16 @@ agent_log_callback(int major, int minor, void *serverarg, void *clientarg) { struct snmp_log_message *slm = (struct snmp_log_message *)serverarg; - char *msg = strdup(slm->msg); + char *msg = NULL; + size_t len; (void)major; (void)minor; (void)clientarg; - if (msg && msg[strlen(msg) - 1] == '\n') msg[strlen(msg) - 1] = '\0'; + if (slm->msg == NULL) return 0; + msg = strdup(slm->msg); + if (msg && (len = strlen(msg)) > 0 && msg[len - 1] == '\n') + msg[len - 1] = '\0'; switch (slm->priority) { case LOG_EMERG: log_warnx("libsnmp", "%s", msg ? msg : slm->msg); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/client.c new/lldpd-1.0.22/src/daemon/client.c --- old/lldpd-1.0.21/src/daemon/client.c 2026-02-19 20:26:51.000000000 +0100 +++ new/lldpd-1.0.22/src/daemon/client.c 2026-05-09 15:36:21.000000000 +0200 @@ -529,6 +529,12 @@ set->med_location->format); return -1; } + if (set->med_location->data_len < 0 || + set->med_location->data_len > LLDP_TLV_ORG_OUI_INFO_MAXLEN) { + log_warnx("rpc", "invalid location data length provided: %d", + set->med_location->data_len); + return -1; + } loc = &port->p_med_location[set->med_location->format - 1]; free(loc->data); memcpy(loc, set->med_location, sizeof(struct lldpd_med_loc)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/dmi-osx.c new/lldpd-1.0.22/src/daemon/dmi-osx.c --- old/lldpd-1.0.21/src/daemon/dmi-osx.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/dmi-osx.c 2026-05-09 15:36:21.000000000 +0200 @@ -44,26 +44,42 @@ cfres = IORegistryEntryCreateCFProperty(service, property, kCFAllocatorDefault, kNilOptions); if (!cfres) { + const char *prop_name = + CFStringGetCStringPtr(property, kCFStringEncodingMacRoman); log_debug("localchassis", "cannot find property %s in class %s in registry", - CFStringGetCStringPtr(property, kCFStringEncodingMacRoman), - classname); + prop_name ? prop_name : "(unknown)", classname); goto end; } - if (CFGetTypeID(cfres) == CFStringGetTypeID()) - result = strdup(CFStringGetCStringPtr((CFStringRef)cfres, - kCFStringEncodingMacRoman)); - else if (CFGetTypeID(cfres) == CFDataGetTypeID()) { + if (CFGetTypeID(cfres) == CFStringGetTypeID()) { + const char *cstr = CFStringGetCStringPtr((CFStringRef)cfres, + kCFStringEncodingMacRoman); + if (cstr != NULL) { + result = strdup(cstr); + } else { + CFIndex len = + CFStringGetLength((CFStringRef)cfres) * 4 + 1; + result = calloc(1, len); + if (result && + !CFStringGetCString((CFStringRef)cfres, result, len, + kCFStringEncodingMacRoman)) { + free(result); + result = NULL; + } + } + } else if (CFGetTypeID(cfres) == CFDataGetTypeID()) { /* OK, we know this is a string. */ result = calloc(1, CFDataGetLength((CFDataRef)cfres) + 1); if (!result) goto end; memcpy(result, CFDataGetBytePtr((CFDataRef)cfres), CFDataGetLength((CFDataRef)cfres)); - } else + } else { + const char *prop_name = + CFStringGetCStringPtr(property, kCFStringEncodingMacRoman); log_debug("localchassis", "unknown type for property %s in class %s", - CFStringGetCStringPtr(property, kCFStringEncodingMacRoman), - classname); + prop_name ? prop_name : "(unknown)", classname); + } end: if (cfres) CFRelease(cfres); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/event.c new/lldpd-1.0.22/src/daemon/event.c --- old/lldpd-1.0.21/src/daemon/event.c 2026-02-19 20:26:51.000000000 +0100 +++ new/lldpd-1.0.22/src/daemon/event.c 2026-05-09 15:36:21.000000000 +0200 @@ -258,6 +258,8 @@ } } +/* Returns the number of bytes written, or -1 on error. On error, the caller + * is responsible for freeing the client. */ static ssize_t levent_ctl_send(struct lldpd_one_client *client, int type, void *data, size_t len) { @@ -267,7 +269,6 @@ if (bufferevent_write(bev, &hdr, sizeof(struct hmsg_header)) == -1 || (len > 0 && bufferevent_write(bev, data, len) == -1)) { log_warnx("event", "unable to create answer to client"); - levent_ctl_free_client(client); return -1; } bufferevent_enable(bev, EV_WRITE); @@ -309,7 +310,8 @@ } } - levent_ctl_send(client, NOTIFICATION, output, output_len); + if (levent_ctl_send(client, NOTIFICATION, output, output_len) == -1) + levent_ctl_free_client(client); } free(output); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/interfaces-bsd.c new/lldpd-1.0.22/src/daemon/interfaces-bsd.c --- old/lldpd-1.0.21/src/daemon/interfaces-bsd.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/interfaces-bsd.c 2026-05-09 15:36:21.000000000 +0200 @@ -75,11 +75,15 @@ struct ifbifconf bifc = {}; retry_alloc: - if ((req = realloc(req, ifbic_len)) == NULL) { - log_warn("interfaces", "unable to allocate memory to query bridge %s", - master->name); - free(bifc.ifbic_req); - return; + { + struct ifbreq *new_req = realloc(req, ifbic_len); + if (new_req == NULL) { + log_warn("interfaces", + "unable to allocate memory to query bridge %s", + master->name); + goto end; + } + req = new_req; } bifc.ifbic_len = ifbic_len; bifc.ifbic_req = req; @@ -93,13 +97,13 @@ strlcpy(ifd.ifd_name, master->name, sizeof(ifd.ifd_name)); if (ioctl(cfg->g_sock, SIOCGDRVSPEC, (caddr_t)&ifd) < 0) { log_debug("interfaces", "%s is not a bridge", master->name); - return; + goto end; } #elif defined HOST_OS_OPENBSD strlcpy(bifc.ifbic_name, master->name, sizeof(bifc.ifbic_name)); if (ioctl(cfg->g_sock, SIOCBRDGIFS, (caddr_t)&bifc) < 0) { log_debug("interfaces", "%s is not a bridge", master->name); - return; + goto end; } #else # error Unsupported OS @@ -122,6 +126,8 @@ slave->upper = master; } master->type |= IFACE_BRIDGE_T; +end: + free(req); } static void @@ -160,7 +166,8 @@ master->type |= IFACE_BOND_T; #elif defined HOST_OS_NETBSD /* No max, we consider a maximum of 24 ports */ - char buf[sizeof(struct agrportinfo) * 24] = {}; +# define IFBSD_NETBSD_MAX_AGRPORTS 24 + char buf[sizeof(struct agrportinfo) * IFBSD_NETBSD_MAX_AGRPORTS] = {}; size_t buflen = sizeof(buf); struct agrreq ar = { .ar_version = AGRREQ_VERSION, .ar_cmd = AGRCMD_PORTLIST, @@ -180,6 +187,8 @@ } return; } + if (apl->apl_nports > IFBSD_NETBSD_MAX_AGRPORTS) + apl->apl_nports = IFBSD_NETBSD_MAX_AGRPORTS; for (int i = 0; i < apl->apl_nports; i++, api++) { struct interfaces_device *slave; slave = interfaces_nametointerface(interfaces, api->api_ifname); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/lldpd.c new/lldpd-1.0.22/src/daemon/lldpd.c --- old/lldpd-1.0.21/src/daemon/lldpd.c 2026-03-10 08:46:47.000000000 +0100 +++ new/lldpd-1.0.22/src/daemon/lldpd.c 2026-05-12 20:49:00.000000000 +0200 @@ -574,7 +574,7 @@ /* VLAN decapsulation means to shift 4 bytes left the frame from * offset 2*ETHER_ADDR_LEN */ memmove(frame + 2 * ETHER_ADDR_LEN, frame + 2 * ETHER_ADDR_LEN + 4, - s - 2 * ETHER_ADDR_LEN); + s - 2 * ETHER_ADDR_LEN - 4); s -= 4; } @@ -877,6 +877,7 @@ *ptr1 = '\0'; ptr1--; } + if (release[0] == '\0') return NULL; if (release[0] == '"') return release + 1; return release; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/priv-bsd.c new/lldpd-1.0.22/src/daemon/priv-bsd.c --- old/lldpd-1.0.21/src/daemon/priv-bsd.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/priv-bsd.c 2026-05-09 15:36:21.000000000 +0200 @@ -211,7 +211,7 @@ struct ifreq ifr = { .ifr_data = (caddr_t)descr }; # endif strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 1) { + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { rc = errno; log_warnx("privsep", "unable to open inet socket"); return rc; @@ -241,7 +241,7 @@ } else snprintf(descr, sizeof(descr), "lldpd: connected to %s", description); # if defined HOST_OS_FREEBSD - ift.ifr_buffer.length = strlen(descr); + ifr.ifr_buffer.length = strlen(descr); # endif if (ioctl(sock, SIOCSIFDESCR, (caddr_t)&ifr) < 0) { rc = errno; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/priv-linux.c new/lldpd-1.0.22/src/daemon/priv-linux.c --- old/lldpd-1.0.21/src/daemon/priv-linux.c 2026-03-11 08:01:51.000000000 +0100 +++ new/lldpd-1.0.22/src/daemon/priv-linux.c 2026-05-09 15:36:21.000000000 +0200 @@ -79,6 +79,12 @@ must_read(PRIV_PRIVILEGED, file, len); file[len] = '\0'; + if (memchr(file, '\0', len) != NULL) { + log_warnx("privsep", "embedded NUL byte in path"); + free(file); + return NULL; + } + for (f = authorized; *f != NULL; f++) { if (regcomp(&preg, *f, REG_NOSUB) != 0) fatal("privsep", "unable to compile a regex"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/priv-seccomp.c new/lldpd-1.0.22/src/daemon/priv-seccomp.c --- old/lldpd-1.0.21/src/daemon/priv-seccomp.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/priv-seccomp.c 2026-05-09 15:36:21.000000000 +0200 @@ -42,8 +42,8 @@ /* If there is no privilege separation, seccomp is currently useless */ #ifdef ENABLE_PRIVSEP -static int monitored = -1; -static int trapped = 0; +static volatile sig_atomic_t monitored = -1; +static volatile sig_atomic_t trapped = 0; /** * SIGSYS signal handler * @param nr the signal number @@ -68,15 +68,20 @@ syscall = ctx->uc_mcontext.gregs[REG_SYSCALL]; trapped = 1; - /* Log them. Technically, `log_warnx()` is not signal safe, but we are - * unlikely to reenter here. */ - log_warnx("seccomp", "invalid syscall attempted: %s(%d)", - (syscall < sizeof(syscall_names)) ? syscall_names[syscall] : "unknown", - syscall); + /* Log via write(2) only; stdio/syslog are not async-signal-safe. */ + static const char prefix[] = "seccomp: invalid syscall attempted: "; + const char *name = + (syscall < sizeof(syscall_names) / sizeof(syscall_names[0])) ? + syscall_names[syscall] : + "unknown"; + const char *end = name; + while (*end) end++; + (void)!write(STDERR_FILENO, prefix, sizeof(prefix) - 1); + (void)!write(STDERR_FILENO, name, end - name); + (void)!write(STDERR_FILENO, "\n", 1); /* Kill children and exit */ kill(monitored, SIGTERM); - fatalx("seccomp", "invalid syscall not allowed: stop here"); _exit(161); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/priv.c new/lldpd-1.0.22/src/daemon/priv.c --- old/lldpd-1.0.21/src/daemon/priv.c 2026-03-11 08:01:51.000000000 +0100 +++ new/lldpd-1.0.22/src/daemon/priv.c 2026-05-09 15:36:21.000000000 +0200 @@ -73,7 +73,7 @@ #endif #ifdef ENABLE_PRIVSEP -static int monitored = -1; /* Child */ +static volatile sig_atomic_t monitored = -1; /* Child */ #endif static char *ctlname = NULL; /* Registered control socket path */ @@ -689,14 +689,14 @@ void #ifdef ENABLE_PRIVSEP -priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid, const char *ctlname) +priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid, const char *name) #else -priv_init(const char *ctlname) +priv_init(const char *name) #endif { /* Store the expected control socket path for asroot_ctl_cleanup() */ - if (ctlname) { - ctlname = strdup(ctlname); + if (name) { + ctlname = strdup(name); if (ctlname == NULL) fatal("privsep", NULL); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/privsep_fd.c new/lldpd-1.0.22/src/daemon/privsep_fd.c --- old/lldpd-1.0.21/src/daemon/privsep_fd.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/privsep_fd.c 2026-05-09 15:36:21.000000000 +0200 @@ -108,18 +108,26 @@ msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); - if ((n = recvmsg(priv_fd(ctx), &msg, 0)) == -1) log_warn("privsep", "recvmsg"); - if (n != sizeof(int)) - log_warnx("privsep", "recvmsg: expected received 1 got %ld", (long)n); + if ((n = recvmsg(priv_fd(ctx), &msg, 0)) == -1) { + log_warn("privsep", "recvmsg"); + return -1; + } + if (n != sizeof(int)) { + log_warnx("privsep", "recvmsg: expected received 1 got %ld", + (long)n); + return -1; + } if (result == 0) { cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL) { log_warnx("privsep", "no message header"); return -1; } - if (cmsg->cmsg_type != SCM_RIGHTS) + if (cmsg->cmsg_type != SCM_RIGHTS) { log_warnx("privsep", "expected type %d got %d", SCM_RIGHTS, cmsg->cmsg_type); + return -1; + } memcpy(&fd, CMSG_DATA(cmsg), sizeof(int)); return fd; } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/protocols/cdp.c new/lldpd-1.0.22/src/daemon/protocols/cdp.c --- old/lldpd-1.0.21/src/daemon/protocols/cdp.c 2025-12-06 09:25:19.000000000 +0100 +++ new/lldpd-1.0.22/src/daemon/protocols/cdp.c 2026-05-08 23:20:03.000000000 +0200 @@ -291,7 +291,7 @@ int software_len = 0, platform_len = 0, proto, version, nb, caps; const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR; # ifdef ENABLE_FDP - const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR; + const unsigned char fdpaddr[] = FDP_MULTICAST_ADDR; int fdp = 0; # endif u_int8_t *pos, *tlv, *pos_address, *pos_next_address; @@ -329,7 +329,7 @@ if (PEEK_CMP(cdpaddr, sizeof(cdpaddr)) != 0) { # ifdef ENABLE_FDP PEEK_RESTORE((u_int8_t *)frame); - if (PEEK_CMP(fdpaddr, sizeof(fdpaddr)) != 0) + if (PEEK_CMP(fdpaddr, sizeof(fdpaddr)) == 0) fdp = 1; else { # endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/protocols/edp.c new/lldpd-1.0.22/src/daemon/protocols/edp.c --- old/lldpd-1.0.21/src/daemon/protocols/edp.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/protocols/edp.c 2026-05-09 15:36:21.000000000 +0200 @@ -476,7 +476,8 @@ mgmt_next = TAILQ_NEXT(mgmt, m_entries); TAILQ_REMOVE(&chassis->c_mgmt, mgmt, m_entries); /* Don't add an address that already exists! */ - TAILQ_FOREACH (m, &chassis->c_mgmt, m_entries) + TAILQ_FOREACH (m, &oport->p_chassis->c_mgmt, + m_entries) if (m->m_family == mgmt->m_family && !memcmp(&m->m_addr, &mgmt->m_addr, sizeof(m->m_addr))) @@ -485,6 +486,8 @@ TAILQ_INSERT_TAIL( &oport->p_chassis->c_mgmt, mgmt, m_entries); + else + free(mgmt); } } /* We discard the remaining frame */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/daemon/protocols/lldp.c new/lldpd-1.0.22/src/daemon/protocols/lldp.c --- old/lldpd-1.0.21/src/daemon/protocols/lldp.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/daemon/protocols/lldp.c 2026-05-09 15:36:21.000000000 +0200 @@ -796,8 +796,10 @@ case LLDP_TLV_MGMT_ADDR: CHECK_TLV_SIZE(1, "Management address"); addr_str_length = PEEK_UINT8; - if (addr_str_length > sizeof(addr_str_buffer)) { - log_warnx("lldp", "too large management address on %s", + if (addr_str_length < 1 || + addr_str_length > sizeof(addr_str_buffer)) { + log_warnx("lldp", + "invalid management address length on %s", hardware->h_ifname); goto malformed; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/lib/connection.c new/lldpd-1.0.22/src/lib/connection.c --- old/lldpd-1.0.21/src/lib/connection.c 2026-02-19 20:26:51.000000000 +0100 +++ new/lldpd-1.0.22/src/lib/connection.c 2026-05-08 22:58:03.000000000 +0200 @@ -61,7 +61,7 @@ /* Statically receive data from remote end. */ static ssize_t -sync_recv(lldpctl_conn_t *lldpctl, const uint8_t *data, size_t length, void *user_data) +sync_recv(lldpctl_conn_t *lldpctl, uint8_t *data, size_t length, void *user_data) { struct lldpctl_conn_sync_t *conn = user_data; ssize_t nb = 0; @@ -92,8 +92,7 @@ if (fds[1].revents & POLLIN) { /* Message from daemon. */ - if ((nb = read(conn->fd, (unsigned char *)data + offset, - remain)) == -1) { + if ((nb = read(conn->fd, data + offset, remain)) == -1) { if (errno == EAGAIN || errno == EINTR) continue; return LLDPCTL_ERR_CALLBACK_FAILURE; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/lib/lldpctl.h new/lldpd-1.0.22/src/lib/lldpctl.h --- old/lldpd-1.0.21/src/lib/lldpctl.h 2026-02-19 20:26:51.000000000 +0100 +++ new/lldpd-1.0.22/src/lib/lldpctl.h 2026-05-08 22:58:03.000000000 +0200 @@ -129,7 +129,7 @@ * @c LLDPCTL_ERR_CALLBACK_FAILURE for other errors or @c * LLDPCTL_ERR_EOF if end of file was reached. */ -typedef ssize_t (*lldpctl_recv_callback)(lldpctl_conn_t *conn, const uint8_t *data, +typedef ssize_t (*lldpctl_recv_callback)(lldpctl_conn_t *conn, uint8_t *data, size_t length, void *user_data); /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/lldpd-structs.c new/lldpd-1.0.22/src/lldpd-structs.c --- old/lldpd-1.0.21/src/lldpd-structs.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/lldpd-structs.c 2026-05-09 15:36:21.000000000 +0200 @@ -101,6 +101,12 @@ { struct lldpd_custom *custom; + if (curr->oui_info_len < 0 || + curr->oui_info_len > LLDP_TLV_ORG_OUI_INFO_MAXLEN) { + log_warnx("rpc", "invalid custom TLV info length: %d", + curr->oui_info_len); + return; + } if ((custom = malloc(sizeof(struct lldpd_custom)))) { memcpy(custom, curr, sizeof(struct lldpd_custom)); if ((custom->oui_info = malloc(custom->oui_info_len))) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/log.c new/lldpd-1.0.22/src/log.c --- old/lldpd-1.0.21/src/log.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/log.c 2026-05-09 15:36:21.000000000 +0200 @@ -173,18 +173,15 @@ va_end(ap2); } - /* Log to standard error in all cases */ - char *nfmt; - /* best effort in out of mem situations */ - if (asprintf(&nfmt, "%s %s%s%s]%s %s\n", date(), translate(STDERR_FILENO, pri), - token ? "/" : "", token ? token : "", - isatty(STDERR_FILENO) ? "\033[0m" : "", fmt) == -1) { - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } else { - vfprintf(stderr, nfmt, ap); - free(nfmt); - } + /* Log to standard error in all cases. Format the caller's message + * first so it is not re-interpreted as a format string by the + * surrounding fprintf. */ + char *body = NULL; + if (vasprintf(&body, fmt, ap) == -1) body = NULL; + fprintf(stderr, "%s %s%s%s]%s %s\n", date(), translate(STDERR_FILENO, pri), + token ? "/" : "", token ? token : "", + isatty(STDERR_FILENO) ? "\033[0m" : "", body ? body : fmt); + free(body); fflush(stderr); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lldpd-1.0.21/src/marshal.c new/lldpd-1.0.22/src/marshal.c --- old/lldpd-1.0.21/src/marshal.c 2025-08-30 20:02:39.000000000 +0200 +++ new/lldpd-1.0.22/src/marshal.c 2026-05-09 15:36:21.000000000 +0200 @@ -257,17 +257,18 @@ marshal_unserialize_(struct marshal_info *mi, void *buffer, size_t len, void **output, void *_pointers, int skip, int osize) { - int total_len = sizeof(struct marshal_serialized) + (skip ? 0 : mi->size); + ssize_t total_len = sizeof(struct marshal_serialized) + (skip ? 0 : mi->size); struct marshal_serialized *serialized = buffer; struct gc_l *pointers = _pointers; - int size, already, extra = 0; + ssize_t size; + int already, extra = 0; void *new; struct marshal_subinfo *current; struct gc *apointer; log_debug("marshal", "start unserialization of %s", mi->name); - if (len < sizeof(struct marshal_serialized) || len < total_len) { + if (len < sizeof(struct marshal_serialized) || (ssize_t)len < total_len) { log_warnx("marshal", "data to deserialize is too small (%zu) for structure %s", len, mi->name); @@ -295,12 +296,19 @@ 1; break; case 'f': + if (osize < 0) { + log_warnx("marshal", + "negative fixed string size for %s", + mi->name); + total_len = 0; + goto unmarshal_error; + } size = osize; extra = 1; break; /* The extra byte is to ensure that the string is null terminated. */ } - if (size > len - sizeof(struct marshal_serialized)) { + if ((size_t)size > len - sizeof(struct marshal_serialized)) { log_warnx("marshal", "data to deserialize contains a string too long"); total_len = 0; @@ -353,7 +361,7 @@ sizeof(int)); padlen = ALIGNOF(struct marshal_serialized); padlen = (padlen - (total_len % padlen)) % padlen; - if (len < total_len + padlen || + if (total_len < 0 || (size_t)total_len + padlen > len || ((sublen = marshal_unserialize_(current->mi, (unsigned char *)buffer + total_len + padlen, len - total_len - padlen, &new, pointers,
