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

Ticket #70: 0001-Fix-Race-Condition-in-sysfs_get_device_list.patch

File 0001-Fix-Race-Condition-in-sysfs_get_device_list.patch, 8.3 KB (added by stuge, 2 years ago)

Alan's latest patch

  • libusb/os/linux_usbfs.c

    From fe264aa6c76d0e1e7c09d81a3314690545845878 Mon Sep 17 00:00:00 2001
    From: Alan Ott <alan@signal11.us>
    Date: Wed, 5 Jan 2011 00:37:28 -0500
    Subject: [PATCH] Fix 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>
    ---
     libusb/os/linux_usbfs.c |  125 +++++++++++++++++++++++++++++++++++------------
     1 files changed, 94 insertions(+), 31 deletions(-)
    
    diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
    index a44688d..1e98137 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) 
    234234        return sublevel >= 32; 
    235235} 
    236236 
     237/* Return 1 if filename exists inside dirname in sysfs. 
     238   SYSFS_DEVICE_PATH is assumed to be the beginning of the path. */ 
     239static int sysfs_has_file(const char *dirname, const char *filename) 
     240{ 
     241        struct stat statbuf; 
     242        char path[PATH_MAX]; 
     243        int r; 
     244 
     245        snprintf(path, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, dirname, filename); 
     246        r = stat(path, &statbuf); 
     247        if (r == 0 && S_ISREG(statbuf.st_mode)) 
     248                return 1; 
     249 
     250        return 0; 
     251} 
     252 
    237253static int op_init(struct libusb_context *ctx) 
    238254{ 
    239255        struct stat statbuf; 
    static int op_init(struct libusb_context *ctx) 
    261277 
    262278        r = stat(SYSFS_DEVICE_PATH, &statbuf); 
    263279        if (r == 0 && S_ISDIR(statbuf.st_mode)) { 
     280                DIR *devices = opendir(SYSFS_DEVICE_PATH); 
     281                struct dirent *entry; 
     282 
    264283                usbi_dbg("found usb devices in sysfs"); 
     284 
     285                if (!devices) { 
     286                        usbi_err(ctx, "opendir devices failed errno=%d", errno); 
     287                        return LIBUSB_ERROR_IO; 
     288                } 
     289 
     290                /* Make sure sysfs supports all the required files. If it 
     291                 * does not, then usbfs will be used instead.  Determine 
     292                 * this by looping through the directories in 
     293                 * SYSFS_DEVICE_PATH.  With the assumption that there will 
     294                 * always be subdirectories of the name usbN (usb1, usb2, 
     295                 * etc) representing the root hubs, check the usbN 
     296                 * subdirectories to see if they have all the needed files. 
     297                 * This algorithm uses the usbN subdirectories (root hubs) 
     298                 * because a device disconnection will cause a race 
     299                 * condition regarding which files are available, sometimes 
     300                 * causing an incorrect result.  The root hubs are used 
     301                 * because it is assumed that they will always be present. 
     302                 * See the "sysfs vs usbfs" comment at the top of this file 
     303                 * for more details.  */ 
     304                while ((entry = readdir(devices))) { 
     305                        int has_busnum=0, has_devnum=0, has_descriptors=0; 
     306                        int has_configuration_value=0; 
     307 
     308                        /* Only check the usbN directories. */ 
     309                        if (strncmp(entry->d_name, "usb", 3) != 0) 
     310                                continue; 
     311 
     312                        /* Check for the files libusb needs from sysfs. */ 
     313                        has_busnum = sysfs_has_file(entry->d_name, "busnum"); 
     314                        has_devnum = sysfs_has_file(entry->d_name, "devnum"); 
     315                        has_descriptors = sysfs_has_file(entry->d_name, "descriptors"); 
     316                        has_configuration_value = sysfs_has_file(entry->d_name, "bConfigurationValue"); 
     317 
     318                        if (has_busnum && has_devnum && has_configuration_value) 
     319                                sysfs_can_relate_devices = 1; 
     320                        if (has_descriptors) 
     321                                sysfs_has_descriptors = 1; 
     322 
     323                        /* Only need to check until we've found ONE device which 
     324                           has all the attributes. */ 
     325                        if (sysfs_has_descriptors && sysfs_can_relate_devices) 
     326                                break; 
     327                } 
     328 
     329                /* Only use sysfs descriptors if the rest of 
     330                   sysfs will work for libusb. */ 
     331                if (!sysfs_can_relate_devices) 
     332                        sysfs_has_descriptors = 0; 
    265333        } else { 
    266334                usbi_dbg("sysfs usb info not available"); 
    267335                sysfs_has_descriptors = 0; 
    out: 
    922990} 
    923991 
    924992static int sysfs_scan_device(struct libusb_context *ctx, 
    925         struct discovered_devs **_discdevs, const char *devname, 
    926         int *usbfs_fallback) 
     993        struct discovered_devs **_discdevs, const char *devname) 
    927994{ 
    928995        int r; 
    929996        FILE *fd; 
    static int sysfs_scan_device(struct libusb_context *ctx, 
    9541021        fd = fopen(filename, "r"); 
    9551022        if (!fd) { 
    9561023                if (errno == ENOENT) { 
    957                         usbi_dbg("busnum not found, cannot relate sysfs to usbfs, " 
    958                                 "falling back on pure usbfs"); 
    959                         sysfs_can_relate_devices = 0; 
    960                         *usbfs_fallback = 1; 
    961                         return LIBUSB_ERROR_OTHER; 
     1024                        /* busnum doesn't exist. Assume the device has been 
     1025                           disconnected (unplugged). */ 
     1026                        return LIBUSB_ERROR_NO_DEVICE; 
    9621027                } 
    9631028                usbi_err(ctx, "open busnum failed, errno=%d", errno); 
    9641029                return LIBUSB_ERROR_IO; 
    9651030        } 
    9661031 
    967         sysfs_can_relate_devices = 1; 
    968  
    9691032        r = fscanf(fd, "%d", &busnum); 
    9701033        fclose(fd); 
    9711034        if (r != 1) { 
    9721035                usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno); 
    973                 return LIBUSB_ERROR_IO; 
     1036                return LIBUSB_ERROR_NO_DEVICE; 
    9741037        } 
    9751038 
    9761039        snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname); 
    9771040        fd = fopen(filename, "r"); 
    9781041        if (!fd) { 
     1042                if (errno == ENOENT) { 
     1043                        /* devnum doesn't exist. Assume the device has been 
     1044                           disconnected (unplugged). */ 
     1045                        return LIBUSB_ERROR_NO_DEVICE; 
     1046                } 
    9791047                usbi_err(ctx, "open devnum failed, errno=%d", errno); 
    9801048                return LIBUSB_ERROR_IO; 
    9811049        } 
    static int sysfs_scan_device(struct libusb_context *ctx, 
    9841052        fclose(fd); 
    9851053        if (r != 1) { 
    9861054                usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno); 
    987                 return LIBUSB_ERROR_IO; 
     1055                return LIBUSB_ERROR_NO_DEVICE; 
    9881056        } 
    9891057 
    9901058        usbi_dbg("bus=%d dev=%d", busnum, devaddr); 
    static int sysfs_scan_device(struct libusb_context *ctx, 
    9961064} 
    9971065 
    9981066static int sysfs_get_device_list(struct libusb_context *ctx, 
    999         struct discovered_devs **_discdevs, int *usbfs_fallback) 
     1067        struct discovered_devs **_discdevs) 
    10001068{ 
    10011069        struct discovered_devs *discdevs = *_discdevs; 
    10021070        DIR *devices = opendir(SYSFS_DEVICE_PATH); 
    static int sysfs_get_device_list(struct libusb_context *ctx, 
    10151083                                || strchr(entry->d_name, ':')) 
    10161084                        continue; 
    10171085 
    1018                 r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name, 
    1019                         usbfs_fallback); 
    1020                 if (r < 0) 
     1086                r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name); 
     1087                if (r < 0 && r != LIBUSB_ERROR_NO_DEVICE) 
    10211088                        goto out; 
    10221089                discdevs = discdevs_new; 
    1023         }        
    1024  
     1090        } 
     1091        r = 0; 
    10251092out: 
    10261093        closedir(devices); 
    10271094        *_discdevs = discdevs; 
    static int op_get_device_list(struct libusb_context *ctx, 
    10361103         * any autosuspended USB devices. however, sysfs is not available 
    10371104         * everywhere, so we need a usbfs fallback too. 
    10381105         * 
    1039          * as described in the "sysfs vs usbfs" comment, sometimes we have 
    1040          * sysfs but not enough information to relate sysfs devices to usbfs 
    1041          * nodes. the usbfs_fallback variable is used to indicate that we should 
    1042          * fall back on usbfs. 
     1106         * as described in the "sysfs vs usbfs" comment at the top of this 
     1107         * file, sometimes we have sysfs but not enough information to 
     1108         * relate sysfs devices to usbfs nodes.  op_init() determines the 
     1109         * adequacy of sysfs and sets sysfs_can_relate_devices. 
    10431110         */ 
    1044         if (sysfs_can_relate_devices != 0) { 
    1045                 int usbfs_fallback = 0; 
    1046                 int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback); 
    1047                 if (!usbfs_fallback) 
    1048                         return r; 
    1049         } 
    1050  
    1051         return usbfs_get_device_list(ctx, _discdevs); 
     1111        if (sysfs_can_relate_devices != 0) 
     1112                return sysfs_get_device_list(ctx, _discdevs); 
     1113        else 
     1114                return usbfs_get_device_list(ctx, _discdevs); 
    10521115} 
    10531116 
    10541117static int op_open(struct libusb_device_handle *handle)