mirror of
https://github.com/systemd/systemd
synced 2025-09-28 00:04:47 +02:00
Compare commits
9 Commits
6bfbfce795
...
6597686865
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6597686865 | ||
![]() |
104fc4be11 | ||
![]() |
cca2da15c8 | ||
![]() |
8620022f28 | ||
![]() |
073f50a099 | ||
![]() |
b432080dc8 | ||
![]() |
450fa34bd0 | ||
![]() |
c5a0aeb33a | ||
![]() |
1d30fc5cb6 |
4
TODO
4
TODO
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
if (a->family == AF_INET)
|
||||
siphash24_compress_string(a->label, state);
|
||||
|
||||
switch (a->family) {
|
||||
case AF_INET:
|
||||
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);
|
||||
uint32_t prefix = address_prefix(a);
|
||||
siphash24_compress(&prefix, sizeof(prefix), 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);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
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 = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
|
||||
r = CMP(address_prefix(a1), address_prefix(a2));
|
||||
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);
|
||||
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <netinet/ether.h>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
@ -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 (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 (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
|
||||
* already blocked. */
|
||||
if (!blocked_new)
|
||||
return 0;
|
||||
|
||||
r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
|
||||
if (r < 0)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user