VirtualBox

Ignore:
Timestamp:
Nov 9, 2011 6:50:33 PM (13 years ago)
Author:
vboxsync
Message:

Additions/solaris/SharedFolders: Fix for incorrect stat association with dirents while reading large directories.

Fix nasty bug when reading large directories. The dirent's and stats were
located in two separate, parallel buffers; but when calling readdir with
a non-zero offset we were skipping through only the dirent's, thereby ending
up associating the wrong stats with these dirents.

This fix merges the two buffers into one structure, thereby both eliminating
the possibility of this bug and also simplifying the code.

Also included is proper validation of the offset that is passed in to
readdir.

Plus other minor fixes.

Location:
trunk/src/VBox/Additions/solaris/SharedFolders
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c

    r39249 r39258  
    864864        sfp_mount_t *mnt,
    865865        char *path,
    866         sffs_dirents_t **dirents,
    867         sffs_stats_t **stats)
     866        sffs_dirents_t **dirents)
    868867{
    869868        int error;
     
    880879        off_t offset;
    881880        sffs_dirents_t *cur_buf;
    882         sffs_stats_t *cur_stats;
    883         struct dirent64 *dirent;
     881        struct sffs_dirent *dirent;
    884882        sffs_stat_t *stat;
    885883        unsigned short reclen;
     884        unsigned short entlen;
    886885
    887886        *dirents = NULL;
    888         *stats = NULL;
    889887
    890888        error = sfprov_open(mnt, path, &fp);
     
    893891
    894892        /*
    895          * Allocate the first dirents and stats buffers.
     893         * Allocate the first dirents buffers.
    896894         */
    897895        *dirents = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
     
    903901        cur_buf->sf_next = NULL;
    904902        cur_buf->sf_len = 0;
    905 
    906         *stats = kmem_alloc(sizeof(**stats), KM_SLEEP);
    907         if (*stats == NULL) {
    908                 error = (ENOSPC);
    909                 goto done;
    910         }
    911         cur_stats = *stats;
    912         cur_stats->sf_next = NULL;
    913         cur_stats->sf_num = 0;
    914903
    915904        /*
     
    964953                        /* expand buffers if we need more space */
    965954                        reclen = DIRENT64_RECLEN(strlen(info->name.String.utf8));
    966                         if (SFFS_DIRENTS_OFF + cur_buf->sf_len + reclen > SFFS_DIRENTS_SIZE) {
     955                        entlen = sizeof(sffs_stat_t) + reclen;
     956                        if (SFFS_DIRENTS_OFF + cur_buf->sf_len + entlen > SFFS_DIRENTS_SIZE) {
    967957                                cur_buf->sf_next = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
    968958                                if (cur_buf->sf_next == NULL) {
     
    975965                        }
    976966
    977                         if (cur_stats->sf_num >= SFFS_STATS_LEN) {
    978                                 cur_stats->sf_next = kmem_alloc(sizeof(**stats), KM_SLEEP);
    979                                 if (cur_stats->sf_next == NULL) {
    980                                         error = (ENOSPC);
    981                                         goto done;
    982                                 }
    983                                 cur_stats = cur_stats->sf_next;
    984                                 cur_stats->sf_next = NULL;
    985                                 cur_stats->sf_num = 0;
    986                         }
    987 
    988967                        /* create the dirent with the name, offset, and len */
    989                         dirent = (dirent64_t *)
     968                        dirent = (struct sffs_dirent *)
    990969                            (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len);
    991                         strncpy(&dirent->d_name[0], info->name.String.utf8, DIRENT64_NAMELEN(reclen));
    992                         dirent->d_reclen = reclen;
    993                         offset += reclen;
    994                         dirent->d_off = offset;
    995 
    996                         cur_buf->sf_len += reclen;
     970                        strncpy(&dirent->sf_entry.d_name[0], info->name.String.utf8, DIRENT64_NAMELEN(reclen));
     971                        dirent->sf_entry.d_reclen = reclen;
     972                        offset += entlen;
     973                        dirent->sf_entry.d_off = offset;
    997974
    998975                        /* save the stats */
    999                         stat = &cur_stats->sf_stats[cur_stats->sf_num];
    1000                         ++cur_stats->sf_num;
     976                        stat = &dirent->sf_stat;
    1001977
    1002978                        sfprov_mode_from_fmode(&stat->sf_mode, info->Info.Attr.fMode);
     
    1007983
    1008984                        /* next info */
     985                        cur_buf->sf_len += entlen;
    1009986                        size = offsetof (SHFLDIRINFO, name.String) + info->name.u16Size;
    1010987                        info = (SHFLDIRINFO *) ((uintptr_t) info + size);
     
    10251002                        *dirents = cur_buf;
    10261003                }
    1027                 while (*stats) {
    1028                         cur_stats = (*stats)->sf_next;
    1029                         kmem_free(*stats, sizeof(**stats));
    1030                         *stats = cur_stats;
    1031                 }
    10321004        }
    10331005        if (infobuff != NULL)
  • trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h

    r31691 r39258  
    120120extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
    121121
    122 /*
    123  * Read directory entries.
    124  */
    125 /*
    126  * a singly linked list of buffers, each containing an array of dirent's.
    127  * sf_len is length of the sf_entries array, in bytes.
    128  */
    129 typedef struct sffs_dirents {
    130         struct sffs_dirents     *sf_next;
    131         len_t                   sf_len;
    132         dirent64_t              sf_entries[1];
    133 } sffs_dirents_t;
    134 
    135 #define SFFS_DIRENTS_SIZE       8192
    136 #define SFFS_DIRENTS_OFF        (offsetof(sffs_dirents_t, sf_entries[0]))
    137 #define SFFS_STATS_LEN          100
    138 
    139122typedef struct sffs_stat {
    140123        mode_t          sf_mode;
     
    145128} sffs_stat_t;
    146129
    147 typedef struct sffs_stats {
    148         struct sffs_stats       *sf_next;
    149         len_t                   sf_num;
    150         sffs_stat_t             sf_stats[SFFS_STATS_LEN];
    151 } sffs_stats_t;
     130/*
     131 * Read directory entries.
     132 */
     133/*
     134 * a singly linked list of buffers, each containing an array of stat's+dirent's.
     135 * sf_len is length of the sf_entries array, in bytes.
     136 */
     137typedef struct sffs_dirents {
     138        struct sffs_dirents     *sf_next;
     139        len_t                   sf_len;
     140        struct sffs_dirent {
     141                sffs_stat_t     sf_stat;
     142                dirent64_t      sf_entry;       /* this is variable length */
     143        }                       sf_entries[1];
     144} sffs_dirents_t;
    152145
    153 extern int sfprov_readdir(sfp_mount_t *mnt, char *path, sffs_dirents_t **dirents,
    154     sffs_stats_t **stats);
     146#define SFFS_DIRENTS_SIZE       8192
     147#define SFFS_DIRENTS_OFF        (offsetof(sffs_dirents_t, sf_entries[0]))
     148
     149extern int sfprov_readdir(sfp_mount_t *mnt, char *path,
     150        sffs_dirents_t **dirents);
    155151
    156152#ifdef  __cplusplus
  • trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c

    r39249 r39258  
    171171                node->sf_dir_list = next;
    172172        }
    173 
    174         while (node->sf_dir_stats != NULL) {
    175                 sffs_stats_t *next = node->sf_dir_stats->sf_next;
    176                 kmem_free(node->sf_dir_stats, sizeof(*node->sf_dir_stats));
    177                 node->sf_dir_stats = next;
    178         }
    179173}
    180174
     
    262256                ++parent->sf_children;
    263257        node->sf_dir_list = NULL;
    264         node->sf_dir_stats = NULL;
    265258        if (stat != NULL) {
    266259                node->sf_stat = *stat;
     
    702695        sfnode_t *dir = VN2SFN(vp);
    703696        sfnode_t *node;
    704         struct dirent64 *dirent;
     697        struct sffs_dirent *dirent = NULL;
    705698        sffs_dirents_t *cur_buf;
    706         sffs_stats_t *cur_stats;
    707         int cur_snum;
    708         offset_t offset;
     699        offset_t offset = 0;
     700        offset_t orig_off = uiop->uio_loffset;
    709701        int dummy_eof;
    710702        int error = 0;
     
    734726        if (dir->sf_dir_list == NULL) {
    735727                error = sfprov_readdir(dir->sf_sffs->sf_handle, dir->sf_path,
    736                     &dir->sf_dir_list, &dir->sf_dir_stats);
     728                    &dir->sf_dir_list);
    737729                if (error != 0)
    738730                        goto done;
    739731        }
    740732
     733        /*
     734         * Validate and skip to the desired offset.
     735         */
     736        cur_buf = dir->sf_dir_list;
     737        offset = 0;
     738
     739        while (cur_buf != NULL &&
     740            offset + cur_buf->sf_len <= uiop->uio_loffset) {
     741                offset += cur_buf->sf_len;
     742                cur_buf = cur_buf->sf_next;
     743        }
     744
     745        if (cur_buf == NULL && offset != uiop->uio_loffset) {
     746                error = EINVAL;
     747                goto done;
     748        }
     749        if (cur_buf != NULL && offset != uiop->uio_loffset) {
     750                offset_t off = offset;
     751                int step;
     752                dirent = &cur_buf->sf_entries[0];
     753
     754                while (off < uiop->uio_loffset) {
     755                        if (dirent->sf_entry.d_off == uiop->uio_loffset)
     756                                break;
     757                        step = sizeof(sffs_stat_t) + dirent->sf_entry.d_reclen;
     758                        dirent = (struct sffs_dirent *) (((char *) dirent) + step);
     759                        off += step;
     760                }
     761
     762                if (off >= uiop->uio_loffset) {
     763                        error = EINVAL;
     764                        goto done;
     765                }
     766        }
     767
     768        offset = uiop->uio_loffset - offset;
     769
    741770        /*
    742771         * Lookup each of the names, so that we have ino's, and copy to
    743772         * result buffer.
    744773         */
    745         offset = 0;
    746         cur_buf = dir->sf_dir_list;
    747         cur_stats = dir->sf_dir_stats;
    748         cur_snum = 0;
    749774        while (cur_buf != NULL) {
    750                 if (offset + cur_buf->sf_len <= uiop->uio_loffset) {
    751                         offset += cur_buf->sf_len;
     775                if (offset >= cur_buf->sf_len) {
    752776                        cur_buf = cur_buf->sf_next;
     777                        offset = 0;
    753778                        continue;
    754779                }
    755780
    756                 if (cur_snum >= SFFS_STATS_LEN) {
    757                         cur_stats = cur_stats->sf_next;
    758                         cur_snum = 0;
    759                 }
    760 
    761                 dirent = (dirent64_t *)
    762                     (((char *) &cur_buf->sf_entries[0]) +
    763                      (uiop->uio_loffset - offset));
    764                 if (dirent->d_reclen > uiop->uio_resid)
     781                dirent = (struct sffs_dirent *)
     782                    (((char *) &cur_buf->sf_entries[0]) + offset);
     783                if (dirent->sf_entry.d_reclen > uiop->uio_resid)
    765784                        break;
    766785
    767                 if (strcmp(dirent->d_name, ".") == 0) {
     786                if (strcmp(dirent->sf_entry.d_name, ".") == 0) {
    768787                        node = dir;
    769                 } else if (strcmp(dirent->d_name, "..") == 0) {
     788                } else if (strcmp(dirent->sf_entry.d_name, "..") == 0) {
    770789                        node = dir->sf_parent;
    771790                        if (node == NULL)
    772791                                node = dir;
    773792                } else {
    774                         node = sfnode_lookup(dir, dirent->d_name, VNON,
    775                             &cur_stats->sf_stats[cur_snum],
    776                             sfnode_cur_time_usec(), NULL);
     793                        node = sfnode_lookup(dir, dirent->sf_entry.d_name, VNON,
     794                            &dirent->sf_stat, sfnode_cur_time_usec(), NULL);
    777795                        if (node == NULL)
    778796                                panic("sffs_readdir() lookup failed");
    779797                }
    780                 dirent->d_ino = node->sf_ino;
    781 
    782                 error = uiomove(dirent, dirent->d_reclen, UIO_READ, uiop);
    783                 ++cur_snum;
     798                dirent->sf_entry.d_ino = node->sf_ino;
     799
     800                error = uiomove(&dirent->sf_entry, dirent->sf_entry.d_reclen, UIO_READ, uiop);
    784801                if (error != 0)
    785802                        break;
     803
     804                uiop->uio_loffset= dirent->sf_entry.d_off;
     805                offset += sizeof(sffs_stat_t) + dirent->sf_entry.d_reclen;
    786806        }
    787807        if (error == 0 && cur_buf == NULL)
     
    789809done:
    790810        mutex_exit(&sffs_lock);
     811        if (error != 0)
     812                uiop->uio_loffset = orig_off;
    791813        return (error);
    792814}
  • trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h

    r38901 r39258  
    6060        uint64_t        sf_stat_time;   /* last-modified time of sf_stat */
    6161        sffs_dirents_t  *sf_dir_list;   /* list of entries for this directory */
    62         sffs_stats_t    *sf_dir_stats;  /* file attrs for the above entries */
    6362} sfnode_t;
    6463
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette