1
0
mirror of https://github.com/systemd/systemd synced 2025-09-28 00:04:47 +02:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Greg Depoire--Ferrer
6597686865 seccomp: don't install filters for archs that can't use syscalls
When seccomp_restrict_archs is called, architectures that are blocked
are replaced by the SECCOMP_LOCAL_ARCH_BLOCKED marker so that they are
not disabled again and filters are not installed for them.

This can make some service that use SystemCallArchitecture= and
SystemCallFilter= start faster.
2020-12-10 16:13:02 +01:00
Vito Caputo
104fc4be11 mmap-cache: bind prot(ection) to MMapFileDescriptor
There are no mmap_cache_get() users that actually deviate prot
from the JournalFile's f->prot.

So there's no point in making this a separate parameter to
mmap_cache_get(), nor is there any need to store it in
JournalFile's f->prot.

Instead just pass it to mmap_cache_add_fd() at MMapFileDescriptor
creation, storing it in there for the mmap() callers, which
already receive MMapFileDescriptor *.

For functions receiving both an MMapFileDescriptor * and prot,
the prot argument has been simply removed and call sites updated.

Formalizing this fd:prot binding at the public API also enables
discarding the prot check in window_matches(), which is a hot
function on long window lists, so a minor CPU efficiency gain
should be had there as seen with the past removal of the fd
check.  Unnoticable for uncached journals, but maybe a little
runtime improvement when cached in specific circumstances.

window_matches_fd() has also been simplified to treat the
MMapFileDescrptor * as equivalent to its fd and prot.
2020-12-10 13:03:31 +01:00
Lennart Poettering
cca2da15c8 three spdx header fixes 2020-12-10 13:03:11 +01:00
Lennart Poettering
8620022f28
Merge pull request #17851 from yuwata/network-address-compare-func
network: revert previous changes to address_compare_func()
2020-12-10 10:43:47 +01:00
Vito Caputo
073f50a099 mmap-cache: separate context and window list cache hit accounting
Account and log these statistics separately since their overheads
are potentially quite different when the window lists are large.

There should probably be a histogram of window list traversal
counts too.
2020-12-10 10:23:01 +01:00
Yu Watanabe
b432080dc8 network: warn when NDISC and DHCPv6 provide the same address
With some router, the address in NDISC generated with EUI-64 conflicts
with an address provided by DHCPv6.

Prompted by #17831.
2020-12-08 13:36:19 +09:00
Yu Watanabe
450fa34bd0 network: fix SIGABRT related to unreachable route with DHCP6
After #17834, unreachable routes generated through DHCP6 are managed by
Manager. But they are referrenced by the DHCP6 uplink. So, the routes
managed by Manager must be freed after all Link objects are freed.

Follow-up for 575f14eef010101c60e9d4d970e542c815be1994.

Fixes SIGABRT reproted in #17831.
2020-12-08 12:41:07 +09:00
Yu Watanabe
c5a0aeb33a network: use address_get() in address_exists()
And rename address_exists() to link_has_ipv6_address().
2020-12-08 12:41:07 +09:00
Yu Watanabe
1d30fc5cb6 network: revert previous changes to address_compare_func()
This partially reverts fe841414ef157f7f01d339c5d5730126e7b5fe0a and
2a236f9fc0ff8fb2152032551436fde74da7217a.

For IPv4, kernel compares the local address, prefix, and prefixlen.
For IPv6, kernel compares only the local address.
Let's follow the kernel's comparison way.

Fixes #17831.
2020-12-08 12:41:07 +09:00
18 changed files with 217 additions and 147 deletions

4
TODO
View File

@ -135,10 +135,6 @@ Features:
o move into separate libsystemd-shared-iptables.so .so
- iptables-libs (only used by nspawn + networkd)
* seccomp: when SystemCallArchitectures=native is set then don't install any
other seccomp filters for any of the other archs, in order to reduce the
number of seccomp filters we install needlessly.
* seccomp: maybe use seccomp_merge() to merge our filters per-arch if we can.
Apparently kernel performance is much better with fewer larger seccomp
filters than with more smaller seccomp filters.

View File

@ -751,7 +751,7 @@ static int journal_file_move_to(
return -EADDRNOTAVAIL;
}
return mmap_cache_get(f->mmap, f->cache_fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret, ret_size);
return mmap_cache_get(f->mmap, f->cache_fd, type_to_context(type), keep_always, offset, size, &f->last_stat, ret, ret_size);
}
static uint64_t minimum_header_size(Object *o) {
@ -3365,7 +3365,6 @@ int journal_file_open(
.mode = mode,
.flags = flags,
.prot = prot_from_flags(flags),
.writable = (flags & O_ACCMODE) != O_RDONLY,
#if HAVE_ZSTD
@ -3464,7 +3463,7 @@ int journal_file_open(
goto fail;
}
f->cache_fd = mmap_cache_add_fd(f->mmap, f->fd);
f->cache_fd = mmap_cache_add_fd(f->mmap, f->fd, prot_from_flags(flags));
if (!f->cache_fd) {
r = -ENOMEM;
goto fail;
@ -3511,7 +3510,7 @@ int journal_file_open(
goto fail;
}
r = mmap_cache_get(f->mmap, f->cache_fd, f->prot, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h, NULL);
r = mmap_cache_get(f->mmap, f->cache_fd, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h, NULL);
if (r == -EINVAL) {
/* Some file systems (jffs2 or p9fs) don't support mmap() properly (or only read-only
* mmap()), and return EINVAL in that case. Let's propagate that as a more recognizable error

View File

@ -63,7 +63,6 @@ typedef struct JournalFile {
mode_t mode;
int flags;
int prot;
bool writable:1;
bool compress_xz:1;
bool compress_lz4:1;

View File

@ -377,7 +377,7 @@ static int contains_uint64(MMapCache *m, MMapFileDescriptor *f, uint64_t n, uint
c = (a + b) / 2;
r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
r = mmap_cache_get(m, f, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
if (r < 0)
return r;
@ -862,19 +862,19 @@ int journal_file_verify(
goto fail;
}
cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd);
cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd, PROT_READ|PROT_WRITE);
if (!cache_data_fd) {
r = log_oom();
goto fail;
}
cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd);
cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd, PROT_READ|PROT_WRITE);
if (!cache_entry_fd) {
r = log_oom();
goto fail;
}
cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd);
cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd, PROT_READ|PROT_WRITE);
if (!cache_entry_array_fd) {
r = log_oom();
goto fail;

View File

@ -25,7 +25,6 @@ struct Window {
bool keep_always:1;
bool in_unused:1;
int prot;
void *ptr;
uint64_t offset;
size_t size;
@ -49,6 +48,7 @@ struct Context {
struct MMapFileDescriptor {
MMapCache *cache;
int fd;
int prot;
bool sigbus;
LIST_HEAD(Window, windows);
};
@ -57,7 +57,7 @@ struct MMapCache {
unsigned n_ref;
unsigned n_windows;
unsigned n_hit, n_missed;
unsigned n_context_cache_hit, n_window_list_hit, n_missed;
Hashmap *fds;
Context *contexts[MMAP_CACHE_MAX_CONTEXTS];
@ -112,6 +112,7 @@ static void window_unlink(Window *w) {
static void window_invalidate(Window *w) {
assert(w);
assert(w->fd);
if (w->invalidated)
return;
@ -121,7 +122,7 @@ static void window_invalidate(Window *w) {
* trigger any further SIGBUS, possibly overrunning the sigbus
* queue. */
assert_se(mmap(w->ptr, w->size, w->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr);
assert_se(mmap(w->ptr, w->size, w->fd->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr);
w->invalidated = true;
}
@ -133,27 +134,25 @@ static void window_free(Window *w) {
free(w);
}
_pure_ static bool window_matches(Window *w, int prot, uint64_t offset, size_t size) {
_pure_ static bool window_matches(Window *w, uint64_t offset, size_t size) {
assert(w);
assert(size > 0);
return
prot == w->prot &&
offset >= w->offset &&
offset + size <= w->offset + w->size;
}
_pure_ static bool window_matches_fd(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) {
_pure_ static bool window_matches_fd(Window *w, MMapFileDescriptor *f, uint64_t offset, size_t size) {
assert(w);
assert(f);
return
w->fd &&
f->fd == w->fd->fd &&
window_matches(w, prot, offset, size);
w->fd == f &&
window_matches(w, offset, size);
}
static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool keep_always, uint64_t offset, size_t size, void *ptr) {
static Window *window_add(MMapCache *m, MMapFileDescriptor *f, bool keep_always, uint64_t offset, size_t size, void *ptr) {
Window *w;
assert(m);
@ -176,7 +175,6 @@ static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool ke
*w = (Window) {
.cache = m,
.fd = f,
.prot = prot,
.keep_always = keep_always,
.offset = offset,
.size = size,
@ -304,7 +302,6 @@ static int make_room(MMapCache *m) {
static int try_context(
MMapCache *m,
MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
uint64_t offset,
@ -329,7 +326,7 @@ static int try_context(
if (!c->window)
return 0;
if (!window_matches_fd(c->window, f, prot, offset, size)) {
if (!window_matches_fd(c->window, f, offset, size)) {
/* Drop the reference to the window, since it's unnecessary now */
context_detach_window(c);
@ -351,7 +348,6 @@ static int try_context(
static int find_mmap(
MMapCache *m,
MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
uint64_t offset,
@ -371,7 +367,7 @@ static int find_mmap(
return -EIO;
LIST_FOREACH(by_fd, w, f->windows)
if (window_matches(w, prot, offset, size))
if (window_matches(w, offset, size))
break;
if (!w)
@ -391,7 +387,7 @@ static int find_mmap(
return 1;
}
static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int prot, int flags, uint64_t offset, size_t size, void **res) {
static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int flags, uint64_t offset, size_t size, void **res) {
void *ptr;
assert(m);
@ -401,7 +397,7 @@ static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int
for (;;) {
int r;
ptr = mmap(addr, size, prot, flags, f->fd, offset);
ptr = mmap(addr, size, f->prot, flags, f->fd, offset);
if (ptr != MAP_FAILED)
break;
if (errno != ENOMEM)
@ -421,7 +417,6 @@ static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int
static int add_mmap(
MMapCache *m,
MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
uint64_t offset,
@ -471,7 +466,7 @@ static int add_mmap(
wsize = PAGE_ALIGN(st->st_size - woffset);
}
r = mmap_try_harder(m, NULL, f, prot, MAP_SHARED, woffset, wsize, &d);
r = mmap_try_harder(m, NULL, f, MAP_SHARED, woffset, wsize, &d);
if (r < 0)
return r;
@ -479,7 +474,7 @@ static int add_mmap(
if (!c)
goto outofmem;
w = window_add(m, f, prot, keep_always, woffset, wsize, d);
w = window_add(m, f, keep_always, woffset, wsize, d);
if (!w)
goto outofmem;
@ -499,7 +494,6 @@ outofmem:
int mmap_cache_get(
MMapCache *m,
MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
uint64_t offset,
@ -518,29 +512,29 @@ int mmap_cache_get(
assert(context < MMAP_CACHE_MAX_CONTEXTS);
/* Check whether the current context is the right one already */
r = try_context(m, f, prot, context, keep_always, offset, size, ret, ret_size);
r = try_context(m, f, context, keep_always, offset, size, ret, ret_size);
if (r != 0) {
m->n_hit++;
m->n_context_cache_hit++;
return r;
}
/* Search for a matching mmap */
r = find_mmap(m, f, prot, context, keep_always, offset, size, ret, ret_size);
r = find_mmap(m, f, context, keep_always, offset, size, ret, ret_size);
if (r != 0) {
m->n_hit++;
m->n_window_list_hit++;
return r;
}
m->n_missed++;
/* Create a new mmap */
return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret, ret_size);
return add_mmap(m, f, context, keep_always, offset, size, st, ret, ret_size);
}
void mmap_cache_stats_log_debug(MMapCache *m) {
assert(m);
log_debug("mmap cache statistics: %u hit, %u miss", m->n_hit, m->n_missed);
log_debug("mmap cache statistics: %u context cache hit, %u window list hit, %u miss", m->n_context_cache_hit, m->n_window_list_hit, m->n_missed);
}
static void mmap_cache_process_sigbus(MMapCache *m) {
@ -614,7 +608,7 @@ bool mmap_cache_got_sigbus(MMapCache *m, MMapFileDescriptor *f) {
return f->sigbus;
}
MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) {
MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd, int prot) {
MMapFileDescriptor *f;
int r;
@ -635,6 +629,7 @@ MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) {
f->cache = m;
f->fd = fd;
f->prot = prot;
r = hashmap_put(m->fds, FD_TO_PTR(fd), f);
if (r < 0)

View File

@ -17,7 +17,6 @@ MMapCache* mmap_cache_unref(MMapCache *m);
int mmap_cache_get(
MMapCache *m,
MMapFileDescriptor *f,
int prot,
unsigned context,
bool keep_always,
uint64_t offset,
@ -25,7 +24,7 @@ int mmap_cache_get(
struct stat *st,
void **ret,
size_t *ret_size);
MMapFileDescriptor * mmap_cache_add_fd(MMapCache *m, int fd);
MMapFileDescriptor * mmap_cache_add_fd(MMapCache *m, int fd, int prot);
void mmap_cache_free_fd(MMapCache *m, MMapFileDescriptor *f);
void mmap_cache_stats_log_debug(MMapCache *m);

View File

@ -24,7 +24,7 @@ int main(int argc, char *argv[]) {
assert_se(x >= 0);
unlink(px);
assert_se(fx = mmap_cache_add_fd(m, x));
assert_se(fx = mmap_cache_add_fd(m, x, PROT_READ));
y = mkostemp_safe(py);
assert_se(y >= 0);
@ -34,23 +34,23 @@ int main(int argc, char *argv[]) {
assert_se(z >= 0);
unlink(pz);
r = mmap_cache_get(m, fx, PROT_READ, 0, false, 1, 2, NULL, &p, NULL);
r = mmap_cache_get(m, fx, 0, false, 1, 2, NULL, &p, NULL);
assert_se(r >= 0);
r = mmap_cache_get(m, fx, PROT_READ, 0, false, 2, 2, NULL, &q, NULL);
r = mmap_cache_get(m, fx, 0, false, 2, 2, NULL, &q, NULL);
assert_se(r >= 0);
assert_se((uint8_t*) p + 1 == (uint8_t*) q);
r = mmap_cache_get(m, fx, PROT_READ, 1, false, 3, 2, NULL, &q, NULL);
r = mmap_cache_get(m, fx, 1, false, 3, 2, NULL, &q, NULL);
assert_se(r >= 0);
assert_se((uint8_t*) p + 2 == (uint8_t*) q);
r = mmap_cache_get(m, fx, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, NULL);
r = mmap_cache_get(m, fx, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, NULL);
assert_se(r >= 0);
r = mmap_cache_get(m, fx, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, NULL);
r = mmap_cache_get(m, fx, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, NULL);
assert_se(r >= 0);
assert_se((uint8_t*) p + 1 == (uint8_t*) q);

View File

@ -153,26 +153,40 @@ static bool address_may_have_broadcast(const Address *a) {
return a->family == AF_INET && in4_addr_is_null(&a->in_addr_peer.in) && a->prefixlen <= 30;
}
static uint32_t address_prefix(const Address *a) {
assert(a);
/* make sure we don't try to shift by 32.
* See ISO/IEC 9899:TC3 § 6.5.7.3. */
if (a->prefixlen == 0)
return 0;
if (a->in_addr_peer.in.s_addr != 0)
return be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
else
return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
}
void address_hash_func(const Address *a, struct siphash *state) {
assert(a);
siphash24_compress(&a->family, sizeof(a->family), state);
if (!IN_SET(a->family, AF_INET, AF_INET6))
/* treat non-IPv4 or IPv6 address family as AF_UNSPEC */
return;
switch (a->family) {
case AF_INET:
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
if (a->family == AF_INET)
siphash24_compress_string(a->label, state);
uint32_t prefix = address_prefix(a);
siphash24_compress(&prefix, sizeof(prefix), state);
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
/* local address */
siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
/* peer address */
siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
if (address_may_have_broadcast(a))
siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
_fallthrough_;
case AF_INET6:
siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
break;
default:
/* treat any other address family as AF_UNSPEC */
break;
}
}
int address_compare_func(const Address *a1, const Address *a2) {
@ -182,32 +196,25 @@ int address_compare_func(const Address *a1, const Address *a2) {
if (r != 0)
return r;
if (!IN_SET(a1->family, AF_INET, AF_INET6))
/* treat non-IPv4 or IPv6 address family as AF_UNSPEC */
return 0;
if (a1->family == AF_INET) {
r = strcmp_ptr(a1->label, a2->label);
switch (a1->family) {
case AF_INET:
/* See kernel's find_matching_ifa() in net/ipv4/devinet.c */
r = CMP(a1->prefixlen, a2->prefixlen);
if (r != 0)
return r;
r = CMP(address_prefix(a1), address_prefix(a2));
if (r != 0)
return r;
_fallthrough_;
case AF_INET6:
/* See kernel's ipv6_get_ifaddr() in net/ipv6/addrconf.c */
return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
default:
/* treat any other address family as AF_UNSPEC */
return 0;
}
r = CMP(a1->prefixlen, a2->prefixlen);
if (r != 0)
return r;
r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
r = memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
if (r != 0)
return r;
if (address_may_have_broadcast(a1))
return CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
return 0;
}
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
@ -440,29 +447,23 @@ int address_get(Link *link, const Address *in, Address **ret) {
return -ENOENT;
}
static bool address_exists_internal(Set *addresses, int family, const union in_addr_union *in_addr) {
Address *address;
int link_has_ipv6_address(Link *link, const struct in6_addr *address) {
_cleanup_(address_freep) Address *a = NULL;
int r;
SET_FOREACH(address, addresses) {
if (address->family != family)
continue;
if (in_addr_equal(address->family, &address->in_addr, in_addr))
return true;
}
return false;
}
bool address_exists(Link *link, int family, const union in_addr_union *in_addr) {
assert(link);
assert(IN_SET(family, AF_INET, AF_INET6));
assert(in_addr);
assert(address);
if (address_exists_internal(link->addresses, family, in_addr))
return true;
if (address_exists_internal(link->addresses_foreign, family, in_addr))
return true;
return false;
r = address_new(&a);
if (r < 0)
return r;
/* address_compare_func() only compares the local address for IPv6 case. So, it is enough to
* set only family and the address. */
a->family = AF_INET6;
a->in_addr.in6 = *address;
return address_get(link, a, NULL) >= 0;
}
static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {

View File

@ -49,7 +49,6 @@ typedef struct Address {
int address_new(Address **ret);
Address *address_free(Address *address);
int address_get(Link *link, const Address *in, Address **ret);
bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
int address_configure(const Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
int address_remove(const Address *address, Link *link, link_netlink_message_handler_t callback);
bool address_equal(const Address *a1, const Address *a2);
@ -63,6 +62,7 @@ int link_set_addresses(Link *link);
int link_drop_addresses(Link *link);
int link_drop_foreign_addresses(Link *link);
bool link_address_is_dynamic(const Link *link, const Address *address);
int link_has_ipv6_address(Link *link, const struct in6_addr *address);
void ipv4_dad_unref(Link *link);
int ipv4_dad_stop(Link *link);

View File

@ -969,6 +969,70 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
static void log_dhcp6_address(Link *link, const Address *address, char **ret) {
char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX];
const char *valid_str = NULL, *preferred_str = NULL;
_cleanup_free_ char *buffer = NULL;
bool by_ndisc = false;
Address *existing;
NDiscAddress *na;
int log_level, r;
assert(link);
assert(address);
(void) in_addr_to_string(address->family, &address->in_addr, &buffer);
if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
address->cinfo.ifa_valid * USEC_PER_SEC,
USEC_PER_SEC);
if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME)
preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX,
address->cinfo.ifa_prefered * USEC_PER_SEC,
USEC_PER_SEC);
r = address_get(link, address, &existing);
if (r < 0) {
/* New address. */
log_level = LOG_INFO;
goto simple_log;
} else
log_level = LOG_DEBUG;
if (set_contains(link->dhcp6_addresses, address))
/* Already warned. */
goto simple_log;
if (address->prefixlen == existing->prefixlen)
/* Currently, only conflict in prefix length is reported. */
goto simple_log;
SET_FOREACH(na, link->ndisc_addresses)
if (address_compare_func(na->address, existing)) {
by_ndisc = true;
break;
}
log_link_warning(link, "DHCPv6 address %s/%u (valid %s%s, preferred %s%s) conflicts the existing address %s/%u%s.",
strnull(buffer), address->prefixlen,
valid_str ? "for " : "forever", strempty(valid_str),
preferred_str ? "for " : "forever", strempty(preferred_str),
strnull(buffer), existing->prefixlen,
by_ndisc ? "assigned by NDISC. Please try to use or update IPv6Token= setting "
"to change the address generated by NDISC, or disable UseAutonomousPrefix=" : "");
goto finalize;
simple_log:
log_link_full(link, log_level, "DHCPv6 address %s/%u (valid %s%s, preferred %s%s)",
strnull(buffer), address->prefixlen,
valid_str ? "for " : "forever", strempty(valid_str),
preferred_str ? "for " : "forever", strempty(preferred_str));
finalize:
if (ret)
*ret = TAKE_PTR(buffer);
}
static int dhcp6_update_address(
Link *link,
const struct in6_addr *ip6_addr,
@ -991,22 +1055,19 @@ static int dhcp6_update_address(
addr->cinfo.ifa_prefered = lifetime_preferred;
addr->cinfo.ifa_valid = lifetime_valid;
(void) in_addr_to_string(addr->family, &addr->in_addr, &buffer);
log_link_full(link, set_contains(link->dhcp6_addresses, addr) ? LOG_DEBUG : LOG_INFO,
"DHCPv6 address %s/%u timeout preferred %d valid %d",
strna(buffer), addr->prefixlen, lifetime_preferred, lifetime_valid);
log_dhcp6_address(link, addr, &buffer);
r = address_configure(addr, link, dhcp6_address_handler, true, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s/%u: %m",
strna(buffer), addr->prefixlen);
strnull(buffer), addr->prefixlen);
link->dhcp6_address_messages++;
r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s/%u: %m",
strna(buffer), addr->prefixlen);
strnull(buffer), addr->prefixlen);
(void) set_remove(link->dhcp6_addresses_old, ret);

View File

@ -888,13 +888,17 @@ void manager_free(Manager *m) {
m->rules_foreign = set_free(m->rules_foreign);
set_free(m->rules_saved);
m->routes = set_free(m->routes);
m->routes_foreign = set_free(m->routes_foreign);
sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl);
sd_resolve_unref(m->resolve);
/* reject (e.g. unreachable) type routes are managed by Manager, but may be referenced by a
* link. E.g., DHCP6 with prefix delegation creates unreachable routes, and they are referenced
* by the upstream link. And the links may be referenced by netlink slots. Hence, two
* set_free() must be called after the above sd_netlink_unref(). */
m->routes = set_free(m->routes);
m->routes_foreign = set_free(m->routes_foreign);
sd_event_source_unref(m->speed_meter_event_source);
sd_event_unref(m->event);

View File

@ -483,7 +483,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
if (address_exists(link, AF_INET6, &gateway)) {
if (link_has_ipv6_address(link, &gateway.in6) > 0) {
if (DEBUG_LOGGING) {
_cleanup_free_ char *buffer = NULL;

View File

@ -159,10 +159,8 @@ static void test_address_equality(void) {
assert_se(in_addr_from_string(AF_INET, "192.168.3.9", &a2->in_addr) >= 0);
assert_se(address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.10", &a1->in_addr_peer) >= 0);
assert_se(!address_equal(a1, a2));
assert_se(address_equal(a1, a2));
assert_se(in_addr_from_string(AF_INET, "192.168.3.11", &a2->in_addr_peer) >= 0);
assert_se(!address_equal(a1, a2));
a2->in_addr_peer = a1->in_addr_peer;
assert_se(address_equal(a1, a2));
a1->prefixlen = 10;
assert_se(!address_equal(a1, a2));
@ -173,13 +171,10 @@ static void test_address_equality(void) {
assert_se(!address_equal(a1, a2));
a2->family = AF_INET6;
a1->in_addr_peer = a2->in_addr_peer = IN_ADDR_NULL;
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a1->in_addr) >= 0);
assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a2->in_addr) >= 0);
assert_se(address_equal(a1, a2));
a1->prefixlen = 8;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 8;
assert_se(address_equal(a1, a2));

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: LGPL-2+ */
/* SPDX-License-Identifier: LGPL-2.0-or-later */
/*
* initreq.h Interface to talk to init through /dev/initctl.
*

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/ether.h>

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/nl80211.h>

View File

@ -23,7 +23,8 @@
#include "string-util.h"
#include "strv.h"
const uint32_t seccomp_local_archs[] = {
/* This array will be modified at runtime as seccomp_restrict_archs is called. */
uint32_t seccomp_local_archs[] = {
/* Note: always list the native arch we are compiled as last, so that users can deny-list seccomp(), but our own calls to it still succeed */
@ -94,7 +95,7 @@ const uint32_t seccomp_local_archs[] = {
#elif defined(__s390__)
SCMP_ARCH_S390,
#endif
(uint32_t) -1
SECCOMP_LOCAL_ARCH_END
};
const char* seccomp_arch_to_string(uint32_t c) {
@ -1758,8 +1759,8 @@ int seccomp_memory_deny_write_execute(void) {
int seccomp_restrict_archs(Set *archs) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
void *id;
int r;
bool blocked_new = false;
/* This installs a filter with no rules, but that restricts the system call architectures to the specified
* list.
@ -1775,24 +1776,36 @@ int seccomp_restrict_archs(Set *archs) {
if (!seccomp)
return -ENOMEM;
SET_FOREACH(id, archs) {
r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
if (r < 0 && r != -EEXIST)
return r;
for (unsigned i = 0; seccomp_local_archs[i] != SECCOMP_LOCAL_ARCH_END; ++i) {
uint32_t arch = seccomp_local_archs[i];
/* That architecture might have already been blocked by a previous call to seccomp_restrict_archs. */
if (arch == SECCOMP_LOCAL_ARCH_BLOCKED)
continue;
bool block = !set_contains(archs, UINT32_TO_PTR(arch + 1));
/* The vdso for x32 assumes that x86-64 syscalls are available. Let's allow them, since x32
* x32 syscalls should basically match x86-64 for everything except the pointer type.
* The important thing is that you can block the old 32-bit x86 syscalls.
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850047 */
if (block && arch == SCMP_ARCH_X86_64 && seccomp_arch_native() == SCMP_ARCH_X32)
block = !set_contains(archs, UINT32_TO_PTR(SCMP_ARCH_X32 + 1));
if (block) {
seccomp_local_archs[i] = SECCOMP_LOCAL_ARCH_BLOCKED;
blocked_new = true;
} else {
r = seccomp_arch_add(seccomp, arch);
if (r < 0 && r != -EEXIST)
return r;
}
}
/* The vdso for x32 assumes that x86-64 syscalls are available. Let's allow them, since x32
* x32 syscalls should basically match x86-64 for everything except the pointer type.
* The important thing is that you can block the old 32-bit x86 syscalls.
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850047 */
if (seccomp_arch_native() == SCMP_ARCH_X32 ||
set_contains(archs, UINT32_TO_PTR(SCMP_ARCH_X32 + 1))) {
r = seccomp_arch_add(seccomp, SCMP_ARCH_X86_64);
if (r < 0 && r != -EEXIST)
return r;
}
/* All architectures that will be blocked by the seccomp program were
* already blocked. */
if (!blocked_new)
return 0;
r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
if (r < 0)

View File

@ -100,12 +100,20 @@ int seccomp_lock_personality(unsigned long personality);
int seccomp_protect_hostname(void);
int seccomp_restrict_suid_sgid(void);
extern const uint32_t seccomp_local_archs[];
extern uint32_t seccomp_local_archs[];
#define SECCOMP_LOCAL_ARCH_END UINT32_MAX
/* Note: 0 is safe to use here because although SCMP_ARCH_NATIVE is 0, it would
* never be in the seccomp_local_archs array anyway so we can use it as a
* marker. */
#define SECCOMP_LOCAL_ARCH_BLOCKED 0
#define SECCOMP_FOREACH_LOCAL_ARCH(arch) \
for (unsigned _i = ({ (arch) = seccomp_local_archs[0]; 0; }); \
seccomp_local_archs[_i] != (uint32_t) -1; \
(arch) = seccomp_local_archs[++_i])
(arch) != SECCOMP_LOCAL_ARCH_END; \
(arch) = seccomp_local_archs[++_i]) \
if ((arch) != SECCOMP_LOCAL_ARCH_BLOCKED)
/* EACCES: does not have the CAP_SYS_ADMIN or no_new_privs == 1
* ENOMEM: out of memory, failed to allocate space for a libseccomp structure, or would exceed a defined constant