|
@@ -351,29 +351,50 @@ static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr
|
|
|
}
|
|
|
|
|
|
static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle,
|
|
|
- size_t idx, const void *from)
|
|
|
+ size_t idx, const void *from, size_t size)
|
|
|
{
|
|
|
const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
|
|
|
u16 flags;
|
|
|
+ size_t min_size;
|
|
|
|
|
|
if (IS_ERR(attr))
|
|
|
return PTR_ERR(attr);
|
|
|
|
|
|
+ min_size = min_t(size_t, attr->ptr_attr.len, size);
|
|
|
+ if (copy_to_user(attr->ptr_attr.ptr, from, min_size))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT;
|
|
|
- return (!copy_to_user(attr->ptr_attr.ptr, from, attr->ptr_attr.len) &&
|
|
|
- !put_user(flags, &attr->uattr->flags)) ? 0 : -EFAULT;
|
|
|
+ if (put_user(flags, &attr->uattr->flags))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static inline int _uverbs_copy_from(void *to, size_t to_size,
|
|
|
+static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)
|
|
|
+{
|
|
|
+ return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data);
|
|
|
+}
|
|
|
+
|
|
|
+static inline int _uverbs_copy_from(void *to,
|
|
|
const struct uverbs_attr_bundle *attrs_bundle,
|
|
|
- size_t idx)
|
|
|
+ size_t idx,
|
|
|
+ size_t size)
|
|
|
{
|
|
|
const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
|
|
|
|
|
|
if (IS_ERR(attr))
|
|
|
return PTR_ERR(attr);
|
|
|
|
|
|
- if (to_size <= sizeof(((struct ib_uverbs_attr *)0)->data))
|
|
|
+ /*
|
|
|
+ * Validation ensures attr->ptr_attr.len >= size. If the caller is
|
|
|
+ * using UVERBS_ATTR_SPEC_F_MIN_SZ then it must call copy_from with
|
|
|
+ * the right size.
|
|
|
+ */
|
|
|
+ if (unlikely(size < attr->ptr_attr.len))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (uverbs_attr_ptr_is_inline(attr))
|
|
|
memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len);
|
|
|
else if (copy_from_user(to, attr->ptr_attr.ptr, attr->ptr_attr.len))
|
|
|
return -EFAULT;
|
|
@@ -382,7 +403,7 @@ static inline int _uverbs_copy_from(void *to, size_t to_size,
|
|
|
}
|
|
|
|
|
|
#define uverbs_copy_from(to, attrs_bundle, idx) \
|
|
|
- _uverbs_copy_from(to, sizeof(*(to)), attrs_bundle, idx)
|
|
|
+ _uverbs_copy_from(to, attrs_bundle, idx, sizeof(*to))
|
|
|
|
|
|
/* =================================================
|
|
|
* Definitions -> Specs infrastructure
|