dhcp-network: adjust sockaddr length for addresses longer than 8 bytes (#6527)
An infiniband hardware address is 20 bytes, but sockaddr_ll.sll_addr is only 8 bytes. Explicitly ensure that sockaddr_union has enough space for infiniband addresses, even if they run over sockaddr_ll and add a macro to compute the proper size to pass to kernel.
This commit is contained in:
parent
ed88a9007a
commit
b1f24b75af
|
@ -27,6 +27,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
@ -42,6 +43,8 @@ union sockaddr_union {
|
|||
struct sockaddr_storage storage;
|
||||
struct sockaddr_ll ll;
|
||||
struct sockaddr_vm vm;
|
||||
/* Ensure there is enough space to store Infiniband addresses */
|
||||
uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
|
||||
};
|
||||
|
||||
typedef struct SocketAddress {
|
||||
|
@ -147,6 +150,23 @@ int flush_accept(int fd);
|
|||
|
||||
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
|
||||
|
||||
/*
|
||||
* Certain hardware address types (e.g Infiniband) do not fit into sll_addr
|
||||
* (8 bytes) and run over the structure. This macro returns the correct size that
|
||||
* must be passed to kernel.
|
||||
*/
|
||||
#define SOCKADDR_LL_LEN(sa) \
|
||||
({ \
|
||||
const struct sockaddr_ll *_sa = &(sa); \
|
||||
size_t _mac_len = sizeof(_sa->sll_addr); \
|
||||
assert(_sa->sll_family == AF_PACKET); \
|
||||
if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER) \
|
||||
_mac_len = MAX(_mac_len, (size_t) ETH_ALEN); \
|
||||
if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND) \
|
||||
_mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
|
||||
offsetof(struct sockaddr_ll, sll_addr) + _mac_len; \
|
||||
})
|
||||
|
||||
/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
|
||||
#define SOCKADDR_UN_LEN(sa) \
|
||||
({ \
|
||||
|
|
|
@ -108,14 +108,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
|||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
link->ll.sll_family = AF_PACKET;
|
||||
link->ll.sll_protocol = htobe16(ETH_P_IP);
|
||||
link->ll.sll_ifindex = ifindex;
|
||||
link->ll.sll_hatype = htobe16(arp_type);
|
||||
link->ll.sll_halen = mac_addr_len;
|
||||
link->ll = (struct sockaddr_ll) {
|
||||
.sll_family = AF_PACKET,
|
||||
.sll_protocol = htobe16(ETH_P_IP),
|
||||
.sll_ifindex = ifindex,
|
||||
.sll_hatype = htobe16(arp_type),
|
||||
.sll_halen = mac_addr_len,
|
||||
};
|
||||
memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
|
||||
|
||||
r = bind(s, &link->sa, sizeof(link->ll));
|
||||
r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -221,7 +223,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
|
|||
assert(packet);
|
||||
assert(len);
|
||||
|
||||
r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll));
|
||||
r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
|
|
Loading…
Reference in a new issue