mirror of
https://github.com/systemd/systemd.git
synced 2026-08-09 17:38:42 +00:00
Assorted basic/shared/ndisc/import hardening fixes flagged by kres (#42934)
This commit is contained in:
@@ -87,14 +87,21 @@ int efi_get_variable(
|
||||
}
|
||||
|
||||
/* We want +1 for the read call, and +3 for the additional terminating bytes added below. */
|
||||
size_t file_size = (size_t) st.st_size, payload_size, read_size, alloc_size, read_limit;
|
||||
if (!SUB_SAFE(&payload_size, file_size, sizeof(attr)) ||
|
||||
!ADD_SAFE(&read_size, payload_size, 1) ||
|
||||
!ADD_SAFE(&alloc_size, read_size, 3) ||
|
||||
!ADD_SAFE(&read_limit, file_size, 1))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOVERFLOW), "EFI variable '%s' size calculation overflow, refusing.", p);
|
||||
|
||||
free(buf);
|
||||
buf = malloc((size_t) st.st_size - sizeof(attr) + CONST_MAX(1, 3));
|
||||
buf = malloc(alloc_size);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
struct iovec iov[] = {
|
||||
{ &attr, sizeof(attr) },
|
||||
{ buf, (size_t) st.st_size - sizeof(attr) + 1 },
|
||||
{ buf, read_size },
|
||||
};
|
||||
|
||||
n = readv(fd, iov, 2);
|
||||
@@ -103,11 +110,11 @@ int efi_get_variable(
|
||||
return log_debug_errno(errno, "Reading from '%s' failed: %m", p);
|
||||
|
||||
log_debug("Reading from '%s' failed with EINTR, retrying.", p);
|
||||
} else if ((size_t) n == sizeof(attr) + st.st_size + 1)
|
||||
} else if ((size_t) n == read_limit)
|
||||
/* We need to try again with a bigger buffer, the variable was apparently changed concurrently? */
|
||||
log_debug("EFI variable '%s' larger than expected, retrying.", p);
|
||||
else {
|
||||
assert((size_t) n < sizeof(attr) + st.st_size + 1);
|
||||
assert((size_t) n < read_limit);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ static int oci_pull_redirect_manifest(OciPull *i, const OciIndexEntry *entry) {
|
||||
|
||||
j->on_finished = oci_pull_job_on_finished_manifest;
|
||||
j->calc_checksum = true;
|
||||
if (!iovec_memdup(&entry->digest, &j->checksum))
|
||||
if (!iovec_memdup(&entry->digest, &j->expected_checksum))
|
||||
return -ENOMEM;
|
||||
|
||||
j->description = strjoin("Image Manifest (", url, ")");
|
||||
|
||||
@@ -52,7 +52,9 @@ int ndisc_neighbor_parse(sd_ndisc *nd, sd_ndisc_neighbor *na) {
|
||||
/* Neighbor advertisement packets are neatly aligned to 64-bit boundaries, hence we can access them directly */
|
||||
const struct nd_neighbor_advert *a = (const struct nd_neighbor_advert*) na->packet->raw_packet;
|
||||
assert(a->nd_na_type == ND_NEIGHBOR_ADVERT);
|
||||
assert(a->nd_na_code == 0);
|
||||
if (a->nd_na_code != 0)
|
||||
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received Neighbor Advertisement with non-zero code, ignoring datagram.");
|
||||
|
||||
na->flags = a->nd_na_flags_reserved; /* the first 3 bits */
|
||||
na->target_address = a->nd_na_target;
|
||||
|
||||
@@ -52,7 +52,9 @@ int ndisc_redirect_parse(sd_ndisc *nd, sd_ndisc_redirect *rd) {
|
||||
|
||||
const struct nd_redirect *a = (const struct nd_redirect*) rd->packet->raw_packet;
|
||||
assert(a->nd_rd_type == ND_REDIRECT);
|
||||
assert(a->nd_rd_code == 0);
|
||||
if (a->nd_rd_code != 0)
|
||||
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received Redirect message with non-zero code, ignoring datagram.");
|
||||
|
||||
rd->target_address = a->nd_rd_target;
|
||||
rd->destination_address = a->nd_rd_dst;
|
||||
|
||||
@@ -108,7 +108,9 @@ int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
|
||||
|
||||
a = (const struct nd_router_advert*) rt->packet->raw_packet;
|
||||
assert(a->nd_ra_type == ND_ROUTER_ADVERT);
|
||||
assert(a->nd_ra_code == 0);
|
||||
if (a->nd_ra_code != 0)
|
||||
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received Router Advertisement with non-zero code, ignoring.");
|
||||
|
||||
rt->hop_limit = a->nd_ra_curhoplimit;
|
||||
rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include "icmp6-test-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "ndisc-internal.h"
|
||||
#include "ndisc-neighbor-internal.h"
|
||||
#include "ndisc-redirect-internal.h"
|
||||
#include "ndisc-router-internal.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
|
||||
@@ -22,6 +25,59 @@ static struct ether_addr mac_addr = {
|
||||
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
|
||||
};
|
||||
|
||||
static ICMP6Packet* make_packet(const void *raw, size_t size) {
|
||||
ICMP6Packet *packet;
|
||||
|
||||
assert(raw);
|
||||
|
||||
packet = malloc0(offsetof(ICMP6Packet, raw_packet) + size);
|
||||
ASSERT_NOT_NULL(packet);
|
||||
|
||||
packet->n_ref = 1;
|
||||
packet->raw_size = size;
|
||||
memcpy(packet->raw_packet, raw, size);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
TEST(parse_rejects_nonzero_code) {
|
||||
static const struct nd_router_advert router_advertisement = {
|
||||
.nd_ra_type = ND_ROUTER_ADVERT,
|
||||
.nd_ra_code = 1,
|
||||
};
|
||||
static const struct nd_neighbor_advert neighbor_advertisement = {
|
||||
.nd_na_type = ND_NEIGHBOR_ADVERT,
|
||||
.nd_na_code = 1,
|
||||
};
|
||||
static const struct nd_redirect redirect = {
|
||||
.nd_rd_type = ND_REDIRECT,
|
||||
.nd_rd_code = 1,
|
||||
};
|
||||
|
||||
_cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet =
|
||||
make_packet(&router_advertisement, sizeof(router_advertisement));
|
||||
_cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *router =
|
||||
ASSERT_PTR(ndisc_router_new(packet));
|
||||
|
||||
ASSERT_ERROR(ndisc_router_parse(/* nd= */ NULL, router), EBADMSG);
|
||||
router = sd_ndisc_router_unref(router);
|
||||
packet = icmp6_packet_unref(packet);
|
||||
|
||||
packet = make_packet(&neighbor_advertisement, sizeof(neighbor_advertisement));
|
||||
_cleanup_(sd_ndisc_neighbor_unrefp) sd_ndisc_neighbor *neighbor =
|
||||
ASSERT_PTR(ndisc_neighbor_new(packet));
|
||||
|
||||
ASSERT_ERROR(ndisc_neighbor_parse(/* nd= */ NULL, neighbor), EBADMSG);
|
||||
neighbor = sd_ndisc_neighbor_unref(neighbor);
|
||||
packet = icmp6_packet_unref(packet);
|
||||
|
||||
packet = make_packet(&redirect, sizeof(redirect));
|
||||
_cleanup_(sd_ndisc_redirect_unrefp) sd_ndisc_redirect *rd =
|
||||
ASSERT_PTR(ndisc_redirect_new(packet));
|
||||
|
||||
ASSERT_ERROR(ndisc_redirect_parse(/* nd= */ NULL, rd), EBADMSG);
|
||||
}
|
||||
|
||||
static void router_dump(sd_ndisc_router *rt) {
|
||||
struct in6_addr addr;
|
||||
uint8_t hop_limit;
|
||||
|
||||
@@ -40,6 +40,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
const char *canonical = NULL;
|
||||
int n_addresses = 0;
|
||||
uint32_t local_address_ipv4 = 0;
|
||||
bool ipv6_enabled;
|
||||
size_t l, idx, ms;
|
||||
char *r_name;
|
||||
|
||||
@@ -96,7 +97,9 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
}
|
||||
|
||||
l = strlen(canonical);
|
||||
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 1 + socket_ipv6_is_enabled());
|
||||
ipv6_enabled = n_addresses == 0 && socket_ipv6_is_enabled();
|
||||
ms = ALIGN(l+1) +
|
||||
ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 1 + ipv6_enabled);
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
*errnop = ERANGE;
|
||||
@@ -112,13 +115,14 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
assert(n_addresses >= 0);
|
||||
if (n_addresses == 0) {
|
||||
/* Second, fill in IPv6 tuple */
|
||||
if (socket_ipv6_is_enabled()) {
|
||||
if (ipv6_enabled) {
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = r_tuple_prev;
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = AF_INET6;
|
||||
*r_tuple = (struct gaih_addrtuple) {
|
||||
.next = r_tuple_prev,
|
||||
.name = r_name,
|
||||
.family = AF_INET6,
|
||||
};
|
||||
memcpy(r_tuple->addr, LOCALADDRESS_IPV6, FAMILY_ADDRESS_SIZE(AF_INET6));
|
||||
r_tuple->scopeid = 0;
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
r_tuple_prev = r_tuple;
|
||||
@@ -126,11 +130,12 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
|
||||
/* Third, fill in IPv4 tuple */
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = r_tuple_prev;
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = AF_INET;
|
||||
*(uint32_t*) r_tuple->addr = local_address_ipv4;
|
||||
r_tuple->scopeid = 0;
|
||||
*r_tuple = (struct gaih_addrtuple) {
|
||||
.next = r_tuple_prev,
|
||||
.name = r_name,
|
||||
.family = AF_INET,
|
||||
};
|
||||
memcpy(r_tuple->addr, &local_address_ipv4, FAMILY_ADDRESS_SIZE(AF_INET));
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
r_tuple_prev = r_tuple;
|
||||
@@ -139,12 +144,18 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
/* Fourth, fill actual addresses in, but in backwards order */
|
||||
for (int i = n_addresses; i > 0; i--) {
|
||||
struct local_address *a = addresses + i - 1;
|
||||
uint32_t scopeid = 0;
|
||||
|
||||
if (a->family == AF_INET6 && in6_addr_is_link_local(&a->address.in6))
|
||||
scopeid = a->ifindex;
|
||||
|
||||
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
|
||||
r_tuple->next = r_tuple_prev;
|
||||
r_tuple->name = r_name;
|
||||
r_tuple->family = a->family;
|
||||
r_tuple->scopeid = a->family == AF_INET6 && in6_addr_is_link_local(&a->address.in6) ? a->ifindex : 0;
|
||||
*r_tuple = (struct gaih_addrtuple) {
|
||||
.next = r_tuple_prev,
|
||||
.name = r_name,
|
||||
.family = a->family,
|
||||
.scopeid = scopeid,
|
||||
};
|
||||
memcpy(r_tuple->addr, &a->address, FAMILY_ADDRESS_SIZE(a->family));
|
||||
|
||||
idx += ALIGN(sizeof(struct gaih_addrtuple));
|
||||
@@ -180,6 +191,7 @@ static enum nss_status fill_in_hostent(
|
||||
int af,
|
||||
struct local_address *addresses, unsigned n_addresses,
|
||||
uint32_t local_address_ipv4,
|
||||
bool ipv6_enabled,
|
||||
struct hostent *result,
|
||||
char *buffer, size_t buflen,
|
||||
int *errnop, int *h_errnop,
|
||||
@@ -212,8 +224,8 @@ static enum nss_status fill_in_hostent(
|
||||
(additional ? ALIGN(l_additional+1) : 0) +
|
||||
sizeof(char*) +
|
||||
(additional ? sizeof(char*) : 0) +
|
||||
(c > 0 ? c : af == AF_INET ? 1 : socket_ipv6_is_enabled()) * ALIGN(alen) +
|
||||
(c > 0 ? c+1 : af == AF_INET ? 2 : (unsigned) socket_ipv6_is_enabled() + 1) * sizeof(char*);
|
||||
(c > 0 ? c : af == AF_INET ? 1 : ipv6_enabled) * ALIGN(alen) +
|
||||
(c > 0 ? c+1 : af == AF_INET ? 2 : (unsigned) ipv6_enabled + 1) * sizeof(char*);
|
||||
|
||||
if (buflen < ms) {
|
||||
UNPROTECT_ERRNO;
|
||||
@@ -263,7 +275,7 @@ static enum nss_status fill_in_hostent(
|
||||
} else if (af == AF_INET) {
|
||||
*(uint32_t*) r_addr = local_address_ipv4;
|
||||
assert_se(INC_SAFE(&idx, ALIGN(alen)));
|
||||
} else if (socket_ipv6_is_enabled()) {
|
||||
} else if (ipv6_enabled) {
|
||||
memcpy(r_addr, LOCALADDRESS_IPV6, FAMILY_ADDRESS_SIZE(AF_INET6));
|
||||
assert_se(INC_SAFE(&idx, ALIGN(alen)));
|
||||
}
|
||||
@@ -279,7 +291,7 @@ static enum nss_status fill_in_hostent(
|
||||
((char**) r_addr_list)[i] = NULL;
|
||||
assert_se(INC_SAFE(&idx, (c+1) * sizeof(char*)));
|
||||
|
||||
} else if (af == AF_INET || socket_ipv6_is_enabled()) {
|
||||
} else if (af == AF_INET || ipv6_enabled) {
|
||||
((char**) r_addr_list)[0] = r_addr;
|
||||
((char**) r_addr_list)[1] = NULL;
|
||||
assert_se(INC_SAFE(&idx, 2 * sizeof(char*)));
|
||||
@@ -324,6 +336,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
const char *canonical, *additional = NULL;
|
||||
_cleanup_free_ char *hn = NULL;
|
||||
uint32_t local_address_ipv4 = 0;
|
||||
bool ipv6_enabled;
|
||||
int n_addresses = 0;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
@@ -345,7 +358,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
}
|
||||
|
||||
if (af == AF_INET6 && !socket_ipv6_is_enabled())
|
||||
ipv6_enabled = af == AF_INET6 && socket_ipv6_is_enabled();
|
||||
if (af == AF_INET6 && !ipv6_enabled)
|
||||
goto not_found;
|
||||
|
||||
if (is_localhost(name)) {
|
||||
@@ -397,6 +411,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
af,
|
||||
addresses, n_addresses,
|
||||
local_address_ipv4,
|
||||
ipv6_enabled,
|
||||
host,
|
||||
buffer, buflen,
|
||||
errnop, h_errnop,
|
||||
@@ -423,6 +438,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
|
||||
int n_addresses = 0;
|
||||
struct local_address *a;
|
||||
bool additional_from_hostname = false;
|
||||
bool ipv6_enabled = false;
|
||||
unsigned n;
|
||||
|
||||
PROTECT_ERRNO;
|
||||
@@ -461,7 +477,8 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
|
||||
} else {
|
||||
assert(af == AF_INET6);
|
||||
|
||||
if (!socket_ipv6_is_enabled())
|
||||
ipv6_enabled = socket_ipv6_is_enabled();
|
||||
if (!ipv6_enabled)
|
||||
goto not_found;
|
||||
|
||||
if (memcmp(addr, LOCALADDRESS_IPV6, FAMILY_ADDRESS_SIZE(AF_INET6)) == 0) {
|
||||
@@ -511,6 +528,7 @@ found:
|
||||
af,
|
||||
addresses, n_addresses,
|
||||
local_address_ipv4,
|
||||
ipv6_enabled,
|
||||
host,
|
||||
buffer, buflen,
|
||||
errnop, h_errnop,
|
||||
|
||||
@@ -1032,17 +1032,17 @@ int encrypt_credential_and_warn(
|
||||
return log_error_errno(r, "Failed to seal to TPM2: %m");
|
||||
|
||||
log_notice_errno(r, "TPM2 sealing didn't work, continuing without TPM2: %m");
|
||||
} else {
|
||||
if (!iovec_memdup(&IOVEC_MAKE(tpm2_policy.buffer, tpm2_policy.size), &tpm2_policy_hash))
|
||||
return log_oom();
|
||||
|
||||
assert(n_blobs == 1);
|
||||
tpm2_blob = TAKE_STRUCT(blobs[0]);
|
||||
|
||||
assert(tpm2_blob.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
assert(tpm2_policy_hash.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
assert(tpm2_srk.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
}
|
||||
|
||||
if (!iovec_memdup(&IOVEC_MAKE(tpm2_policy.buffer, tpm2_policy.size), &tpm2_policy_hash))
|
||||
return log_oom();
|
||||
|
||||
assert(n_blobs == 1);
|
||||
tpm2_blob = TAKE_STRUCT(blobs[0]);
|
||||
|
||||
assert(tpm2_blob.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
assert(tpm2_policy_hash.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
assert(tpm2_srk.iov_len <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "local-addresses.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "nss-test-util.h"
|
||||
#include "nss-util.h"
|
||||
#include "parse-util.h"
|
||||
@@ -67,6 +68,16 @@ static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static void assert_myhostname_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
|
||||
assert(tuples);
|
||||
|
||||
for (const struct gaih_addrtuple *it = tuples; it; it = it->next)
|
||||
if (it->family == AF_INET)
|
||||
assert_se(memeqzero(
|
||||
(const uint8_t*) it->addr + FAMILY_ADDRESS_SIZE(AF_INET),
|
||||
sizeof(it->addr) - FAMILY_ADDRESS_SIZE(AF_INET)));
|
||||
}
|
||||
|
||||
static void print_struct_hostent(struct hostent *host, const char *canon) {
|
||||
log_info(" \"%s\"", host->h_name);
|
||||
STRV_FOREACH(s, host->h_aliases)
|
||||
@@ -112,6 +123,9 @@ static void test_gethostbyname4_r(void *handle, const char *module, const char *
|
||||
return;
|
||||
}
|
||||
|
||||
/* Poison the scratch buffer so uninitialized padding in NSS replies is observable. */
|
||||
memset(buffer, 0xa5, sizeof(buffer));
|
||||
|
||||
status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl);
|
||||
if (status == NSS_STATUS_SUCCESS) {
|
||||
log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%"PRIxPTR" errno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
|
||||
@@ -122,6 +136,8 @@ static void test_gethostbyname4_r(void *handle, const char *module, const char *
|
||||
errno2, hstrerror(errno2),
|
||||
ttl);
|
||||
n = print_gaih_addrtuples(pat);
|
||||
if (streq(module, "myhostname"))
|
||||
assert_myhostname_gaih_addrtuples(pat);
|
||||
} else {
|
||||
log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s",
|
||||
fname, name,
|
||||
|
||||
Reference in New Issue
Block a user