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

Compare commits

..

No commits in common. "6597686865ffcba7450b44814618b94321cfa3cf" and "6bfbfce795e42c758e3ffc4d744c8b2a9a1da2b5" have entirely different histories.

18 changed files with 148 additions and 218 deletions

4
TODO
View File

@ -135,6 +135,10 @@ Features:
o move into separate libsystemd-shared-iptables.so .so o move into separate libsystemd-shared-iptables.so .so
- iptables-libs (only used by nspawn + networkd) - 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. * seccomp: maybe use seccomp_merge() to merge our filters per-arch if we can.
Apparently kernel performance is much better with fewer larger seccomp Apparently kernel performance is much better with fewer larger seccomp
filters than with more smaller seccomp filters. filters than with more smaller seccomp filters.

View File

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

View File

@ -63,6 +63,7 @@ typedef struct JournalFile {
mode_t mode; mode_t mode;
int flags; int flags;
int prot;
bool writable:1; bool writable:1;
bool compress_xz:1; bool compress_xz:1;
bool compress_lz4: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; c = (a + b) / 2;
r = mmap_cache_get(m, f, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL); r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -862,19 +862,19 @@ int journal_file_verify(
goto fail; goto fail;
} }
cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd, PROT_READ|PROT_WRITE); cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd);
if (!cache_data_fd) { if (!cache_data_fd) {
r = log_oom(); r = log_oom();
goto fail; goto fail;
} }
cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd, PROT_READ|PROT_WRITE); cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd);
if (!cache_entry_fd) { if (!cache_entry_fd) {
r = log_oom(); r = log_oom();
goto fail; goto fail;
} }
cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd, PROT_READ|PROT_WRITE); cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd);
if (!cache_entry_array_fd) { if (!cache_entry_array_fd) {
r = log_oom(); r = log_oom();
goto fail; goto fail;

View File

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

View File

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

View File

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

View File

@ -153,40 +153,26 @@ 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; 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) { void address_hash_func(const Address *a, struct siphash *state) {
assert(a); assert(a);
siphash24_compress(&a->family, sizeof(a->family), state); siphash24_compress(&a->family, sizeof(a->family), state);
switch (a->family) { if (!IN_SET(a->family, AF_INET, AF_INET6))
case AF_INET: /* treat non-IPv4 or IPv6 address family as AF_UNSPEC */
siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); return;
uint32_t prefix = address_prefix(a); if (a->family == AF_INET)
siphash24_compress(&prefix, sizeof(prefix), state); siphash24_compress_string(a->label, state);
_fallthrough_; siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
case AF_INET6: /* local address */
siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state); siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
break; /* peer address */
default: siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
/* treat any other address family as AF_UNSPEC */
break; if (address_may_have_broadcast(a))
} siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
} }
int address_compare_func(const Address *a1, const Address *a2) { int address_compare_func(const Address *a1, const Address *a2) {
@ -196,25 +182,32 @@ int address_compare_func(const Address *a1, const Address *a2) {
if (r != 0) if (r != 0)
return r; return r;
switch (a1->family) { if (!IN_SET(a1->family, AF_INET, AF_INET6))
case AF_INET: /* treat non-IPv4 or IPv6 address family as AF_UNSPEC */
/* 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; return 0;
if (a1->family == AF_INET) {
r = strcmp_ptr(a1->label, a2->label);
if (r != 0)
return r;
} }
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); DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
@ -447,23 +440,29 @@ int address_get(Link *link, const Address *in, Address **ret) {
return -ENOENT; return -ENOENT;
} }
int link_has_ipv6_address(Link *link, const struct in6_addr *address) { static bool address_exists_internal(Set *addresses, int family, const union in_addr_union *in_addr) {
_cleanup_(address_freep) Address *a = NULL; Address *address;
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(link);
assert(address); assert(IN_SET(family, AF_INET, AF_INET6));
assert(in_addr);
r = address_new(&a); if (address_exists_internal(link->addresses, family, in_addr))
if (r < 0) return true;
return r; if (address_exists_internal(link->addresses_foreign, family, in_addr))
return true;
/* address_compare_func() only compares the local address for IPv6 case. So, it is enough to return false;
* 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) { static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {

View File

@ -49,6 +49,7 @@ typedef struct Address {
int address_new(Address **ret); int address_new(Address **ret);
Address *address_free(Address *address); Address *address_free(Address *address);
int address_get(Link *link, const Address *in, Address **ret); 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_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); int address_remove(const Address *address, Link *link, link_netlink_message_handler_t callback);
bool address_equal(const Address *a1, const Address *a2); bool address_equal(const Address *a1, const Address *a2);
@ -62,7 +63,6 @@ int link_set_addresses(Link *link);
int link_drop_addresses(Link *link); int link_drop_addresses(Link *link);
int link_drop_foreign_addresses(Link *link); int link_drop_foreign_addresses(Link *link);
bool link_address_is_dynamic(const Link *link, const Address *address); 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); void ipv4_dad_unref(Link *link);
int ipv4_dad_stop(Link *link); int ipv4_dad_stop(Link *link);

View File

@ -969,70 +969,6 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1; 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( static int dhcp6_update_address(
Link *link, Link *link,
const struct in6_addr *ip6_addr, const struct in6_addr *ip6_addr,
@ -1055,19 +991,22 @@ static int dhcp6_update_address(
addr->cinfo.ifa_prefered = lifetime_preferred; addr->cinfo.ifa_prefered = lifetime_preferred;
addr->cinfo.ifa_valid = lifetime_valid; addr->cinfo.ifa_valid = lifetime_valid;
log_dhcp6_address(link, addr, &buffer); (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);
r = address_configure(addr, link, dhcp6_address_handler, true, &ret); r = address_configure(addr, link, dhcp6_address_handler, true, &ret);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s/%u: %m", return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s/%u: %m",
strnull(buffer), addr->prefixlen); strna(buffer), addr->prefixlen);
link->dhcp6_address_messages++; link->dhcp6_address_messages++;
r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, ret); r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, ret);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s/%u: %m", return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s/%u: %m",
strnull(buffer), addr->prefixlen); strna(buffer), addr->prefixlen);
(void) set_remove(link->dhcp6_addresses_old, ret); (void) set_remove(link->dhcp6_addresses_old, ret);

View File

@ -888,17 +888,13 @@ void manager_free(Manager *m) {
m->rules_foreign = set_free(m->rules_foreign); m->rules_foreign = set_free(m->rules_foreign);
set_free(m->rules_saved); 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->rtnl);
sd_netlink_unref(m->genl); sd_netlink_unref(m->genl);
sd_resolve_unref(m->resolve); 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_source_unref(m->speed_meter_event_source);
sd_event_unref(m->event); 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) if (r < 0)
return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m"); return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
if (link_has_ipv6_address(link, &gateway.in6) > 0) { if (address_exists(link, AF_INET6, &gateway)) {
if (DEBUG_LOGGING) { if (DEBUG_LOGGING) {
_cleanup_free_ char *buffer = NULL; _cleanup_free_ char *buffer = NULL;

View File

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

View File

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

View File

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

View File

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

View File

@ -23,8 +23,7 @@
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
/* This array will be modified at runtime as seccomp_restrict_archs is called. */ const uint32_t seccomp_local_archs[] = {
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 */ /* 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 */
@ -95,7 +94,7 @@ uint32_t seccomp_local_archs[] = {
#elif defined(__s390__) #elif defined(__s390__)
SCMP_ARCH_S390, SCMP_ARCH_S390,
#endif #endif
SECCOMP_LOCAL_ARCH_END (uint32_t) -1
}; };
const char* seccomp_arch_to_string(uint32_t c) { const char* seccomp_arch_to_string(uint32_t c) {
@ -1759,8 +1758,8 @@ int seccomp_memory_deny_write_execute(void) {
int seccomp_restrict_archs(Set *archs) { int seccomp_restrict_archs(Set *archs) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
void *id;
int r; int r;
bool blocked_new = false;
/* This installs a filter with no rules, but that restricts the system call architectures to the specified /* This installs a filter with no rules, but that restricts the system call architectures to the specified
* list. * list.
@ -1776,36 +1775,24 @@ int seccomp_restrict_archs(Set *archs) {
if (!seccomp) if (!seccomp)
return -ENOMEM; return -ENOMEM;
for (unsigned i = 0; seccomp_local_archs[i] != SECCOMP_LOCAL_ARCH_END; ++i) { SET_FOREACH(id, archs) {
uint32_t arch = seccomp_local_archs[i]; r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
if (r < 0 && r != -EEXIST)
/* That architecture might have already been blocked by a previous call to seccomp_restrict_archs. */ return r;
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;
}
} }
/* All architectures that will be blocked by the seccomp program were /* The vdso for x32 assumes that x86-64 syscalls are available. Let's allow them, since x32
* already blocked. */ * x32 syscalls should basically match x86-64 for everything except the pointer type.
if (!blocked_new) * The important thing is that you can block the old 32-bit x86 syscalls.
return 0; * 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;
}
r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
if (r < 0) if (r < 0)

View File

@ -100,20 +100,12 @@ int seccomp_lock_personality(unsigned long personality);
int seccomp_protect_hostname(void); int seccomp_protect_hostname(void);
int seccomp_restrict_suid_sgid(void); int seccomp_restrict_suid_sgid(void);
extern uint32_t seccomp_local_archs[]; extern const 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) \ #define SECCOMP_FOREACH_LOCAL_ARCH(arch) \
for (unsigned _i = ({ (arch) = seccomp_local_archs[0]; 0; }); \ for (unsigned _i = ({ (arch) = seccomp_local_archs[0]; 0; }); \
(arch) != SECCOMP_LOCAL_ARCH_END; \ seccomp_local_archs[_i] != (uint32_t) -1; \
(arch) = seccomp_local_archs[++_i]) \ (arch) = seccomp_local_archs[++_i])
if ((arch) != SECCOMP_LOCAL_ARCH_BLOCKED)
/* EACCES: does not have the CAP_SYS_ADMIN or no_new_privs == 1 /* 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 * ENOMEM: out of memory, failed to allocate space for a libseccomp structure, or would exceed a defined constant