Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

IB/core: Split uverbs_get_const/default to consider target type

Change uverbs_get_const/uverbs_get_const_default to work properly with
both signed/unsigned parameters.

Current APIs mix s64 and u64 which leads to incorrect check when u64
value was supplied and its upper bit was set. In that case
uverbs_get_const() / uverbs_get_const_default() lower bound check may
fail unexpectedly, target is unsigned (lower bound is 0) but value
became negative as of the s64 usage.

Split to have two different APIs, no change to callers as the required
API will be called internally according to the target type.

Link: https://lore.kernel.org/r/20210304130501.1102577-3-leon@kernel.org
Signed-off-by: Yishai Hadas <yishaih@nvidia.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

authored by

Yishai Hadas and committed by
Jason Gunthorpe
2904bb37 3f32dc0f

+96 -17
+28 -4
drivers/infiniband/core/uverbs_ioctl.c
··· 752 752 return uverbs_set_output(bundle, attr); 753 753 } 754 754 755 - int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, 756 - size_t idx, s64 lower_bound, u64 upper_bound, 757 - s64 *def_val) 755 + int _uverbs_get_const_signed(s64 *to, 756 + const struct uverbs_attr_bundle *attrs_bundle, 757 + size_t idx, s64 lower_bound, u64 upper_bound, 758 + s64 *def_val) 758 759 { 759 760 const struct uverbs_attr *attr; 760 761 ··· 774 773 775 774 return 0; 776 775 } 777 - EXPORT_SYMBOL(_uverbs_get_const); 776 + EXPORT_SYMBOL(_uverbs_get_const_signed); 777 + 778 + int _uverbs_get_const_unsigned(u64 *to, 779 + const struct uverbs_attr_bundle *attrs_bundle, 780 + size_t idx, u64 upper_bound, u64 *def_val) 781 + { 782 + const struct uverbs_attr *attr; 783 + 784 + attr = uverbs_attr_get(attrs_bundle, idx); 785 + if (IS_ERR(attr)) { 786 + if ((PTR_ERR(attr) != -ENOENT) || !def_val) 787 + return PTR_ERR(attr); 788 + 789 + *to = *def_val; 790 + } else { 791 + *to = attr->ptr_attr.data; 792 + } 793 + 794 + if (*to > upper_bound) 795 + return -EINVAL; 796 + 797 + return 0; 798 + } 799 + EXPORT_SYMBOL(_uverbs_get_const_unsigned); 778 800 779 801 int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle, 780 802 size_t idx, const void *from, size_t size)
+1
drivers/infiniband/hw/mlx5/main.c
··· 42 42 #include "counters.h" 43 43 #include <linux/mlx5/accel.h> 44 44 #include <rdma/uverbs_std_types.h> 45 + #include <rdma/uverbs_ioctl.h> 45 46 #include <rdma/mlx5_user_ioctl_verbs.h> 46 47 #include <rdma/mlx5_user_ioctl_cmds.h> 47 48 #include <rdma/ib_umem_odp.h>
+67 -13
include/rdma/uverbs_ioctl.h
··· 875 875 return ERR_PTR(-EOVERFLOW); 876 876 return uverbs_zalloc(bundle, bytes); 877 877 } 878 - int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, 879 - size_t idx, s64 lower_bound, u64 upper_bound, 880 - s64 *def_val); 878 + 879 + int _uverbs_get_const_signed(s64 *to, 880 + const struct uverbs_attr_bundle *attrs_bundle, 881 + size_t idx, s64 lower_bound, u64 upper_bound, 882 + s64 *def_val); 883 + int _uverbs_get_const_unsigned(u64 *to, 884 + const struct uverbs_attr_bundle *attrs_bundle, 885 + size_t idx, u64 upper_bound, u64 *def_val); 881 886 int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle, 882 887 size_t idx, const void *from, size_t size); 883 888 #else ··· 926 921 { 927 922 return -EINVAL; 928 923 } 924 + static int 925 + _uverbs_get_const_signed(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, 926 + size_t idx, s64 lower_bound, u64 upper_bound, 927 + s64 *def_val) 928 + { 929 + return -EINVAL; 930 + } 931 + static int 932 + _uverbs_get_const_unsigned(u64 *to, 933 + const struct uverbs_attr_bundle *attrs_bundle, 934 + size_t idx, u64 upper_bound, u64 *def_val) 935 + { 936 + return -EINVAL; 937 + } 929 938 #endif 930 939 931 - #define uverbs_get_const(_to, _attrs_bundle, _idx) \ 940 + #define uverbs_get_const_signed(_to, _attrs_bundle, _idx) \ 932 941 ({ \ 933 942 s64 _val; \ 934 - int _ret = _uverbs_get_const(&_val, _attrs_bundle, _idx, \ 935 - type_min(typeof(*_to)), \ 936 - type_max(typeof(*_to)), NULL); \ 937 - (*_to) = _val; \ 943 + int _ret = \ 944 + _uverbs_get_const_signed(&_val, _attrs_bundle, _idx, \ 945 + type_min(typeof(*(_to))), \ 946 + type_max(typeof(*(_to))), NULL); \ 947 + (*(_to)) = _val; \ 938 948 _ret; \ 939 949 }) 940 950 941 - #define uverbs_get_const_default(_to, _attrs_bundle, _idx, _default) \ 951 + #define uverbs_get_const_unsigned(_to, _attrs_bundle, _idx) \ 952 + ({ \ 953 + u64 _val; \ 954 + int _ret = \ 955 + _uverbs_get_const_unsigned(&_val, _attrs_bundle, _idx, \ 956 + type_max(typeof(*(_to))), NULL); \ 957 + (*(_to)) = _val; \ 958 + _ret; \ 959 + }) 960 + 961 + #define uverbs_get_const_default_signed(_to, _attrs_bundle, _idx, _default) \ 942 962 ({ \ 943 963 s64 _val; \ 944 964 s64 _def_val = _default; \ 945 965 int _ret = \ 946 - _uverbs_get_const(&_val, _attrs_bundle, _idx, \ 947 - type_min(typeof(*_to)), \ 948 - type_max(typeof(*_to)), &_def_val); \ 949 - (*_to) = _val; \ 966 + _uverbs_get_const_signed(&_val, _attrs_bundle, _idx, \ 967 + type_min(typeof(*(_to))), \ 968 + type_max(typeof(*(_to))), &_def_val); \ 969 + (*(_to)) = _val; \ 950 970 _ret; \ 951 971 }) 972 + 973 + #define uverbs_get_const_default_unsigned(_to, _attrs_bundle, _idx, _default) \ 974 + ({ \ 975 + u64 _val; \ 976 + u64 _def_val = _default; \ 977 + int _ret = \ 978 + _uverbs_get_const_unsigned(&_val, _attrs_bundle, _idx, \ 979 + type_max(typeof(*(_to))), &_def_val); \ 980 + (*(_to)) = _val; \ 981 + _ret; \ 982 + }) 983 + 984 + #define uverbs_get_const(_to, _attrs_bundle, _idx) \ 985 + (is_signed_type(typeof(*(_to))) ? \ 986 + uverbs_get_const_signed(_to, _attrs_bundle, _idx) : \ 987 + uverbs_get_const_unsigned(_to, _attrs_bundle, _idx)) \ 988 + 989 + #define uverbs_get_const_default(_to, _attrs_bundle, _idx, _default) \ 990 + (is_signed_type(typeof(*(_to))) ? \ 991 + uverbs_get_const_default_signed(_to, _attrs_bundle, _idx, \ 992 + _default) : \ 993 + uverbs_get_const_default_unsigned(_to, _attrs_bundle, _idx, \ 994 + _default)) 995 + 952 996 #endif