systemd: merge branch systemd into main

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/897
This commit is contained in:
Thomas Haller 2021-06-17 16:48:12 +02:00
commit fbf3952274
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
24 changed files with 222 additions and 137 deletions

View file

@ -14,6 +14,7 @@
#include "network-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "udev-util.h"
#include "virt.h"
@ -166,38 +167,40 @@ int dhcp_identifier_set_iaid(
const uint8_t *mac,
size_t mac_len,
bool legacy_unstable_byteorder,
bool use_mac,
void *_id) {
#if 0 /* NM_IGNORED */
/* name is a pointer to memory in the sd_device struct, so must
* have the same scope */
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *name = NULL;
uint64_t id;
uint32_t id32;
uint64_t id;
int r;
if (detect_container() <= 0) {
/* not in a container, udev will be around */
char ifindex_str[1 + DECIMAL_STR_MAX(int)];
int r;
if (path_is_read_only_fs("/sys") <= 0 && !use_mac) {
/* udev should be around */
xsprintf(ifindex_str, "n%d", ifindex);
if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) {
r = sd_device_get_is_initialized(device);
if (r < 0)
return r;
if (r == 0)
/* not yet ready */
return -EBUSY;
r = sd_device_new_from_ifindex(&device, ifindex);
if (r < 0)
return r;
r = device_is_renaming(device);
if (r < 0)
return r;
if (r > 0)
/* device is under renaming */
return -EBUSY;
r = sd_device_get_is_initialized(device);
if (r < 0)
return r;
if (r == 0)
/* not yet ready */
return -EBUSY;
name = net_get_name_persistent(device);
}
r = device_is_renaming(device);
if (r < 0)
return r;
if (r > 0)
/* device is under renaming */
return -EBUSY;
name = net_get_name_persistent(device);
}
if (name)

View file

@ -59,4 +59,4 @@ int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *add
int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len);
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len);
int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, void *_id);
int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, bool use_mac, void *_id);

View file

@ -30,6 +30,8 @@ typedef struct DHCPServerData {
extern const struct hash_ops dhcp_option_hash_ops;
typedef struct sd_dhcp_client sd_dhcp_client;
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
const uint8_t *mac_addr, size_t mac_addr_len,
const uint8_t *bcast_addr, size_t bcast_addr_len,
@ -62,6 +64,8 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode);
/* If we are invoking callbacks of a dhcp-client, ensure unreffing the
* client from the callback doesn't destroy the object we are working
* on */

View file

@ -91,6 +91,8 @@ typedef struct DHCP6IA {
LIST_HEAD(DHCP6Address, addresses);
} DHCP6IA;
typedef struct sd_dhcp6_client sd_dhcp6_client;
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval);
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
@ -118,6 +120,8 @@ int dhcp6_message_type_from_string(const char *s) _pure_;
const char *dhcp6_message_status_to_string(int s) _const_;
int dhcp6_message_status_from_string(const char *s) _pure_;
void dhcp6_client_set_test_mode(sd_dhcp6_client *client, bool test_mode);
#define log_dhcp6_client_errno(client, error, fmt, ...) \
log_interface_prefix_full_errno( \
"DHCPv6 client: ", \

View file

@ -119,6 +119,9 @@ struct sd_dhcp_client {
sd_dhcp_lease *lease;
usec_t start_delay;
int ip_service_type;
/* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
bool test_mode;
};
static const uint8_t default_req_opts[] = {
@ -470,7 +473,8 @@ static int dhcp_client_set_iaid_duid_internal(
else {
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
client->mac_addr_len,
true,
/* legacy_unstable_byteorder = */ true,
/* use_mac = */ client->test_mode,
&client->client_id.ns.iaid);
if (r < 0)
return log_dhcp_client_errno(client, r, "Failed to set IAID: %m");
@ -560,6 +564,12 @@ int sd_dhcp_client_set_duid_llt(
}
#endif /* NM_IGNORED */
void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode) {
assert(client);
client->test_mode = test_mode;
}
int sd_dhcp_client_set_hostname(
sd_dhcp_client *client,
const char *hostname) {
@ -865,7 +875,9 @@ static int client_message_init(
client->client_id.type = 255;
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
true, &client->client_id.ns.iaid);
/* legacy_unstable_byteorder = */ true,
/* use_mac = */ client->test_mode,
&client->client_id.ns.iaid);
if (r < 0)
return r;

View file

@ -90,6 +90,9 @@ struct sd_dhcp6_client {
usec_t information_refresh_time_usec;
OrderedHashmap *extra_options;
OrderedHashmap *vendor_options;
/* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
bool test_mode;
};
static const uint16_t default_req_opts[] = {
@ -408,6 +411,12 @@ int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
return 0;
}
void dhcp6_client_set_test_mode(sd_dhcp6_client *client, bool test_mode) {
assert(client);
client->test_mode = test_mode;
}
int sd_dhcp6_client_get_iaid(sd_dhcp6_client *client, uint32_t *iaid) {
assert_return(client, -EINVAL);
assert_return(iaid, -EINVAL);
@ -1083,7 +1092,10 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
if (client->iaid_set)
return 0;
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
/* legacy_unstable_byteorder = */ true,
/* use_mac = */ client->test_mode,
&iaid);
if (r < 0)
return r;

View file

@ -170,10 +170,9 @@ static int pending_prioq_compare(const void *a, const void *b) {
assert(y->pending);
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
if (r != 0)
return r;
/* Non rate-limited ones first. */
r = CMP(!!x->ratelimited, !!y->ratelimited);
@ -197,10 +196,9 @@ static int prepare_prioq_compare(const void *a, const void *b) {
assert(y->prepare);
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
if (r != 0)
return r;
/* Non rate-limited ones first. */
r = CMP(!!x->ratelimited, !!y->ratelimited);
@ -239,25 +237,6 @@ static usec_t time_event_source_next(const sd_event_source *s) {
return USEC_INFINITY;
}
static int earliest_time_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
/* Move the pending ones to the end */
if (!x->pending && y->pending)
return -1;
if (x->pending && !y->pending)
return 1;
/* Order by time */
return CMP(time_event_source_next(x), time_event_source_next(y));
}
static usec_t time_event_source_latest(const sd_event_source *s) {
assert(s);
@ -276,36 +255,51 @@ static usec_t time_event_source_latest(const sd_event_source *s) {
return USEC_INFINITY;
}
static int latest_time_prioq_compare(const void *a, const void *b) {
static bool event_source_timer_candidate(const sd_event_source *s) {
assert(s);
/* Returns true for event sources that either are not pending yet (i.e. where it's worth to mark them pending)
* or which are currently ratelimited (i.e. where it's worth leaving the ratelimited state) */
return !s->pending || s->ratelimited;
}
static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) {
const sd_event_source *x = a, *y = b;
int r;
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
if (r != 0)
return r;
/* Move the pending ones to the end */
if (!x->pending && y->pending)
return -1;
if (x->pending && !y->pending)
return 1;
/* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */
r = CMP(!event_source_timer_candidate(x), !event_source_timer_candidate(y));
if (r != 0)
return r;
/* Order by time */
return CMP(time_event_source_latest(x), time_event_source_latest(y));
return CMP(time_func(x), time_func(y));
}
static int earliest_time_prioq_compare(const void *a, const void *b) {
return time_prioq_compare(a, b, time_event_source_next);
}
static int latest_time_prioq_compare(const void *a, const void *b) {
return time_prioq_compare(a, b, time_event_source_latest);
}
static int exit_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
int r;
assert(x->type == SOURCE_EXIT);
assert(y->type == SOURCE_EXIT);
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF);
if (r != 0)
return r;
/* Lower priority values first */
return CMP(x->priority, y->priority);
@ -779,14 +773,15 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) {
assert(s);
/* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
* pending, enable state. Makes sure the two prioq's are ordered properly again. */
* pending, enable state, and ratelimiting state. Makes sure the two prioq's are ordered
* properly again. */
if (s->ratelimited)
d = &s->event->monotonic;
else {
assert(EVENT_SOURCE_IS_TIME(s->type));
else if (EVENT_SOURCE_IS_TIME(s->type))
assert_se(d = event_get_clock_data(s->event, s->type));
}
else
return; /* no-op for an event source which is neither a timer nor ratelimited. */
prioq_reshuffle(d->earliest, s, &s->earliest_index);
prioq_reshuffle(d->latest, s, &s->latest_index);
@ -2379,14 +2374,6 @@ static int event_source_offline(
source_io_unregister(s);
break;
case SOURCE_TIME_REALTIME:
case SOURCE_TIME_BOOTTIME:
case SOURCE_TIME_MONOTONIC:
case SOURCE_TIME_REALTIME_ALARM:
case SOURCE_TIME_BOOTTIME_ALARM:
event_source_time_prioq_reshuffle(s);
break;
case SOURCE_SIGNAL:
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
break;
@ -2407,6 +2394,11 @@ static int event_source_offline(
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
break;
case SOURCE_TIME_REALTIME:
case SOURCE_TIME_BOOTTIME:
case SOURCE_TIME_MONOTONIC:
case SOURCE_TIME_REALTIME_ALARM:
case SOURCE_TIME_BOOTTIME_ALARM:
case SOURCE_DEFER:
case SOURCE_POST:
case SOURCE_INOTIFY:
@ -2416,6 +2408,9 @@ static int event_source_offline(
assert_not_reached("Wut? I shouldn't exist.");
}
/* Always reshuffle time prioq, as the ratelimited flag may be changed. */
event_source_time_prioq_reshuffle(s);
return 1;
}
@ -2505,22 +2500,11 @@ static int event_source_online(
s->ratelimited = ratelimited;
/* Non-failing operations below */
switch (s->type) {
case SOURCE_TIME_REALTIME:
case SOURCE_TIME_BOOTTIME:
case SOURCE_TIME_MONOTONIC:
case SOURCE_TIME_REALTIME_ALARM:
case SOURCE_TIME_BOOTTIME_ALARM:
event_source_time_prioq_reshuffle(s);
break;
case SOURCE_EXIT:
if (s->type == SOURCE_EXIT)
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
break;
default:
break;
}
/* Always reshuffle time prioq, as the ratelimited flag may be changed. */
event_source_time_prioq_reshuffle(s);
return 1;
}
@ -2990,8 +2974,8 @@ static int event_arm_timer(
if (!d->needs_rearm)
return 0;
else
d->needs_rearm = false;
d->needs_rearm = false;
a = prioq_peek(d->earliest);
if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
@ -3687,8 +3671,8 @@ static int arm_watchdog(sd_event *e) {
assert(e->watchdog_fd >= 0);
t = sleep_between(e,
e->watchdog_last + (e->watchdog_period / 2),
e->watchdog_last + (e->watchdog_period * 3 / 4));
usec_add(e->watchdog_last, (e->watchdog_period / 2)),
usec_add(e->watchdog_last, (e->watchdog_period * 3 / 4)));
timespec_store(&its.it_value, t);

View file

@ -63,7 +63,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15]
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format (Strictly Big Endian byte order,
* i.e. treats everything as RFC4122 Variant 1 UUIDs, even if variant says otherwise, but matching other
* Linux userspace behaviour.) */
#define SD_ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define SD_ID128_CONST_STR(x) \
@ -105,6 +107,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#define SD_ID128_MAKE_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
#a #b #c #d #e #f #g #h #i #j #k #l #m #n #o #p
#define SD_ID128_MAKE_UUID_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
#a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p
_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
return memcmp(&a, &b, 16) == 0;
}

View file

@ -79,6 +79,13 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
memcpy_safe(_q_, p, _l_); \
})
static inline void unsetp(void *p) {
/* A trivial "destructor" that can be used in cases where we want to
* unset a pointer from a _cleanup_ function. */
*(void**)p = NULL;
}
static inline void freep(void *p) {
*(void**)p = mfree(*(void**) p);
}

View file

@ -12,13 +12,13 @@
#include "macro.h"
#include "string-util.h"
char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
assert(addr);
assert(buffer);
assert(addr->length <= HW_ADDR_MAX_SIZE);
for (size_t i = 0; i < addr->length; i++) {
sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]);
sprintf(&buffer[3*i], "%02"PRIx8, addr->bytes[i]);
if (i < addr->length - 1)
buffer[3*i + 2] = ':';
}
@ -26,6 +26,19 @@ char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_
return buffer;
}
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) {
int r;
assert(a);
assert(b);
r = CMP(a->length, b->length);
if (r != 0)
return r;
return memcmp(a->bytes, b->bytes, a->length);
}
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
assert(addr);
assert(buffer);

View file

@ -11,24 +11,30 @@
* defines a macro of the same name with a much lower size. */
#define HW_ADDR_MAX_SIZE 32
union hw_addr_union {
struct ether_addr ether;
uint8_t infiniband[INFINIBAND_ALEN];
uint8_t bytes[HW_ADDR_MAX_SIZE];
struct hw_addr_data {
size_t length;
union {
struct ether_addr ether;
uint8_t infiniband[INFINIBAND_ALEN];
uint8_t bytes[HW_ADDR_MAX_SIZE];
};
};
typedef struct hw_addr_data {
union hw_addr_union addr;
size_t length;
} hw_addr_data;
#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
/* Use only as function argument, never stand-alone! */
#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
#define HW_ADDR_NULL ((const hw_addr_data){})
#define HW_ADDR_NULL ((const struct hw_addr_data){})
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b);
static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) {
return hw_addr_compare(a, b) == 0;
}
static inline bool hw_addr_is_null(const struct hw_addr_data *addr) {
return hw_addr_equal(addr, &HW_ADDR_NULL);
}
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
@ -36,6 +42,8 @@ char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_
#define ETHER_ADDR_TO_STRING_MAX (3*6)
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
int ether_addr_to_string_alloc(const struct ether_addr *addr, char **ret);
/* Use only as function argument, never stand-alone! */
#define ETHER_ADDR_TO_STR(addr) ether_addr_to_string((addr), (char[ETHER_ADDR_TO_STRING_MAX]){})
int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b);
static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {

View file

@ -29,8 +29,17 @@
#include "string-util.h"
#include "tmpfile-util.h"
/* The maximum size of the file we'll read in one go. */
#define READ_FULL_BYTES_MAX (4U*1024U*1024U - 1)
/* The maximum size of the file we'll read in one go in read_full_file() (64M). */
#define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U)
/* The maximum size of virtual files we'll read in one go in read_virtual_file() (4M). Note that this limit
* is different (and much lower) than the READ_FULL_BYTES_MAX limit. This reflects the fact that we use
* different strategies for reading virtual and regular files: virtual files are generally size constrained:
* there we allocate the full buffer size in advance. Regular files OTOH can be much larger, and here we grow
* the allocations exponentially in a loop. In glibc large allocations are immediately backed by mmap()
* making them relatively slow (measurably so). Thus, when allocating the full buffer in advance the large
* limit is a problem. When allocating piecemeal it's not. Hence pick two distinct limits. */
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 1U)
int fopen_unlocked(const char *path, const char *options, FILE **ret) {
assert(ret);
@ -392,7 +401,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
if (fd < 0)
return -errno;
assert(max_size <= READ_FULL_BYTES_MAX || max_size == SIZE_MAX);
assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX);
/* Limit the number of attempts to read the number of bytes returned by fstat(). */
n_retries = 3;
@ -407,7 +416,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
return -EBADF;
/* Be prepared for files from /proc which generally report a file size of 0. */
assert_cc(READ_FULL_BYTES_MAX < SSIZE_MAX);
assert_cc(READ_VIRTUAL_BYTES_MAX < SSIZE_MAX);
if (st.st_size > 0 && n_retries > 1) {
/* Let's use the file size if we have more than 1 attempt left. On the last attempt
* we'll ignore the file size */
@ -421,13 +430,13 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
} else {
size = MIN((size_t) st.st_size, max_size);
if (size > READ_FULL_BYTES_MAX)
if (size > READ_VIRTUAL_BYTES_MAX)
return -EFBIG;
}
n_retries--;
} else {
size = MIN(READ_FULL_BYTES_MAX, max_size);
size = MIN(READ_VIRTUAL_BYTES_MAX, max_size);
n_retries = 0;
}
@ -436,7 +445,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
return -ENOMEM;
/* Use a bigger allocation if we got it anyway, but not more than the limit. */
size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_FULL_BYTES_MAX);
size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_VIRTUAL_BYTES_MAX);
for (;;) {
ssize_t k;
@ -576,7 +585,7 @@ int read_full_stream_full(
}
memcpy_safe(t, buf, n);
explicit_bzero_safe(buf, n);
buf = mfree(buf);
free(buf);
} else {
t = realloc(buf, n_next + 1);
if (!t)

View file

@ -744,7 +744,7 @@ int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
return wd;
}
static bool unsafe_transition(const struct stat *a, const struct stat *b) {
bool unsafe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
* making us believe we read something safe even though it isn't safe in the specific context we open it in. */

View file

@ -94,6 +94,8 @@ enum {
CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered */
};
bool unsafe_transition(const struct stat *a, const struct stat *b);
/* How many iterations to execute before returning -ELOOP */
#define CHASE_SYMLINKS_MAX 32

View file

@ -530,6 +530,16 @@ char base64char(int x) {
}
#endif /* NM_IGNORED */
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet,
* since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
* See section #5 of RFC 4648. */
char urlsafe_base64char(int x) {
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_";
return table[x & 63];
}
int unbase64char(char c) {
unsigned offset;

View file

@ -27,6 +27,7 @@ char base32hexchar(int x) _const_;
int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
char urlsafe_base64char(int x) _const_;
int unbase64char(char c) _const_;
char *base32hexmem(const void *p, size_t l, bool padding);

View file

@ -123,6 +123,12 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
return -EAFNOSUPPORT;
}
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
return a->s6_addr32[0] == 0 &&
a->s6_addr32[1] == 0 &&
a->s6_addr32[2] == htobe32(UINT32_C(0x0000ffff));
}
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
assert(a);
assert(b);

View file

@ -58,6 +58,7 @@ int in_addr_is_localhost(int family, const union in_addr_union *u);
bool in4_addr_is_local_multicast(const struct in_addr *a);
bool in4_addr_is_non_local(const struct in_addr *a);
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a);
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b);

View file

@ -722,7 +722,7 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
}
bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
bool changed = false;
bool changed = false, originally_unset;
const char* const* i;
assert(timestamp);
@ -730,6 +730,8 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
if (!paths)
return false;
originally_unset = *timestamp == 0;
STRV_FOREACH(i, paths) {
struct stat stats;
usec_t u;
@ -739,11 +741,11 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
u = timespec_load(&stats.st_mtim);
/* first check */
/* check first */
if (*timestamp >= u)
continue;
log_debug("timestamp of '%s' changed", *i);
log_debug(originally_unset ? "Loaded timestamp for '%s'." : "Timestamp of '%s' changed.", *i);
/* update timestamp */
if (update) {

View file

@ -826,7 +826,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
/* Assuming we woke due to the child exiting. */
if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
if (status.si_pid == pid) {
/* This is the correct child.*/
/* This is the correct child. */
if (status.si_code == CLD_EXITED)
return (status.si_status == 0) ? 0 : -EPROTO;
else

View file

@ -190,7 +190,7 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
* invocations or so. That's because we don't really care about the quality here. We
* generally prefer using RDRAND if the caller allows us to, since this way we won't upset
* the kernel's random subsystem by accessing it before the pool is initialized (after all it
* will kmsg log about every attempt to do so)..*/
* will kmsg log about every attempt to do so). */
for (;;) {
unsigned long u;
size_t m;

View file

@ -112,7 +112,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
/* If there's no embedded NUL byte, then the size needs to match the whole
* structure or the structure with one extra NUL byte suffixed. (Yeah, Linux is awful,
* and considers both equivalent: getsockname() even extends sockaddr_un beyond its
* size if the path is non NUL terminated.)*/
* size if the path is non NUL terminated.) */
if (!IN_SET(a->size, sizeof(a->sockaddr.un.sun_path), sizeof(a->sockaddr.un.sun_path)+1))
return -EINVAL;
}
@ -1204,7 +1204,7 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
/* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than
* the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket
* addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that
* do not expect non-NUL terminated file system path*/
* do not expect non-NUL terminated file system path. */
if (l+1 > sizeof(ret->sun_path))
return -EINVAL;

View file

@ -1035,7 +1035,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
if (s == p && *s != '\0')
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */
return -EINVAL;
p = s;
@ -1063,7 +1063,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
r += k;
}
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
if (b == e + 1)
return -EINVAL;
}
@ -1210,7 +1210,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
if (s == p && *s != '\0')
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */
return -EINVAL;
p = s;
@ -1238,7 +1238,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
r += k;
}
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */
if (b == e + 1)
return -EINVAL;
}
@ -1445,7 +1445,7 @@ int get_timezone(char **ret) {
r = readlink_malloc("/etc/localtime", &t);
if (r == -ENOENT) {
/* If the symlink does not exist, assume "UTC", like glibc does*/
/* If the symlink does not exist, assume "UTC", like glibc does */
z = strdup("UTC");
if (!z)
return -ENOMEM;

View file

@ -79,6 +79,7 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
return (sd_char*) s + sl - pl;
}
#if 0 /* NM_IGNORED */
#ifdef SD_BOOT
static sd_bool isdigit(sd_char a) {
return a >= '0' && a <= '9';
@ -154,7 +155,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
* Note that except for '~' prefixed segments, a string has more segments is newer.
* So, this check must be after the '~' check. */
if (*a == '\0' || *b == '\0')
return strcmp(a, b);
return CMP(*a, *b);
/* Handle '-', which separates version and release, e.g 123.4-3.1.fc33.x86_64 */
if (*a == '-' || *b == '-') {
@ -196,9 +197,9 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
/* Find the leading numeric segments. One may be an empty string. So,
* numeric segments are always newer than alpha segments. */
for (aa = a; *aa != '\0' && isdigit(*aa); aa++)
for (aa = a; isdigit(*aa); aa++)
;
for (bb = b; *bb != '\0' && isdigit(*bb); bb++)
for (bb = b; isdigit(*bb); bb++)
;
/* To compare numeric segments without parsing their values, first compare the
@ -213,9 +214,9 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
return r;
} else {
/* Find the leading non-numeric segments. */
for (aa = a; *aa != '\0' && is_alpha(*aa); aa++)
for (aa = a; is_alpha(*aa); aa++)
;
for (bb = b; *bb != '\0' && is_alpha(*bb); bb++)
for (bb = b; is_alpha(*bb); bb++)
;
/* Note that the segments are usually not NUL-terminated. */
@ -234,3 +235,4 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
b = bb;
}
}
#endif /* NM_IGNORED */