libudev-zero: update to 1.0.4

First upstream release since 2023-07. All four locally-carried patches
are merged in 1.0.4 and can be dropped:

- 0001 (PR #57): udev_device.c TOCTOU race fix
- 0002 (PR #62): avoid OOM on small systems
- 0003 (PR #66): correct touchpad detection
- 0004 (PR #80): hwdb USB ID lookup from usb.ids

The release also pulls in PR #79 (do not assume EV_REL and EV_ABS are
mutually exclusive in udev_device.c).

Release notes:
https://github.com/illiliti/libudev-zero/releases/tag/1.0.4

Signed-off-by: Alexandru Ardelean <alex@shruggie.ro>
This commit is contained in:
Alexandru Ardelean
2026-05-25 19:09:14 +03:00
committed by Daniel Golle
parent e74e7138fb
commit f10dfca2ba
5 changed files with 3 additions and 482 deletions
+3 -3
View File
@@ -5,12 +5,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=libudev-zero
PKG_VERSION:=1.0.3
PKG_RELEASE:=3
PKG_VERSION:=1.0.4
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/illiliti/libudev-zero/tar.gz/$(PKG_VERSION)?
PKG_HASH:=0bd89b657d62d019598e6c7ed726ff8fed80e8ba092a83b484d66afb80b77da5
PKG_HASH:=10148cfd6047d387bf71eca72cd19c177084224d96434a118d8def6e0a3d6316
PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
PKG_LICENSE:=ISC
@@ -1,59 +0,0 @@
From a2cc51bb142c16eac5598237d2edb46f095607be Mon Sep 17 00:00:00 2001
From: Mingjie Shen <mjshen137@gmail.com>
Date: Tue, 5 Dec 2023 03:41:24 -0500
Subject: [PATCH] udev_device.c: fix TOCTOU race condition (#57)
Separately checking the state of a file before operating on it may allow
an attacker to modify the file between the two operations.
Reference: CWE-367.
---
udev_device.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
--- a/udev_device.c
+++ b/udev_device.c
@@ -267,16 +267,17 @@ const char *udev_device_get_sysattr_valu
snprintf(path, sizeof(path), "%s/%s", udev_device_get_syspath(udev_device), sysattr);
- if (lstat(path, &st) != 0 || !S_ISREG(st.st_mode)) {
- return NULL;
- }
-
file = fopen(path, "r");
if (!file) {
return NULL;
}
+ if (fstat(fileno(file), &st) != 0 || !S_ISREG(st.st_mode)) {
+ fclose(file);
+ return NULL;
+ }
+
// TODO dynamic allocation of data
len = fread(data, 1, sizeof(data) - 1, file);
@@ -309,16 +310,17 @@ int udev_device_set_sysattr_value(struct
snprintf(path, sizeof(path), "%s/%s", udev_device_get_syspath(udev_device), sysattr);
- if (lstat(path, &st) != 0 || !S_ISREG(st.st_mode)) {
- return -1;
- }
-
file = fopen(path, "w");
if (!file) {
return -1;
}
+ if (fstat(fileno(file), &st) != 0 || !S_ISREG(st.st_mode)) {
+ fclose(file);
+ return -1;
+ }
+
len = strlen(value);
if (fwrite(value, 1, len, file) != len) {
@@ -1,163 +0,0 @@
From 5eca08d71d51074bfe7b14fcf7d89318f4f6ff47 Mon Sep 17 00:00:00 2001
From: liamHowatt <30486941+liamHowatt@users.noreply.github.com>
Date: Tue, 5 Dec 2023 04:15:26 -0500
Subject: [PATCH] Avoidable OOM on small systems (#62)
* bandaid fix OOM
* refactor fix OOM
* Makefile: remove no longer needed -pthread option
* libudev.pc.in: remove threads requirement
---------
Co-authored-by: illiliti <illiliti@protonmail.com>
---
Makefile | 2 +-
libudev.pc.in | 1 -
udev_enumerate.c | 65 +++++++++++-------------------------------------
3 files changed, 15 insertions(+), 53 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ PREFIX = /usr/local
LIBDIR = ${PREFIX}/lib
INCLUDEDIR = ${PREFIX}/include
PKGCONFIGDIR = ${LIBDIR}/pkgconfig
-XCFLAGS = ${CPPFLAGS} ${CFLAGS} -std=c99 -fPIC -pthread -D_XOPEN_SOURCE=700 \
+XCFLAGS = ${CPPFLAGS} ${CFLAGS} -std=c99 -fPIC -D_XOPEN_SOURCE=700 \
-Wall -Wextra -Wpedantic -Wmissing-prototypes -Wstrict-prototypes \
-Wno-unused-parameter
XLDFLAGS = ${LDFLAGS} -shared -Wl,-soname,libudev.so.1
--- a/libudev.pc.in
+++ b/libudev.pc.in
@@ -9,5 +9,4 @@ Description: Daemonless replacement for
Version: @VERSION@
URL: https://github.com/illiliti/libudev-zero
Libs: -L${libdir} -ludev
-Libs.private: -pthread
Cflags: -I${includedir}
--- a/udev_enumerate.c
+++ b/udev_enumerate.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <limits.h>
#include <fnmatch.h>
-#include <pthread.h>
#include "udev.h"
#include "udev_list.h"
@@ -38,13 +37,6 @@ struct udev_enumerate {
int refcount;
};
-struct udev_enumerate_thread {
- struct udev_enumerate *udev_enumerate;
- pthread_mutex_t *mutex;
- char path[PATH_MAX];
- pthread_t thread;
-};
-
int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
{
return udev_enumerate ? !!udev_list_entry_add(&udev_enumerate->subsystem_match, subsystem, NULL, 0) - 1 : -1;
@@ -231,31 +223,27 @@ static int filter_sysattr(struct udev_en
return 1;
}
-static void *add_device(void *ptr)
+static void add_device(struct udev_enumerate *udev_enumerate, const char *path)
{
- struct udev_enumerate_thread *thread = ptr;
struct udev_device *udev_device;
- udev_device = udev_device_new_from_syspath(thread->udev_enumerate->udev, thread->path);
+ udev_device = udev_device_new_from_syspath(udev_enumerate->udev, path);
if (!udev_device) {
- return NULL;
+ return;
}
- if (!filter_subsystem(thread->udev_enumerate, udev_device) ||
- !filter_sysname(thread->udev_enumerate, udev_device) ||
- !filter_property(thread->udev_enumerate, udev_device) ||
- !filter_sysattr(thread->udev_enumerate, udev_device)) {
+ if (!filter_subsystem(udev_enumerate, udev_device) ||
+ !filter_sysname(udev_enumerate, udev_device) ||
+ !filter_property(udev_enumerate, udev_device) ||
+ !filter_sysattr(udev_enumerate, udev_device)) {
udev_device_unref(udev_device);
- return NULL;
+ return;
}
- pthread_mutex_lock(thread->mutex);
- udev_list_entry_add(&thread->udev_enumerate->devices, udev_device_get_syspath(udev_device), NULL, 0);
- pthread_mutex_unlock(thread->mutex);
+ udev_list_entry_add(&udev_enumerate->devices, udev_device_get_syspath(udev_device), NULL, 0);
udev_device_unref(udev_device);
- return NULL;
}
static int filter_dot(const struct dirent *de)
@@ -265,9 +253,7 @@ static int filter_dot(const struct diren
static int scan_devices(struct udev_enumerate *udev_enumerate, const char *path)
{
- struct udev_enumerate_thread *thread;
- pthread_mutex_t mutex;
- int i, cnt, ret = 1;
+ int i, cnt;
struct dirent **de;
cnt = scandir(path, &de, filter_dot, NULL);
@@ -276,41 +262,18 @@ static int scan_devices(struct udev_enum
return 0;
}
- thread = calloc(cnt, sizeof(*thread));
-
- if (!thread) {
- ret = 0;
- goto free_de;
- }
-
- pthread_mutex_init(&mutex, NULL);
-
- for (i = 0; i < cnt; i++) {
- thread[i].mutex = &mutex;
- thread[i].udev_enumerate = udev_enumerate;
-
- snprintf(thread[i].path, sizeof(thread[i].path), "%s/%s", path, de[i]->d_name);
-
- if (pthread_create(&thread[i].thread, NULL, add_device, &thread[i]) != 0) {
- ret = 0;
- break;
- }
- }
-
for (i = 0; i < cnt; i++) {
- pthread_join(thread[i].thread, NULL);
+ char device_path[PATH_MAX];
+ snprintf(device_path, sizeof(device_path), "%s/%s", path, de[i]->d_name);
+ add_device(udev_enumerate, device_path);
}
- free(thread);
- pthread_mutex_destroy(&mutex);
-
-free_de:
for (i = 0; i < cnt; i++) {
free(de[i]);
}
free(de);
- return ret;
+ return 1;
}
int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
@@ -1,41 +0,0 @@
From bbeb7ad51c1edb7ab3cf63f30a21e9bb383b7994 Mon Sep 17 00:00:00 2001
From: Matt <smattie@users.noreply.github.com>
Date: Tue, 13 Feb 2024 11:20:52 +0000
Subject: [PATCH] Fixes incorrect detection of touchpads (#66)
Some touchpad drivers (such as applespi) claim to have both EV_ABS and EV_REL
capabilities. These touchpads are then reported as mice by libudev-zero.
---
udev_device.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
--- a/udev_device.c
+++ b/udev_device.c
@@ -458,13 +458,7 @@ static void set_properties_from_evdev(st
udev_list_entry_add(&udev_device->properties, "ID_INPUT_SWITCH", "1", 0);
}
- if (test_bit(ev_bits, EV_REL)) {
- if (test_bit(rel_bits, REL_Y) && test_bit(rel_bits, REL_X) &&
- test_bit(key_bits, BTN_MOUSE)) {
- udev_list_entry_add(&udev_device->properties, "ID_INPUT_MOUSE", "1", 0);
- }
- }
- else if (test_bit(ev_bits, EV_ABS)) {
+ if (test_bit(ev_bits, EV_ABS)) {
if (test_bit(key_bits, BTN_SELECT) || test_bit(key_bits, BTN_TR) ||
test_bit(key_bits, BTN_START) || test_bit(key_bits, BTN_TL)) {
if (test_bit(key_bits, BTN_TOUCH)) {
@@ -494,6 +488,12 @@ static void set_properties_from_evdev(st
}
}
}
+ else if (test_bit(ev_bits, EV_REL)) {
+ if (test_bit(rel_bits, REL_Y) && test_bit(rel_bits, REL_X) &&
+ test_bit(key_bits, BTN_MOUSE)) {
+ udev_list_entry_add(&udev_device->properties, "ID_INPUT_MOUSE", "1", 0);
+ }
+ }
if (!test_bit(ev_bits, EV_KEY)) {
return;
@@ -1,216 +0,0 @@
From 2bebebc9e0444ec53afd7f1f37aa80ff6b95f5f7 Mon Sep 17 00:00:00 2001
From: Alexandru Ardelean <ardeleanalex@gmail.com>
Date: Tue, 19 May 2026 17:52:47 +0300
Subject: [PATCH] udev: implement hwdb USB ID lookup from usb.ids (#80)
Replace the four stub udev_hwdb_*() functions with a working
implementation that looks up vendor and product names from a
usb.ids database file (e.g. provided by the hwdata package).
udev_hwdb_get_properties_list_entry() parses the file for USB
modalias strings of the form "usb:vVVVVpPPPP" (product lookup)
or "usb:vVVVV" (vendor lookup), and populates the entry list with
ID_MODEL_FROM_DATABASE or ID_VENDOR_FROM_DATABASE properties.
Lines are read via POSIX getline() so the buffer grows as needed
on long usb.ids entries.
The path to the usb.ids file is set at build time via the
USB_IDS_PATH Makefile variable, which defaults to
${SHAREDIR}/hwdata/usb.ids.
---
Makefile | 3 ++
udev.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 144 insertions(+), 7 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -3,9 +3,12 @@
PREFIX = /usr/local
LIBDIR = ${PREFIX}/lib
+SHAREDIR = ${PREFIX}/share
INCLUDEDIR = ${PREFIX}/include
PKGCONFIGDIR = ${LIBDIR}/pkgconfig
+USB_IDS_PATH = ${SHAREDIR}/hwdata/usb.ids
XCFLAGS = ${CPPFLAGS} ${CFLAGS} -std=c99 -fPIC -D_XOPEN_SOURCE=700 \
+ -DUSB_IDS_PATH=\"${USB_IDS_PATH}\" \
-Wall -Wextra -Wpedantic -Wmissing-prototypes -Wstrict-prototypes \
-Wno-unused-parameter
XLDFLAGS = ${LDFLAGS} -shared -Wl,-soname,libudev.so.1
--- a/udev.c
+++ b/udev.c
@@ -15,9 +15,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include "udev.h"
+#include "udev_list.h"
struct udev {
int refcount;
@@ -76,22 +80,152 @@ int udev_get_log_priority(struct udev *u
return 0;
}
-/* XXX NOT IMPLEMENTED */ struct udev_hwdb *udev_hwdb_new(struct udev *udev)
+struct udev_hwdb {
+ struct udev_list_entry head;
+ int refcount;
+};
+
+static int usb_ids_lookup_vendor(uint16_t vendorid, char *buf, size_t buflen)
{
- return NULL;
+ char *line = NULL, *name;
+ size_t cap = 0, len;
+ unsigned int id;
+ FILE *f;
+
+ f = fopen(USB_IDS_PATH, "r");
+ if (!f) {
+ return 0;
+ }
+ while (getline(&line, &cap, f) != -1) {
+ if (line[0] == '#' || line[0] == '\t' || line[0] == '\n') {
+ continue;
+ }
+ if (sscanf(line, "%04x", &id) != 1 || id != vendorid) {
+ continue;
+ }
+ name = strchr(line, ' ');
+ if (name) {
+ while (*name == ' ') {
+ name++;
+ }
+ len = strlen(name);
+ while (len > 0 && (name[len - 1] == '\n' || name[len - 1] == '\r')) {
+ name[--len] = '\0';
+ }
+ snprintf(buf, buflen, "%s", name);
+ }
+ break;
+ }
+ free(line);
+ fclose(f);
+ return buf[0] != '\0';
+}
+
+static int usb_ids_lookup_product(uint16_t vendorid, uint16_t productid, char *buf, size_t buflen)
+{
+ char *line = NULL, *name;
+ size_t cap = 0, len;
+ int in_vendor = 0;
+ unsigned int id;
+ FILE *f;
+
+ f = fopen(USB_IDS_PATH, "r");
+ if (!f) {
+ return 0;
+ }
+ while (getline(&line, &cap, f) != -1) {
+ if (line[0] == '#' || line[0] == '\n') {
+ continue;
+ }
+ if (in_vendor) {
+ if (line[0] != '\t') {
+ break;
+ }
+ if (line[1] == '\t') {
+ continue;
+ }
+ if (sscanf(line + 1, "%04x", &id) != 1 || id != productid) {
+ continue;
+ }
+ name = strchr(line + 1, ' ');
+ if (name) {
+ while (*name == ' ') {
+ name++;
+ }
+ len = strlen(name);
+ while (len > 0 && (name[len - 1] == '\n' || name[len - 1] == '\r')) {
+ name[--len] = '\0';
+ }
+ snprintf(buf, buflen, "%s", name);
+ }
+ break;
+ }
+ if (line[0] == '\t') {
+ continue;
+ }
+ if (sscanf(line, "%04x", &id) != 1 || id != vendorid) {
+ continue;
+ }
+ in_vendor = 1;
+ }
+ free(line);
+ fclose(f);
+ return buf[0] != '\0';
}
-/* XXX NOT IMPLEMENTED */ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb)
+struct udev_hwdb *udev_hwdb_new(struct udev *udev)
{
- return NULL;
+ struct udev_hwdb *hwdb;
+
+ hwdb = calloc(1, sizeof(*hwdb));
+ if (!hwdb) {
+ return NULL;
+ }
+ hwdb->refcount = 1;
+ return hwdb;
}
-/* XXX NOT IMPLEMENTED */ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb)
+struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb)
{
- return NULL;
+ if (!hwdb) {
+ return NULL;
+ }
+ hwdb->refcount++;
+ return hwdb;
}
-/* XXX NOT IMPLEMENTED */ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags)
+struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb)
{
+ if (!hwdb) {
+ return NULL;
+ }
+ if (--hwdb->refcount > 0) {
+ return NULL;
+ }
+ udev_list_entry_free_all(&hwdb->head);
+ free(hwdb);
return NULL;
}
+
+struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags)
+{
+ unsigned int vendorid, productid;
+ char name[64];
+
+ if (!hwdb || !modalias) {
+ return NULL;
+ }
+ udev_list_entry_free_all(&hwdb->head);
+ hwdb->head.next = NULL;
+ name[0] = '\0';
+ if (sscanf(modalias, "usb:v%4xp%4x", &vendorid, &productid) == 2) {
+ if (usb_ids_lookup_product((uint16_t)vendorid, (uint16_t)productid, name, sizeof(name))) {
+ udev_list_entry_add(&hwdb->head, "ID_MODEL_FROM_DATABASE", name, 0);
+ }
+ } else if (sscanf(modalias, "usb:v%4x", &vendorid) == 1) {
+ if (usb_ids_lookup_vendor((uint16_t)vendorid, name, sizeof(name))) {
+ udev_list_entry_add(&hwdb->head, "ID_VENDOR_FROM_DATABASE", name, 0);
+ }
+ }
+ return hwdb->head.next;
+}