mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-10 07:00:48 +00:00
RDMA/cma: Distinguish between sockaddr_in and sockaddr_in6 by size
Clang can do some aggressive inlining, which provides it with greater visibility into the sizes of various objects that are passed into helpers. Specifically, compare_netdev_and_ip() can see through the type given to the "sa" argument, which means it can generate code for "struct sockaddr_in" that would have been passed to ipv6_addr_cmp() (that expects to operate on the larger "struct sockaddr_in6"), which would result in a compile-time buffer overflow condition detected by memcmp(). Logically, this state isn't reachable due to the sa_family assignment two callers above and the check in compare_netdev_and_ip(). Instead, provide a compile-time check on sizes so the size-mismatched code will be elided when inlining. Avoids the following warning from Clang: ../include/linux/fortify-string.h:652:4: error: call to '__read_overflow' declared with 'error' attribute: detected read beyond size of object (1st parameter) __read_overflow(); ^ note: In function 'cma_netevent_callback' note: which inlined function 'node_from_ndev_ip' 1 error generated. When the underlying object size is not known (e.g. with GCC and older Clang), the result of __builtin_object_size() is SIZE_MAX, which will also compile away, leaving the code as it was originally. Link: https://lore.kernel.org/r/20230208232549.never.139-kees@kernel.org Link: https://github.com/ClangBuiltLinux/linux/issues/1687 Signed-off-by: Kees Cook <keescook@chromium.org> Tested-by: Nathan Chancellor <nathan@kernel.org> # build Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
parent
5ff31dfcd6
commit
876e480da2
@ -479,13 +479,20 @@ static int compare_netdev_and_ip(int ifindex_a, struct sockaddr *sa,
|
||||
if (sa->sa_family != sb->sa_family)
|
||||
return sa->sa_family - sb->sa_family;
|
||||
|
||||
if (sa->sa_family == AF_INET)
|
||||
return memcmp((char *)&((struct sockaddr_in *)sa)->sin_addr,
|
||||
(char *)&((struct sockaddr_in *)sb)->sin_addr,
|
||||
if (sa->sa_family == AF_INET &&
|
||||
__builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in)) {
|
||||
return memcmp(&((struct sockaddr_in *)sa)->sin_addr,
|
||||
&((struct sockaddr_in *)sb)->sin_addr,
|
||||
sizeof(((struct sockaddr_in *)sa)->sin_addr));
|
||||
}
|
||||
|
||||
return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)sb)->sin6_addr);
|
||||
if (sa->sa_family == AF_INET6 &&
|
||||
__builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in6)) {
|
||||
return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr,
|
||||
&((struct sockaddr_in6 *)sb)->sin6_addr);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cma_add_id_to_tree(struct rdma_id_private *node_id_priv)
|
||||
|
Loading…
x
Reference in New Issue
Block a user