netinet: correct SIOCDIFADDR{,_IN6} calls to use {,in6_}ifreq

The SIOCDIFADDR{,_IN6} ioctls take an ifreq structure object, not an
ifaliasreq/in_aliasreq/in6_aliasreq structure object, as their argument.
As opposed to ifaliasreq/in_aliasreq/in6_aliasreq used by
SIOCAIFADDR{,_IN6}, the ifreq/in6_ifreq structures used by the
SIOCDIFADDR{,_IN6} ioctls do not include a separate field for a
broadcast address and other values required to add an address to a
network interface with SIOCAIFADDR{,_IN6}.

Whilst this issue is not specific to CHERI-extended architectures, it
was first observed on CheriBSD running on Arm Morello. For example,
incorrect calls using the in6_aliasreq object result in CHERI capability
violations. A pointer to the ifra_addr field in in6_aliasreq cast to the
ifru_addr union member of in6_ifreq results in bounds being set to the
union's larger size. Such bounds exceed the bounds of of in6_aliasreq
object and the bounds-setting instruction clears a tag of the object's
capability.

Reviewed by:	brooks, kp, oshogbo
Accepted by:	oshogbo (mentor)
Reported by:	CHERI
Obtained from:	CheriBSD
Differential Revision: https://reviews.freebsd.org/D46016
This commit is contained in:
Konrad Witaszczyk 2024-06-27 12:54:14 +00:00
parent 2ab5515001
commit bc06c51419
3 changed files with 7 additions and 11 deletions

View File

@ -1037,12 +1037,10 @@ if_purgeaddrs(struct ifnet *ifp)
#ifdef INET
/* XXX: Ugly!! ad hoc just for INET */
if (ifa->ifa_addr->sa_family == AF_INET) {
struct ifaliasreq ifr;
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
ifr.ifra_addr = *ifa->ifa_addr;
if (ifa->ifa_dstaddr)
ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
ifr.ifr_addr = *ifa->ifa_addr;
if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
NULL) == 0)
continue;

View File

@ -1222,7 +1222,7 @@ in_ifscrub_all(void)
{
struct ifnet *ifp;
struct ifaddr *ifa, *nifa;
struct ifaliasreq ifr;
struct ifreq ifr;
IFNET_RLOCK();
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
@ -1237,9 +1237,7 @@ in_ifscrub_all(void)
* cleanly remove addresses and everything attached.
*/
bzero(&ifr, sizeof(ifr));
ifr.ifra_addr = *ifa->ifa_addr;
if (ifa->ifa_dstaddr)
ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
ifr.ifr_addr = *ifa->ifa_addr;
(void)in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr,
ifp, NULL);
}

View File

@ -1194,17 +1194,17 @@ static int
handle_deladdr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs,
if_t ifp, struct nlpcb *nlp, struct nl_pstate *npt)
{
struct sockaddr_in *addr = (struct sockaddr_in *)attrs->ifa_local;
struct sockaddr *addr = attrs->ifa_local;
if (addr == NULL)
addr = (struct sockaddr_in *)attrs->ifa_address;
addr = attrs->ifa_address;
if (addr == NULL) {
nlmsg_report_err_msg(npt, "empty IFA_ADDRESS/IFA_LOCAL");
return (EINVAL);
}
struct ifreq req = { .ifr_addr = *(struct sockaddr *)addr };
struct ifreq req = { .ifr_addr = *addr };
return (in_control_ioctl(SIOCDIFADDR, &req, ifp, nlp_get_cred(nlp)));
}