|
@@ -1434,7 +1434,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
|
|
if (ffs->epfiles)
|
|
if (ffs->epfiles)
|
|
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
|
|
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
|
|
|
|
|
|
- kfree(ffs->raw_descs);
|
|
|
|
|
|
+ kfree(ffs->raw_descs_data);
|
|
kfree(ffs->raw_strings);
|
|
kfree(ffs->raw_strings);
|
|
kfree(ffs->stringtabs);
|
|
kfree(ffs->stringtabs);
|
|
}
|
|
}
|
|
@@ -1446,12 +1446,12 @@ static void ffs_data_reset(struct ffs_data *ffs)
|
|
ffs_data_clear(ffs);
|
|
ffs_data_clear(ffs);
|
|
|
|
|
|
ffs->epfiles = NULL;
|
|
ffs->epfiles = NULL;
|
|
|
|
+ ffs->raw_descs_data = NULL;
|
|
ffs->raw_descs = NULL;
|
|
ffs->raw_descs = NULL;
|
|
ffs->raw_strings = NULL;
|
|
ffs->raw_strings = NULL;
|
|
ffs->stringtabs = NULL;
|
|
ffs->stringtabs = NULL;
|
|
|
|
|
|
- ffs->raw_fs_hs_descs_length = 0;
|
|
|
|
- ffs->raw_ss_descs_length = 0;
|
|
|
|
|
|
+ ffs->raw_descs_length = 0;
|
|
ffs->fs_descs_count = 0;
|
|
ffs->fs_descs_count = 0;
|
|
ffs->hs_descs_count = 0;
|
|
ffs->hs_descs_count = 0;
|
|
ffs->ss_descs_count = 0;
|
|
ffs->ss_descs_count = 0;
|
|
@@ -1865,89 +1865,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|
static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|
static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|
char *const _data, size_t len)
|
|
char *const _data, size_t len)
|
|
{
|
|
{
|
|
- unsigned fs_count, hs_count, ss_count = 0;
|
|
|
|
- int fs_len, hs_len, ss_len, ret = -EINVAL;
|
|
|
|
- char *data = _data;
|
|
|
|
|
|
+ char *data = _data, *raw_descs;
|
|
|
|
+ unsigned counts[3], flags;
|
|
|
|
+ int ret = -EINVAL, i;
|
|
|
|
|
|
ENTER();
|
|
ENTER();
|
|
|
|
|
|
- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
|
|
|
|
- get_unaligned_le32(data + 4) != len))
|
|
|
|
|
|
+ if (get_unaligned_le32(data + 4) != len)
|
|
goto error;
|
|
goto error;
|
|
- fs_count = get_unaligned_le32(data + 8);
|
|
|
|
- hs_count = get_unaligned_le32(data + 12);
|
|
|
|
-
|
|
|
|
- data += 16;
|
|
|
|
- len -= 16;
|
|
|
|
|
|
|
|
- if (likely(fs_count)) {
|
|
|
|
- fs_len = ffs_do_descs(fs_count, data, len,
|
|
|
|
- __ffs_data_do_entity, ffs);
|
|
|
|
- if (unlikely(fs_len < 0)) {
|
|
|
|
- ret = fs_len;
|
|
|
|
|
|
+ switch (get_unaligned_le32(data)) {
|
|
|
|
+ case FUNCTIONFS_DESCRIPTORS_MAGIC:
|
|
|
|
+ flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
|
|
|
|
+ data += 8;
|
|
|
|
+ len -= 8;
|
|
|
|
+ break;
|
|
|
|
+ case FUNCTIONFS_DESCRIPTORS_MAGIC_V2:
|
|
|
|
+ flags = get_unaligned_le32(data + 8);
|
|
|
|
+ if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
|
|
|
|
+ FUNCTIONFS_HAS_HS_DESC |
|
|
|
|
+ FUNCTIONFS_HAS_SS_DESC)) {
|
|
|
|
+ ret = -ENOSYS;
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
-
|
|
|
|
- data += fs_len;
|
|
|
|
- len -= fs_len;
|
|
|
|
- } else {
|
|
|
|
- fs_len = 0;
|
|
|
|
|
|
+ data += 12;
|
|
|
|
+ len -= 12;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ goto error;
|
|
}
|
|
}
|
|
|
|
|
|
- if (likely(hs_count)) {
|
|
|
|
- hs_len = ffs_do_descs(hs_count, data, len,
|
|
|
|
- __ffs_data_do_entity, ffs);
|
|
|
|
- if (unlikely(hs_len < 0)) {
|
|
|
|
- ret = hs_len;
|
|
|
|
|
|
+ /* Read fs_count, hs_count and ss_count (if present) */
|
|
|
|
+ for (i = 0; i < 3; ++i) {
|
|
|
|
+ if (!(flags & (1 << i))) {
|
|
|
|
+ counts[i] = 0;
|
|
|
|
+ } else if (len < 4) {
|
|
goto error;
|
|
goto error;
|
|
|
|
+ } else {
|
|
|
|
+ counts[i] = get_unaligned_le32(data);
|
|
|
|
+ data += 4;
|
|
|
|
+ len -= 4;
|
|
}
|
|
}
|
|
-
|
|
|
|
- data += hs_len;
|
|
|
|
- len -= hs_len;
|
|
|
|
- } else {
|
|
|
|
- hs_len = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (len >= 8) {
|
|
|
|
- /* Check SS_MAGIC for presence of ss_descs and get SS_COUNT */
|
|
|
|
- if (get_unaligned_le32(data) != FUNCTIONFS_SS_DESC_MAGIC)
|
|
|
|
- goto einval;
|
|
|
|
-
|
|
|
|
- ss_count = get_unaligned_le32(data + 4);
|
|
|
|
- data += 8;
|
|
|
|
- len -= 8;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- if (!fs_count && !hs_count && !ss_count)
|
|
|
|
- goto einval;
|
|
|
|
-
|
|
|
|
- if (ss_count) {
|
|
|
|
- ss_len = ffs_do_descs(ss_count, data, len,
|
|
|
|
|
|
+ /* Read descriptors */
|
|
|
|
+ raw_descs = data;
|
|
|
|
+ for (i = 0; i < 3; ++i) {
|
|
|
|
+ if (!counts[i])
|
|
|
|
+ continue;
|
|
|
|
+ ret = ffs_do_descs(counts[i], data, len,
|
|
__ffs_data_do_entity, ffs);
|
|
__ffs_data_do_entity, ffs);
|
|
- if (unlikely(ss_len < 0)) {
|
|
|
|
- ret = ss_len;
|
|
|
|
|
|
+ if (ret < 0)
|
|
goto error;
|
|
goto error;
|
|
- }
|
|
|
|
- ret = ss_len;
|
|
|
|
- } else {
|
|
|
|
- ss_len = 0;
|
|
|
|
- ret = 0;
|
|
|
|
|
|
+ data += ret;
|
|
|
|
+ len -= ret;
|
|
}
|
|
}
|
|
|
|
|
|
- if (unlikely(len != ret))
|
|
|
|
- goto einval;
|
|
|
|
|
|
+ if (raw_descs == data || len) {
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
|
|
- ffs->raw_fs_hs_descs_length = fs_len + hs_len;
|
|
|
|
- ffs->raw_ss_descs_length = ss_len;
|
|
|
|
- ffs->raw_descs = _data;
|
|
|
|
- ffs->fs_descs_count = fs_count;
|
|
|
|
- ffs->hs_descs_count = hs_count;
|
|
|
|
- ffs->ss_descs_count = ss_count;
|
|
|
|
|
|
+ ffs->raw_descs_data = _data;
|
|
|
|
+ ffs->raw_descs = raw_descs;
|
|
|
|
+ ffs->raw_descs_length = data - raw_descs;
|
|
|
|
+ ffs->fs_descs_count = counts[0];
|
|
|
|
+ ffs->hs_descs_count = counts[1];
|
|
|
|
+ ffs->ss_descs_count = counts[2];
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
-einval:
|
|
|
|
- ret = -EINVAL;
|
|
|
|
error:
|
|
error:
|
|
kfree(_data);
|
|
kfree(_data);
|
|
return ret;
|
|
return ret;
|
|
@@ -2359,8 +2346,7 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
|
vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
|
|
vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
|
|
super ? ffs->ss_descs_count + 1 : 0);
|
|
super ? ffs->ss_descs_count + 1 : 0);
|
|
vla_item_with_sz(d, short, inums, ffs->interfaces_count);
|
|
vla_item_with_sz(d, short, inums, ffs->interfaces_count);
|
|
- vla_item_with_sz(d, char, raw_descs,
|
|
|
|
- ffs->raw_fs_hs_descs_length + ffs->raw_ss_descs_length);
|
|
|
|
|
|
+ vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
|
|
char *vlabuf;
|
|
char *vlabuf;
|
|
|
|
|
|
ENTER();
|
|
ENTER();
|
|
@@ -2376,15 +2362,9 @@ static int _ffs_func_bind(struct usb_configuration *c,
|
|
|
|
|
|
/* Zero */
|
|
/* Zero */
|
|
memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
|
|
memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
|
|
- /* Copy only raw (hs,fs) descriptors (until ss_magic and ss_count) */
|
|
|
|
- memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs + 16,
|
|
|
|
- ffs->raw_fs_hs_descs_length);
|
|
|
|
- /* Copy SS descs present @ header + hs_fs_descs + ss_magic + ss_count */
|
|
|
|
- if (func->ffs->ss_descs_count)
|
|
|
|
- memcpy(vla_ptr(vlabuf, d, raw_descs) +
|
|
|
|
- ffs->raw_fs_hs_descs_length,
|
|
|
|
- ffs->raw_descs + 16 + ffs->raw_fs_hs_descs_length + 8,
|
|
|
|
- ffs->raw_ss_descs_length);
|
|
|
|
|
|
+ /* Copy descriptors */
|
|
|
|
+ memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
|
|
|
|
+ ffs->raw_descs_length);
|
|
|
|
|
|
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
|
|
memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz);
|
|
for (ret = ffs->eps_count; ret; --ret) {
|
|
for (ret = ffs->eps_count; ret; --ret) {
|