[close] Attachments you submit will be routed for moderation. If you have an account, please log in first.

Ticket #70: 0001-Linux-Fix-70-race-condition-in-sysfs_get_device_list.patch

File 0001-Linux-Fix-70-race-condition-in-sysfs_get_device_list.patch, 8.4 KB (added by stuge, 2 years ago)

Alan's latest patch against libusb-stuge with fix for opendir() bug

  • libusb/os/linux_usbfs.c

    From c64e9f36b39c5b692ba48ce328dfd912d67eb2c1 Mon Sep 17 00:00:00 2001
    From: Alan Ott <alan@signal11.us>
    Date: Wed, 5 Jan 2011 00:37:28 -0500
    Subject: [PATCH] Linux: Fix #70 race condition in sysfs_get_device_list()
    
    Changed the way libusb chooses between using sysfs and usbfs for information
    about the attached devies.  Using the old method, a race condition could
    occur if a device was unplugged just before (or during) the call to
    libusb_get_device_list(), corrupting the internal sysfs_can_relate_devices
    and sysfs_has_descriptors variables, and preventing libusb_get_device_list()
    from working in future calls.
    
    The old method was based on the assumption that if certain sysfs files (eg:
    busnum) were not able to be opened, that it indicated an inadequacy of sysfs
    (ie: the running kernel's sysfs version did not contain those files), when
    in reality, those files couldn't be opened because the device had been
    unplugged.
    
    The new method checks the adequacy of sysfs during libusb_init() (op_init())
    and if a sysfs file cannot be opened, it is now assumed that it is because
    the device has been unplugged, not because sysfs is inadequate.
    
    Signed-off-by: Alan Ott <alan@signal11.us>
    [stuge: Include closedir() bugfix posted in ticket by arne]
    ---
     libusb/os/linux_usbfs.c |  126 +++++++++++++++++++++++++++++++++++------------
     1 files changed, 95 insertions(+), 31 deletions(-)
    
    diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
    index 72db57a..e4bdcde 100644
    a b static clockid_t monotonic_clkid = -1; 
    9595 
    9696/* do we have a busnum to relate devices? this also implies that we can read 
    9797 * the active configuration through bConfigurationValue */ 
    98 static int sysfs_can_relate_devices = -1; 
     98static int sysfs_can_relate_devices = 0; 
    9999 
    100100/* do we have a descriptors file? */ 
    101 static int sysfs_has_descriptors = -1; 
     101static int sysfs_has_descriptors = 0; 
    102102 
    103103struct linux_device_priv { 
    104104        char *sysfs_dir; 
    static int check_flag_bulk_continuation(void) 
    242242        return 1; 
    243243} 
    244244 
     245/* Return 1 if filename exists inside dirname in sysfs. 
     246   SYSFS_DEVICE_PATH is assumed to be the beginning of the path. */ 
     247static int sysfs_has_file(const char *dirname, const char *filename) 
     248{ 
     249        struct stat statbuf; 
     250        char path[PATH_MAX]; 
     251        int r; 
     252 
     253        snprintf(path, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, dirname, filename); 
     254        r = stat(path, &statbuf); 
     255        if (r == 0 && S_ISREG(statbuf.st_mode)) 
     256                return 1; 
     257 
     258        return 0; 
     259} 
     260 
    245261static int op_init(struct libusb_context *ctx) 
    246262{ 
    247263        struct stat statbuf; 
    static int op_init(struct libusb_context *ctx) 
    269285 
    270286        r = stat(SYSFS_DEVICE_PATH, &statbuf); 
    271287        if (r == 0 && S_ISDIR(statbuf.st_mode)) { 
     288                DIR *devices = opendir(SYSFS_DEVICE_PATH); 
     289                struct dirent *entry; 
     290 
    272291                usbi_dbg("found usb devices in sysfs"); 
     292 
     293                if (!devices) { 
     294                        usbi_err(ctx, "opendir devices failed errno=%d", errno); 
     295                        return LIBUSB_ERROR_IO; 
     296                } 
     297 
     298                /* Make sure sysfs supports all the required files. If it 
     299                 * does not, then usbfs will be used instead.  Determine 
     300                 * this by looping through the directories in 
     301                 * SYSFS_DEVICE_PATH.  With the assumption that there will 
     302                 * always be subdirectories of the name usbN (usb1, usb2, 
     303                 * etc) representing the root hubs, check the usbN 
     304                 * subdirectories to see if they have all the needed files. 
     305                 * This algorithm uses the usbN subdirectories (root hubs) 
     306                 * because a device disconnection will cause a race 
     307                 * condition regarding which files are available, sometimes 
     308                 * causing an incorrect result.  The root hubs are used 
     309                 * because it is assumed that they will always be present. 
     310                 * See the "sysfs vs usbfs" comment at the top of this file 
     311                 * for more details.  */ 
     312                while ((entry = readdir(devices))) { 
     313                        int has_busnum=0, has_devnum=0, has_descriptors=0; 
     314                        int has_configuration_value=0; 
     315 
     316                        /* Only check the usbN directories. */ 
     317                        if (strncmp(entry->d_name, "usb", 3) != 0) 
     318                                continue; 
     319 
     320                        /* Check for the files libusb needs from sysfs. */ 
     321                        has_busnum = sysfs_has_file(entry->d_name, "busnum"); 
     322                        has_devnum = sysfs_has_file(entry->d_name, "devnum"); 
     323                        has_descriptors = sysfs_has_file(entry->d_name, "descriptors"); 
     324                        has_configuration_value = sysfs_has_file(entry->d_name, "bConfigurationValue"); 
     325 
     326                        if (has_busnum && has_devnum && has_configuration_value) 
     327                                sysfs_can_relate_devices = 1; 
     328                        if (has_descriptors) 
     329                                sysfs_has_descriptors = 1; 
     330 
     331                        /* Only need to check until we've found ONE device which 
     332                           has all the attributes. */ 
     333                        if (sysfs_has_descriptors && sysfs_can_relate_devices) 
     334                                break; 
     335                } 
     336                closedir(devices); 
     337 
     338                /* Only use sysfs descriptors if the rest of 
     339                   sysfs will work for libusb. */ 
     340                if (!sysfs_can_relate_devices) 
     341                        sysfs_has_descriptors = 0; 
    273342        } else { 
    274343                usbi_dbg("sysfs usb info not available"); 
    275344                sysfs_has_descriptors = 0; 
    out: 
    930999} 
    9311000 
    9321001static int sysfs_scan_device(struct libusb_context *ctx, 
    933         struct discovered_devs **_discdevs, const char *devname, 
    934         int *usbfs_fallback) 
     1002        struct discovered_devs **_discdevs, const char *devname) 
    9351003{ 
    9361004        int r; 
    9371005        FILE *fd; 
    static int sysfs_scan_device(struct libusb_context *ctx, 
    9621030        fd = fopen(filename, "r"); 
    9631031        if (!fd) { 
    9641032                if (errno == ENOENT) { 
    965                         usbi_dbg("busnum not found, cannot relate sysfs to usbfs, " 
    966                                 "falling back on pure usbfs"); 
    967                         sysfs_can_relate_devices = 0; 
    968                         *usbfs_fallback = 1; 
    969                         return LIBUSB_ERROR_OTHER; 
     1033                        /* busnum doesn't exist. Assume the device has been 
     1034                           disconnected (unplugged). */ 
     1035                        return LIBUSB_ERROR_NO_DEVICE; 
    9701036                } 
    9711037                usbi_err(ctx, "open busnum failed, errno=%d", errno); 
    9721038                return LIBUSB_ERROR_IO; 
    9731039        } 
    9741040 
    975         sysfs_can_relate_devices = 1; 
    976  
    9771041        r = fscanf(fd, "%d", &busnum); 
    9781042        fclose(fd); 
    9791043        if (r != 1) { 
    9801044                usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno); 
    981                 return LIBUSB_ERROR_IO; 
     1045                return LIBUSB_ERROR_NO_DEVICE; 
    9821046        } 
    9831047 
    9841048        snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname); 
    9851049        fd = fopen(filename, "r"); 
    9861050        if (!fd) { 
     1051                if (errno == ENOENT) { 
     1052                        /* devnum doesn't exist. Assume the device has been 
     1053                           disconnected (unplugged). */ 
     1054                        return LIBUSB_ERROR_NO_DEVICE; 
     1055                } 
    9871056                usbi_err(ctx, "open devnum failed, errno=%d", errno); 
    9881057                return LIBUSB_ERROR_IO; 
    9891058        } 
    static int sysfs_scan_device(struct libusb_context *ctx, 
    9921061        fclose(fd); 
    9931062        if (r != 1) { 
    9941063                usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno); 
    995                 return LIBUSB_ERROR_IO; 
     1064                return LIBUSB_ERROR_NO_DEVICE; 
    9961065        } 
    9971066 
    9981067        usbi_dbg("bus=%d dev=%d", busnum, devaddr); 
    static int sysfs_scan_device(struct libusb_context *ctx, 
    10041073} 
    10051074 
    10061075static int sysfs_get_device_list(struct libusb_context *ctx, 
    1007         struct discovered_devs **_discdevs, int *usbfs_fallback) 
     1076        struct discovered_devs **_discdevs) 
    10081077{ 
    10091078        struct discovered_devs *discdevs = *_discdevs; 
    10101079        DIR *devices = opendir(SYSFS_DEVICE_PATH); 
    static int sysfs_get_device_list(struct libusb_context *ctx, 
    10231092                                || strchr(entry->d_name, ':')) 
    10241093                        continue; 
    10251094 
    1026                 r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name, 
    1027                         usbfs_fallback); 
    1028                 if (r < 0) 
     1095                r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name); 
     1096                if (r < 0 && r != LIBUSB_ERROR_NO_DEVICE) 
    10291097                        goto out; 
    10301098                discdevs = discdevs_new; 
    1031         }        
    1032  
     1099        } 
     1100        r = 0; 
    10331101out: 
    10341102        closedir(devices); 
    10351103        *_discdevs = discdevs; 
    static int op_get_device_list(struct libusb_context *ctx, 
    10441112         * any autosuspended USB devices. however, sysfs is not available 
    10451113         * everywhere, so we need a usbfs fallback too. 
    10461114         * 
    1047          * as described in the "sysfs vs usbfs" comment, sometimes we have 
    1048          * sysfs but not enough information to relate sysfs devices to usbfs 
    1049          * nodes. the usbfs_fallback variable is used to indicate that we should 
    1050          * fall back on usbfs. 
     1115         * as described in the "sysfs vs usbfs" comment at the top of this 
     1116         * file, sometimes we have sysfs but not enough information to 
     1117         * relate sysfs devices to usbfs nodes.  op_init() determines the 
     1118         * adequacy of sysfs and sets sysfs_can_relate_devices. 
    10511119         */ 
    1052         if (sysfs_can_relate_devices != 0) { 
    1053                 int usbfs_fallback = 0; 
    1054                 int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback); 
    1055                 if (!usbfs_fallback) 
    1056                         return r; 
    1057         } 
    1058  
    1059         return usbfs_get_device_list(ctx, _discdevs); 
     1120        if (sysfs_can_relate_devices != 0) 
     1121                return sysfs_get_device_list(ctx, _discdevs); 
     1122        else 
     1123                return usbfs_get_device_list(ctx, _discdevs); 
    10601124} 
    10611125 
    10621126static int op_open(struct libusb_device_handle *handle)