|
@@ -17,13 +17,17 @@ struct readdir_handle_s {
|
|
/*
|
|
/*
|
|
* decode routine needed by kmod to make sense of the shared page for readdirs.
|
|
* decode routine needed by kmod to make sense of the shared page for readdirs.
|
|
*/
|
|
*/
|
|
-static long decode_dirents(char *ptr, struct pvfs2_readdir_response_s *readdir)
|
|
|
|
|
|
+static long decode_dirents(char *ptr, size_t size,
|
|
|
|
+ struct pvfs2_readdir_response_s *readdir)
|
|
{
|
|
{
|
|
int i;
|
|
int i;
|
|
struct pvfs2_readdir_response_s *rd =
|
|
struct pvfs2_readdir_response_s *rd =
|
|
(struct pvfs2_readdir_response_s *) ptr;
|
|
(struct pvfs2_readdir_response_s *) ptr;
|
|
char *buf = ptr;
|
|
char *buf = ptr;
|
|
|
|
|
|
|
|
+ if (size < offsetof(struct pvfs2_readdir_response_s, dirent_array))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
readdir->token = rd->token;
|
|
readdir->token = rd->token;
|
|
readdir->pvfs_dirent_outcount = rd->pvfs_dirent_outcount;
|
|
readdir->pvfs_dirent_outcount = rd->pvfs_dirent_outcount;
|
|
readdir->dirent_array = kcalloc(readdir->pvfs_dirent_outcount,
|
|
readdir->dirent_array = kcalloc(readdir->pvfs_dirent_outcount,
|
|
@@ -31,21 +35,43 @@ static long decode_dirents(char *ptr, struct pvfs2_readdir_response_s *readdir)
|
|
GFP_KERNEL);
|
|
GFP_KERNEL);
|
|
if (readdir->dirent_array == NULL)
|
|
if (readdir->dirent_array == NULL)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
+
|
|
buf += offsetof(struct pvfs2_readdir_response_s, dirent_array);
|
|
buf += offsetof(struct pvfs2_readdir_response_s, dirent_array);
|
|
|
|
+ size -= offsetof(struct pvfs2_readdir_response_s, dirent_array);
|
|
|
|
+
|
|
for (i = 0; i < readdir->pvfs_dirent_outcount; i++) {
|
|
for (i = 0; i < readdir->pvfs_dirent_outcount; i++) {
|
|
- __u32 len = *(__u32 *)buf;
|
|
|
|
|
|
+ __u32 len;
|
|
|
|
+
|
|
|
|
+ if (size < 4)
|
|
|
|
+ goto Einval;
|
|
|
|
+
|
|
|
|
+ len = *(__u32 *)buf;
|
|
|
|
+ if (len >= (unsigned)-24)
|
|
|
|
+ goto Einval;
|
|
|
|
+
|
|
readdir->dirent_array[i].d_name = buf + 4;
|
|
readdir->dirent_array[i].d_name = buf + 4;
|
|
- buf += roundup8(4 + len + 1);
|
|
|
|
readdir->dirent_array[i].d_length = len;
|
|
readdir->dirent_array[i].d_length = len;
|
|
|
|
+
|
|
|
|
+ len = roundup8(4 + len + 1);
|
|
|
|
+ if (size < len + 16)
|
|
|
|
+ goto Einval;
|
|
|
|
+ size -= len + 16;
|
|
|
|
+
|
|
|
|
+ buf += len;
|
|
|
|
+
|
|
readdir->dirent_array[i].khandle =
|
|
readdir->dirent_array[i].khandle =
|
|
*(struct pvfs2_khandle *) buf;
|
|
*(struct pvfs2_khandle *) buf;
|
|
buf += 16;
|
|
buf += 16;
|
|
}
|
|
}
|
|
return buf - ptr;
|
|
return buf - ptr;
|
|
|
|
+Einval:
|
|
|
|
+ kfree(readdir->dirent_array);
|
|
|
|
+ readdir->dirent_array = NULL;
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
|
|
static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
|
|
- int buffer_index)
|
|
|
|
|
|
+ size_t size, int buffer_index)
|
|
{
|
|
{
|
|
long ret;
|
|
long ret;
|
|
|
|
|
|
@@ -61,7 +87,7 @@ static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
|
|
}
|
|
}
|
|
rhandle->buffer_index = buffer_index;
|
|
rhandle->buffer_index = buffer_index;
|
|
rhandle->dents_buf = buf;
|
|
rhandle->dents_buf = buf;
|
|
- ret = decode_dirents(buf, &rhandle->readdir_response);
|
|
|
|
|
|
+ ret = decode_dirents(buf, size, &rhandle->readdir_response);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
gossip_err("Could not decode readdir from buffer %ld\n", ret);
|
|
gossip_err("Could not decode readdir from buffer %ld\n", ret);
|
|
rhandle->buffer_index = -1;
|
|
rhandle->buffer_index = -1;
|
|
@@ -209,6 +235,7 @@ get_new_buffer_index:
|
|
bytes_decoded =
|
|
bytes_decoded =
|
|
readdir_handle_ctor(&rhandle,
|
|
readdir_handle_ctor(&rhandle,
|
|
new_op->downcall.trailer_buf,
|
|
new_op->downcall.trailer_buf,
|
|
|
|
+ new_op->downcall.trailer_size,
|
|
buffer_index);
|
|
buffer_index);
|
|
if (bytes_decoded < 0) {
|
|
if (bytes_decoded < 0) {
|
|
gossip_err("pvfs2_readdir: Could not decode trailer buffer into a readdir response %d\n",
|
|
gossip_err("pvfs2_readdir: Could not decode trailer buffer into a readdir response %d\n",
|