diff options
| author | deraadt <> | 2025-11-13 10:34:32 +0000 |
|---|---|---|
| committer | deraadt <> | 2025-11-13 10:34:32 +0000 |
| commit | 825e052c574fe0fd3afe3cf1322f333551ca4888 (patch) | |
| tree | 91903c439b8433ac80e85f001a34fa1b2975949a | |
| parent | 286cd02a2b95cd94707d1ae63155b59302dfefc7 (diff) | |
| download | openbsd-825e052c574fe0fd3afe3cf1322f333551ca4888.tar.gz openbsd-825e052c574fe0fd3afe3cf1322f333551ca4888.tar.bz2 openbsd-825e052c574fe0fd3afe3cf1322f333551ca4888.zip | |
the structure produced has alignment, which contained uninitialized data.
This is obviously fixed by using calloc(), but it was also observed that
the precalculated storage requirement was higher than what is actually
filled. So all the math has been rewritten to be byte accurate.
Temporarily, a syslog_r check is added to report if we ever get count
inconsistancy again so that can be fixed quickly.
ok claudio
| -rw-r--r-- | src/lib/libc/net/getifaddrs.c | 87 |
1 files changed, 57 insertions, 30 deletions
diff --git a/src/lib/libc/net/getifaddrs.c b/src/lib/libc/net/getifaddrs.c index 069ee9afab..448e76097f 100644 --- a/src/lib/libc/net/getifaddrs.c +++ b/src/lib/libc/net/getifaddrs.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: getifaddrs.c,v 1.14 2021/11/29 03:20:37 deraadt Exp $ */ | 1 | /* $OpenBSD: getifaddrs.c,v 1.15 2025/11/13 10:34:32 deraadt Exp $ */ |
| 2 | 2 | ||
| 3 | /* | 3 | /* |
| 4 | * Copyright (c) 1995, 1999 | 4 | * Copyright (c) 1995, 1999 |
| @@ -25,10 +25,10 @@ | |||
| 25 | * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp | 25 | * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <sys/param.h> /* ALIGN ALIGNBYTES */ | ||
| 29 | #include <sys/types.h> | 28 | #include <sys/types.h> |
| 30 | #include <sys/ioctl.h> | 29 | #include <sys/ioctl.h> |
| 31 | #include <sys/socket.h> | 30 | #include <sys/socket.h> |
| 31 | #include <sys/syslog.h> | ||
| 32 | #include <net/if.h> | 32 | #include <net/if.h> |
| 33 | #include <net/route.h> | 33 | #include <net/route.h> |
| 34 | #include <sys/sysctl.h> | 34 | #include <sys/sysctl.h> |
| @@ -38,35 +38,32 @@ | |||
| 38 | #include <ifaddrs.h> | 38 | #include <ifaddrs.h> |
| 39 | #include <stddef.h> | 39 | #include <stddef.h> |
| 40 | #include <stdlib.h> | 40 | #include <stdlib.h> |
| 41 | #include <stdint.h> | ||
| 41 | #include <string.h> | 42 | #include <string.h> |
| 42 | #include <unistd.h> | 43 | #include <unistd.h> |
| 44 | #include <stdio.h> | ||
| 43 | 45 | ||
| 44 | #define SALIGN (sizeof(long) - 1) | 46 | #define roundup(x, y) ((((uintptr_t)(x)+((y)-1))/(y))*(y)) |
| 45 | #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) | 47 | #define proundup(x, y) (void *)roundup(x,y) |
| 48 | |||
| 49 | #define SA_RLEN(sa) ((sa)->sa_len ? \ | ||
| 50 | roundup((sa)->sa_len, sizeof(long)) : \ | ||
| 51 | roundup(1, sizeof(long))) | ||
| 46 | 52 | ||
| 47 | int | 53 | int |
| 48 | getifaddrs(struct ifaddrs **pif) | 54 | getifaddrs(struct ifaddrs **pif) |
| 49 | { | 55 | { |
| 50 | int icnt = 1; | 56 | int icnt = 1, dcnt = 0, ncnt = 0, mib[6], i; |
| 51 | int dcnt = 0; | ||
| 52 | int ncnt = 0; | ||
| 53 | int mib[6]; | ||
| 54 | size_t needed; | 57 | size_t needed; |
| 55 | char *buf = NULL, *bufp; | 58 | char *buf = NULL, *bufp, *data, *names, *next, *p, *p0; |
| 56 | char *next; | 59 | struct ifaddrs *cif = 0, *ifa, *ift; |
| 57 | struct ifaddrs *cif = 0; | ||
| 58 | char *p, *p0; | ||
| 59 | struct rt_msghdr *rtm; | 60 | struct rt_msghdr *rtm; |
| 60 | struct if_msghdr *ifm; | 61 | struct if_msghdr *ifm; |
| 61 | struct ifa_msghdr *ifam; | 62 | struct ifa_msghdr *ifam; |
| 62 | struct sockaddr_dl *dl; | 63 | struct sockaddr_dl *dl; |
| 63 | struct sockaddr *sa; | 64 | struct sockaddr *sa; |
| 64 | u_short index = 0; | 65 | u_short index = 0; |
| 65 | size_t len, alen, dlen; | 66 | size_t len, alen, dlen, dsize; |
| 66 | struct ifaddrs *ifa, *ift; | ||
| 67 | int i; | ||
| 68 | char *data; | ||
| 69 | char *names; | ||
| 70 | 67 | ||
| 71 | mib[0] = CTL_NET; | 68 | mib[0] = CTL_NET; |
| 72 | mib[1] = PF_ROUTE; | 69 | mib[1] = PF_ROUTE; |
| @@ -95,6 +92,7 @@ getifaddrs(struct ifaddrs **pif) | |||
| 95 | break; | 92 | break; |
| 96 | } | 93 | } |
| 97 | 94 | ||
| 95 | /* Calculate data buffer size */ | ||
| 98 | for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { | 96 | for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { |
| 99 | rtm = (struct rt_msghdr *)next; | 97 | rtm = (struct rt_msghdr *)next; |
| 100 | if (rtm->rtm_version != RTM_VERSION) | 98 | if (rtm->rtm_version != RTM_VERSION) |
| @@ -107,10 +105,15 @@ getifaddrs(struct ifaddrs **pif) | |||
| 107 | ++icnt; | 105 | ++icnt; |
| 108 | dl = (struct sockaddr_dl *)(next + | 106 | dl = (struct sockaddr_dl *)(next + |
| 109 | rtm->rtm_hdrlen); | 107 | rtm->rtm_hdrlen); |
| 110 | dcnt += SA_RLEN((struct sockaddr *)dl) + | ||
| 111 | ALIGNBYTES; | ||
| 112 | dcnt += sizeof(ifm->ifm_data); | ||
| 113 | ncnt += dl->sdl_nlen + 1; | 108 | ncnt += dl->sdl_nlen + 1; |
| 109 | |||
| 110 | /* sockaddr's need long alignment */ | ||
| 111 | dcnt = roundup(dcnt, sizeof(long)); | ||
| 112 | dcnt += SA_RLEN((struct sockaddr *)dl); | ||
| 113 | |||
| 114 | /* ifm_data[] needs long long alignment */ | ||
| 115 | dcnt = roundup(dcnt, sizeof(long long)); | ||
| 116 | dcnt += sizeof(ifm->ifm_data); | ||
| 114 | } else | 117 | } else |
| 115 | index = 0; | 118 | index = 0; |
| 116 | break; | 119 | break; |
| @@ -145,6 +148,8 @@ getifaddrs(struct ifaddrs **pif) | |||
| 145 | continue; | 148 | continue; |
| 146 | sa = (struct sockaddr *)p; | 149 | sa = (struct sockaddr *)p; |
| 147 | len = SA_RLEN(sa); | 150 | len = SA_RLEN(sa); |
| 151 | /* sockaddr's need long alignment */ | ||
| 152 | dcnt = roundup(dcnt, sizeof(long)); | ||
| 148 | if (i == RTAX_NETMASK && sa->sa_len == 0) | 153 | if (i == RTAX_NETMASK && sa->sa_len == 0) |
| 149 | dcnt += alen; | 154 | dcnt += alen; |
| 150 | else | 155 | else |
| @@ -155,23 +160,29 @@ getifaddrs(struct ifaddrs **pif) | |||
| 155 | } | 160 | } |
| 156 | } | 161 | } |
| 157 | 162 | ||
| 158 | if (icnt + dcnt + ncnt == 1) { | 163 | if (icnt + ncnt + dcnt == 1) { |
| 159 | *pif = NULL; | 164 | *pif = NULL; |
| 160 | free(buf); | 165 | free(buf); |
| 161 | return (0); | 166 | return (0); |
| 162 | } | 167 | } |
| 163 | data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); | 168 | |
| 169 | dsize = sizeof(struct ifaddrs) * icnt; | ||
| 170 | dsize += ncnt; | ||
| 171 | dsize = roundup(dsize, sizeof(long long)); | ||
| 172 | dsize += dcnt; | ||
| 173 | |||
| 174 | data = calloc(dsize, 1); | ||
| 164 | if (data == NULL) { | 175 | if (data == NULL) { |
| 165 | free(buf); | 176 | free(buf); |
| 166 | return(-1); | 177 | return(-1); |
| 167 | } | 178 | } |
| 168 | 179 | ||
| 169 | ifa = (struct ifaddrs *)data; | 180 | /* ifaddrs[], names, then if_data[] */ |
| 181 | ift = ifa = (struct ifaddrs *)data; | ||
| 170 | data += sizeof(struct ifaddrs) * icnt; | 182 | data += sizeof(struct ifaddrs) * icnt; |
| 171 | names = data + dcnt; | 183 | names = data; |
| 172 | 184 | data += ncnt; | |
| 173 | memset(ifa, 0, sizeof(struct ifaddrs) * icnt); | 185 | data = proundup(data, sizeof(long long)); |
| 174 | ift = ifa; | ||
| 175 | 186 | ||
| 176 | index = 0; | 187 | index = 0; |
| 177 | for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { | 188 | for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { |
| @@ -193,19 +204,21 @@ getifaddrs(struct ifaddrs **pif) | |||
| 193 | names[dl->sdl_nlen] = 0; | 204 | names[dl->sdl_nlen] = 0; |
| 194 | names += dl->sdl_nlen + 1; | 205 | names += dl->sdl_nlen + 1; |
| 195 | 206 | ||
| 207 | data = proundup(data, sizeof(long)); | ||
| 196 | ift->ifa_addr = (struct sockaddr *)data; | 208 | ift->ifa_addr = (struct sockaddr *)data; |
| 197 | memcpy(data, dl, | 209 | memcpy(data, dl, |
| 198 | ((struct sockaddr *)dl)->sa_len); | 210 | ((struct sockaddr *)dl)->sa_len); |
| 199 | data += SA_RLEN((struct sockaddr *)dl); | 211 | data += SA_RLEN((struct sockaddr *)dl); |
| 200 | 212 | ||
| 201 | /* ifm_data needs to be aligned */ | 213 | /* if_data needs long long alignment */ |
| 202 | ift->ifa_data = data = (void *)ALIGN(data); | 214 | data = proundup(data, sizeof(long long)); |
| 215 | ift->ifa_data = data; | ||
| 203 | dlen = rtm->rtm_hdrlen - | 216 | dlen = rtm->rtm_hdrlen - |
| 204 | offsetof(struct if_msghdr, ifm_data); | 217 | offsetof(struct if_msghdr, ifm_data); |
| 205 | if (dlen > sizeof(ifm->ifm_data)) | 218 | if (dlen > sizeof(ifm->ifm_data)) |
| 206 | dlen = sizeof(ifm->ifm_data); | 219 | dlen = sizeof(ifm->ifm_data); |
| 207 | memcpy(data, &ifm->ifm_data, dlen); | 220 | memcpy(data, &ifm->ifm_data, dlen); |
| 208 | data += sizeof(ifm->ifm_data); | 221 | data += dlen; |
| 209 | 222 | ||
| 210 | ift = (ift->ifa_next = ift + 1); | 223 | ift = (ift->ifa_next = ift + 1); |
| 211 | } else | 224 | } else |
| @@ -245,12 +258,14 @@ getifaddrs(struct ifaddrs **pif) | |||
| 245 | len = SA_RLEN(sa); | 258 | len = SA_RLEN(sa); |
| 246 | switch (i) { | 259 | switch (i) { |
| 247 | case RTAX_IFA: | 260 | case RTAX_IFA: |
| 261 | data = proundup(data, sizeof(long)); | ||
| 248 | ift->ifa_addr = (struct sockaddr *)data; | 262 | ift->ifa_addr = (struct sockaddr *)data; |
| 249 | memcpy(data, p, len); | 263 | memcpy(data, p, len); |
| 250 | data += len; | 264 | data += len; |
| 251 | break; | 265 | break; |
| 252 | 266 | ||
| 253 | case RTAX_NETMASK: | 267 | case RTAX_NETMASK: |
| 268 | data = proundup(data, sizeof(long)); | ||
| 254 | ift->ifa_netmask = | 269 | ift->ifa_netmask = |
| 255 | (struct sockaddr *)data; | 270 | (struct sockaddr *)data; |
| 256 | if (sa->sa_len == 0) { | 271 | if (sa->sa_len == 0) { |
| @@ -263,6 +278,7 @@ getifaddrs(struct ifaddrs **pif) | |||
| 263 | break; | 278 | break; |
| 264 | 279 | ||
| 265 | case RTAX_BRD: | 280 | case RTAX_BRD: |
| 281 | data = proundup(data, sizeof(long)); | ||
| 266 | ift->ifa_broadaddr = | 282 | ift->ifa_broadaddr = |
| 267 | (struct sockaddr *)data; | 283 | (struct sockaddr *)data; |
| 268 | memcpy(data, p, len); | 284 | memcpy(data, p, len); |
| @@ -278,6 +294,17 @@ getifaddrs(struct ifaddrs **pif) | |||
| 278 | } | 294 | } |
| 279 | } | 295 | } |
| 280 | 296 | ||
| 297 | /* XXX temporary paranoia until we are sure it is bug free */ | ||
| 298 | if (dsize != (char *)data - (char *)ifa) { | ||
| 299 | char buf[1024]; | ||
| 300 | |||
| 301 | /* <10> is LOG_CRIT */ | ||
| 302 | snprintf(buf, sizeof buf, | ||
| 303 | "<10>%s: getifaddrs: allocated %lu used %lu\n", | ||
| 304 | __progname, dsize, (char *)data - (char *)ifa); | ||
| 305 | sendsyslog(buf, strlen(buf), LOG_CONS); | ||
| 306 | } | ||
| 307 | |||
| 281 | free(buf); | 308 | free(buf); |
| 282 | if (--ift >= ifa) { | 309 | if (--ift >= ifa) { |
| 283 | ift->ifa_next = NULL; | 310 | ift->ifa_next = NULL; |
