Skip to content

Commit a8046a2

Browse files
tweksteendkopecek
authored andcommitted
Fix handling of add uevents during scanning
Ensure that the enumeration is completed before processing any uevent. This is to avoid a race where the kernel is still enumerating the devices and send the uevent while the parent is being authorised. To not lose these uevents, we store them in a backlog that is processed at the end of the scanning.
1 parent 8bace7a commit a8046a2

File tree

2 files changed

+33
-35
lines changed

2 files changed

+33
-35
lines changed

src/Library/UEventDeviceManager.cpp

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,25 @@ namespace usbguard
340340
if (enumeration_count < 0) {
341341
throw Exception("UEventDeviceManager", "present devices", "failed to enumerate");
342342
}
343+
344+
// We keep track of the uevents received during the scanning and process
345+
// them ad-hoc at the end. This is to avoid any inconsistent state while
346+
// enumerating the devices.
347+
_enumeration = false;
348+
processBacklog();
349+
}
350+
351+
void UEventDeviceManager::processBacklog()
352+
{
353+
USBGUARD_LOG(Debug) << "Processing backlog: _backlog.size() = " << _backlog.size();
354+
try {
355+
for (auto & it : _backlog) {
356+
ueventProcessUEvent(std::move(it));
357+
}
358+
}
359+
catch (...) {
360+
USBGUARD_LOG(Warning) << "ueventProcessBacklog: error processing uevent data";
361+
}
343362
}
344363

345364
void UEventDeviceManager::scan(const std::string& devpath)
@@ -565,16 +584,16 @@ namespace usbguard
565584
* Try to parse uevent from the buffer and process it.
566585
*/
567586
try {
568-
const UEvent uevent = UEvent::fromString(buffer, /*attributes_only=*/false, /*trace=*/false);
569-
ueventProcessUEvent(uevent);
587+
UEvent uevent = UEvent::fromString(buffer, /*attributes_only=*/false, /*trace=*/false);
588+
ueventProcessUEvent(std::move(uevent));
570589
}
571590
catch (...) {
572591
USBGUARD_LOG(Warning) << "ueventProcessRead: received invalid uevent data";
573592
USBGUARD_LOG(Debug) << "ueventProcessRead: uevent_data=" << base64Encode(buffer);
574593
}
575594
}
576595

577-
void UEventDeviceManager::ueventProcessUEvent(const UEvent& uevent)
596+
void UEventDeviceManager::ueventProcessUEvent(UEvent uevent)
578597
{
579598
const std::string subsystem = uevent.getAttribute("SUBSYSTEM");
580599
const std::string devtype = uevent.getAttribute("DEVTYPE");
@@ -594,20 +613,23 @@ namespace usbguard
594613
}
595614

596615
const std::string sysfs_devpath = uevent.getAttribute("DEVPATH");
597-
ueventProcessAction(action, sysfs_devpath);
616+
617+
if (_enumeration) {
618+
_backlog.emplace_back(std::move(uevent));
619+
}
620+
else {
621+
ueventProcessAction(action, sysfs_devpath);
622+
}
598623
}
599624

600625
void UEventDeviceManager::ueventProcessAction(const std::string& action, const std::string& sysfs_devpath)
601626
{
602-
bool enumeration_notify = false;
603627

604628
try {
605-
std::unique_lock<std::mutex> lock(_enumeration_mutex);
606629
uint32_t id = 0;
607630
const bool known_path = knownSysfsPath(sysfs_devpath, &id);
608631

609632
if (action == "add" || action == "change") {
610-
lock.unlock();
611633

612634
if (known_path && id > 0) {
613635
processDevicePresence(id);
@@ -637,19 +659,10 @@ namespace usbguard
637659
USBGUARD_LOG(Debug) << "Enumeration notify: sysfs_devpath=" << sysfs_devpath
638660
<< " _enumeration=" << _enumeration
639661
<< " known_path=" << known_path;
640-
641-
if (known_path) {
642-
enumeration_notify = true;
643-
}
644662
}
645663
}
646664
else if (action == "remove") {
647-
lock.unlock();
648665
processDeviceRemoval(sysfs_devpath);
649-
650-
if (known_path) {
651-
enumeration_notify = true;
652-
}
653666
}
654667
else if (action == "bind" || action == "unbind") {
655668
USBGUARD_LOG(Debug) << action << "=" << sysfs_devpath;
@@ -669,10 +682,6 @@ namespace usbguard
669682
DeviceException("unknown exception");
670683
}
671684

672-
if (_enumeration && enumeration_notify) {
673-
_enumeration_complete.notify_one();
674-
USBGUARD_LOG(Debug) << "Notified enumeration routine after sysfs_path=" << sysfs_devpath;
675-
}
676685
}
677686

678687
bool UEventDeviceManager::ueventEnumerateComparePath(const std::pair<std::string, std::string>& a,
@@ -788,19 +797,8 @@ namespace usbguard
788797
SysFSDevice device(sysfs_relative_path);
789798

790799
if (device.getUEvent().getAttribute("DEVTYPE") == "usb_device") {
791-
std::unique_lock<std::mutex> lock(_enumeration_mutex);
792800
learnSysfsPath(sysfs_relative_path);
793-
device.setAttribute("uevent", "add");
794-
795-
if (!_enumeration_complete.wait_for(lock, std::chrono::seconds(2),
796-
[this, sysfs_relative_path]() {
797-
uint32_t id = 0;
798-
const bool known = knownSysfsPath(sysfs_relative_path, &id);
799-
USBGUARD_LOG(Debug) << "cv: known=" << known << " id=" << id;
800-
return id != 0;
801-
})) {
802-
throw Exception("UEventDeviceManager", sysfs_absolute_path, "enumeration timeout");
803-
}
801+
ueventProcessAction("add", sysfs_relative_path);
804802
return 1;
805803
}
806804
else {

src/Library/UEventDeviceManager.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ namespace usbguard
9494

9595
int ueventOpen();
9696
void ueventProcessRead();
97-
void ueventProcessUEvent(const UEvent& uevent);
97+
void ueventProcessUEvent(UEvent uevent);
9898
void ueventProcessAction(const std::string& action, const std::string& sysfs_devpath);
9999
int ueventEnumerateDevices();
100100
int ueventEnumerateTriggerDevice(const std::string& devpath, const std::string& buspath);
@@ -103,10 +103,12 @@ namespace usbguard
103103
void processDeviceInsertion(SysFSDevice& sysfs_device, bool signal_present);
104104
void processDevicePresence(uint32_t id);
105105
void processDeviceRemoval(const std::string& sysfs_devpath);
106+
void processBacklog();
106107

107108
Thread<UEventDeviceManager> _thread;
108109
int _uevent_fd;
109110
int _wakeup_fd;
111+
std::vector<UEvent> _backlog;
110112

111113
bool isPresentSysfsPath(const std::string& sysfs_path) const;
112114
bool knownSysfsPath(const std::string& sysfs_path, uint32_t* id = nullptr) const;
@@ -117,8 +119,6 @@ namespace usbguard
117119

118120
bool _enumeration_only_mode;
119121
std::atomic<bool> _enumeration;
120-
std::condition_variable _enumeration_complete;
121-
std::mutex _enumeration_mutex;
122122
};
123123
} /* namespace usbguard */
124124
#endif /* HAVE_UEVENT */

0 commit comments

Comments
 (0)