diff options
-rw-r--r-- | NEWS | 14 | ||||
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | docs/.gitignore | 1 | ||||
-rw-r--r-- | man/sd_bus_default.xml | 2 | ||||
-rw-r--r-- | man/systemd.network.xml | 17 | ||||
-rw-r--r-- | src/basic/fileio.c | 11 | ||||
-rw-r--r-- | src/basic/fileio.h | 2 | ||||
-rw-r--r-- | src/basic/process-util.c | 3 | ||||
-rw-r--r-- | src/bus-proxyd/proxy.c | 18 | ||||
-rw-r--r-- | src/core/job.c | 4 | ||||
-rw-r--r-- | src/core/service.c | 2 | ||||
-rw-r--r-- | src/libsystemd-network/sd-lldp.c | 2 | ||||
-rw-r--r-- | src/libsystemd-terminal/grdev-drm.c | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-control.c | 29 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/kdbus.h | 1 | ||||
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-internal.h | 2 | ||||
-rw-r--r-- | src/login/71-seat.rules.in | 2 | ||||
-rw-r--r-- | src/network/networkd-link.c | 75 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 131 | ||||
-rw-r--r-- | src/network/networkd-network.c | 58 | ||||
-rw-r--r-- | src/network/networkd.h | 18 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 48 | ||||
-rw-r--r-- | src/test/test-pty.c | 2 |
23 files changed, 350 insertions, 100 deletions
@@ -1,6 +1,7 @@ systemd System and Service Manager CHANGES WITH 222: + * udev does not longer support the WAIT_FOR_SYSFS= key in udev rules. There are no known issues with current sysfs, and udev does not need or should be used to work around such bugs. @@ -14,17 +15,22 @@ CHANGES WITH 222: accelerometer/orientation data with this systemd version. Please upgrade iio-sensor-proxy to version 1.0. + * networkd gained a new configuration option IPv6PrivacyExtensions= + which enables IPv6 privacy extensions (RFC 4941, "Privacy Extensions + for Stateless Address") on selected networks. + Contributions from: Abdo Roig-Maranges, Andrew Eikum, Bastien Nocera, Cédric Delmas, Christian Hesse, Christos Trochalakis, Daniel Mack, daurnimator, David Herrmann, Dimitri John Ledkov, Eric Biggers, Eric Cook, Felipe Sateler, Geert Jansen, Gerd Hoffmann, Gianpaolo Macario, - Greg Kroah-Hartman, Iago López Galeiras, Jan Alexander Steffens, - Jan Engelhardt, Jay Strict, Kay Sievers, Lennart Poettering, + Greg Kroah-Hartman, Iago López Galeiras, Jan Alexander Steffens + (heftig), Jan Engelhardt, Jay Strict, Kay Sievers, Lennart Poettering, Markus Knetschke, Martin Pitt, Michael Biebl, Michael Marineau, Michal Sekletar, Miguel Bernal Marin, Peter Hutterer, Richard Maw, rinrinne, - Tom Gundersen, Vedran Miletić, WaLyong Cho, Zbigniew Jędrzejewski-Szmek + Susant Sahani, Tom Gundersen, Torstein Husebø, Vedran Miletić, WaLyong + Cho, Zbigniew Jędrzejewski-Szmek - -- Berlin, 2015-07-XX + -- Berlin, 2015-07-06 CHANGES WITH 221: @@ -26,6 +26,8 @@ External: Features: +* consider throwing a warning if a service declares it wants to be "Before=" a .device unit. + * "systemctl edit" should know a mode to create a new unit file * there's probably something wrong with having user mounts below /sys, @@ -49,8 +51,6 @@ Features: * install: include generator dirs in unit file search paths -* networkd: add support for configuring ipv6 privacy extensions - * introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used. * stop using off_t, it's a crazy type. Use uint64_t instead. diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..35b5e99aee --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +/html diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml index c5a1b530f9..95b347bdfd 100644 --- a/man/sd_bus_default.xml +++ b/man/sd_bus_default.xml @@ -182,7 +182,7 @@ processes at this time.</para> <para>These calls allocate a bus connection object and initiate - the connection ot a well-known bus of some form. An alternative to + the connection to a well-known bus of some form. An alternative to using these high-level calls is to create an unconnected bus object with <citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry> diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 71ced09696..ff01da6249 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -392,6 +392,23 @@ <literal>no</literal>.</para></listitem> </varlistentry> <varlistentry> + <term><varname>IPv6PrivacyExtensions=</varname></term> + <listitem><para>Configures use of stateless temporary + addresses that change over time (see <ulink + url="https://tools.ietf.org/html/rfc4941">RFC 4941</ulink>, + Privacy Extensions for Stateless Address Autoconfiguration + in IPv6). Takes a boolean or the special values + <literal>prefer-public</literal> and + <literal>kernel</literal>. When true enables the privacy + extensions and prefers temporary addresses over public + addresses. When <literal>prefer-public</literal> enables the + privacy extensions, but prefers public addresses over + temporary addresses. When false, the privacy extensions + remain disabled. When <literal>kernel</literal> the kernel's + default setting will be left in place. Defaults to + <literal>no</literal>.</para></listitem> + </varlistentry> + <varlistentry> <term><varname>Bridge=</varname></term> <listitem> <para>The name of the bridge to add the link to.</para> diff --git a/src/basic/fileio.c b/src/basic/fileio.c index ff6b1a7ed7..00fb6f8b5c 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -134,6 +134,17 @@ int read_one_line_file(const char *fn, char **line) { return 0; } +int verify_one_line_file(const char *fn, const char *line) { + _cleanup_free_ char *value = NULL; + int r; + + r = read_one_line_file(fn, &value); + if (r < 0) + return r; + + return streq(value, line); +} + int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 5ae51c1e28..91d4a0d2d5 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -34,6 +34,8 @@ int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); +int verify_one_line_file(const char *fn, const char *line); + int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index cfc876567d..2c05f2fee4 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -329,6 +329,9 @@ int get_process_environ(pid_t pid, char **env) { sz += cescape_char(c, outcome + sz); } + if (sz == 0) + return -ENOENT; + outcome[sz] = '\0'; *env = outcome; outcome = NULL; diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c index c0055d3788..189ee969c7 100644 --- a/src/bus-proxyd/proxy.c +++ b/src/bus-proxyd/proxy.c @@ -144,6 +144,10 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd return 0; } +/* + * dbus-1 clients receive NameOwnerChanged and directed signals without + * subscribing to them; install the matches to receive them on kdbus. + */ static int proxy_prepare_matches(Proxy *p) { _cleanup_free_ char *match = NULL; const char *unique; @@ -189,6 +193,20 @@ static int proxy_prepare_matches(Proxy *p) { if (r < 0) return log_error_errno(r, "Failed to add match for NameAcquired: %m"); + free(match); + match = strjoin("type='signal'," + "destination='", + unique, + "'", + NULL); + if (!match) + return log_oom(); + + r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL); + if (r < 0) + log_error_errno(r, "Failed to add match for directed signals: %m"); + /* FIXME: temporarily ignore error to support older kdbus versions */ + return 0; } diff --git a/src/core/job.c b/src/core/job.c index 8a047df0c3..1448e5b69a 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -452,7 +452,7 @@ static bool job_is_runnable(Job *j) { j->type == JOB_RELOAD) { /* Immediate result is that the job is or might be - * started. In this case lets wait for the + * started. In this case let's wait for the * dependencies, regardless whether they are * starting or stopping something. */ @@ -462,7 +462,7 @@ static bool job_is_runnable(Job *j) { } /* Also, if something else is being stopped and we should - * change state after it, then lets wait. */ + * change state after it, then let's wait. */ SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) if (other->job && diff --git a/src/core/service.c b/src/core/service.c index fa1e80b710..d72ff54daa 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1235,7 +1235,7 @@ static int main_pid_good(Service *s) { /* Returns 0 if the pid is dead, 1 if it is good, -1 if we * don't know */ - /* If we know the pid file, then lets just check if it is + /* If we know the pid file, then let's just check if it is * still valid */ if (s->main_pid_known) { diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index fddda97f52..6a2c05185d 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -133,8 +133,6 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { lldp->statistics.stats_frames_in_total ++; - return 0; - out: if (r < 0) log_lldp("Receive frame failed: %s", strerror(-r)); diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c index 30c1a726eb..10c13e348a 100644 --- a/src/libsystemd-terminal/grdev-drm.c +++ b/src/libsystemd-terminal/grdev-drm.c @@ -2584,7 +2584,7 @@ static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct u } else { /* We might get DRM-Master implicitly on open(); drop it immediately * so we acquire it only once we're actually enabled. We don't - * really care whether this call fails or not, but lets log any + * really care whether this call fails or not, but let's log any * weird errors, anyway. */ r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); if (r < 0 && errno != EACCES && errno != EINVAL) @@ -2777,7 +2777,7 @@ static int managed_card_resume_device_fn(sd_bus_message *signal, if (cm->card.fd < 0) { /* This shouldn't happen. We should already own an FD from - * TakeDevice(). However, lets be safe and use this FD in case + * TakeDevice(). However, let's be safe and use this FD in case * we really don't have one. There is no harm in doing this * and our code works fine this way. */ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 7a59702cb2..a38c5c50fc 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1219,7 +1219,7 @@ int bus_add_match_internal_kernel( size_t sz; const char *sender = NULL; size_t sender_length = 0; - uint64_t src_id = KDBUS_MATCH_ID_ANY; + uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY; bool using_bloom = false; unsigned i; bool matches_name_change = true; @@ -1332,13 +1332,21 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_DESTINATION: - /* The bloom filter does not include - the destination, since it is only - available for broadcast messages - which do not carry a destination - since they are undirected. */ + case BUS_MATCH_DESTINATION: { + /* + * Kernel only supports matching on destination IDs, but + * not on destination names. So just skip the + * destination name restriction and verify it in + * user-space on retrieval. + */ + r = bus_kernel_parse_unique_name(c->value_str, &dst_id); + if (r < 0) + return r; + else if (r > 0) + sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); + break; + } case BUS_MATCH_ROOT: case BUS_MATCH_VALUE: @@ -1365,6 +1373,13 @@ int bus_add_match_internal_kernel( item = KDBUS_ITEM_NEXT(item); } + if (dst_id != KDBUS_MATCH_ID_ANY) { + item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); + item->type = KDBUS_ITEM_DST_ID; + item->id = dst_id; + item = KDBUS_ITEM_NEXT(item); + } + if (using_bloom) { item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size; item->type = KDBUS_ITEM_BLOOM_MASK; diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h index 00a6e142c9..ecffc6b13c 100644 --- a/src/libsystemd/sd-bus/kdbus.h +++ b/src/libsystemd/sd-bus/kdbus.h @@ -374,6 +374,7 @@ enum kdbus_item_type { KDBUS_ITEM_ATTACH_FLAGS_RECV, KDBUS_ITEM_ID, KDBUS_ITEM_NAME, + KDBUS_ITEM_DST_ID, /* keep these item types in sync with KDBUS_ATTACH_* flags */ _KDBUS_ITEM_ATTACH_BASE = 0x1000, diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index b8a3668bfc..6f51ebe73d 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -93,7 +93,7 @@ struct sd_netlink { }; struct netlink_attribute { - size_t offset; /* offset from hdr to attirubte */ + size_t offset; /* offset from hdr to attribute */ }; struct netlink_container { diff --git a/src/login/71-seat.rules.in b/src/login/71-seat.rules.in index 47d68b85fb..de55c9a4ec 100644 --- a/src/login/71-seat.rules.in +++ b/src/login/71-seat.rules.in @@ -18,7 +18,7 @@ SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" # qemu (version 2.4+) has a PCI-PCI bridge (-device pci-bridge-seat) to group -# evices belonging to one seat. See: +# devices belonging to one seat. See: # http://git.qemu.org/?p=qemu.git;a=blob;f=docs/multiseat.txt SUBSYSTEM=="pci", ATTR{vendor}=="0x1b36", ATTR{device}=="0x000a", TAG+="seat", ENV{ID_AUTOSEAT}="1" diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index dff81a5cf0..5607cf470e 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -116,6 +116,16 @@ static bool link_ipv6_forward_enabled(Link *link) { return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } +static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { + if (link->flags & IFF_LOOPBACK) + return _IPV6_PRIVACY_EXTENSIONS_INVALID; + + if (!link->network) + return _IPV6_PRIVACY_EXTENSIONS_INVALID; + + return link->network->ipv6_privacy_extensions; +} + #define FLAG_STRING(string, flag, old, new) \ (((old ^ new) & flag) \ ? ((old & flag) ? (" -" string) : (" +" string)) \ @@ -1473,35 +1483,84 @@ static int link_enter_join_netdev(Link *link) { } static int link_set_ipv4_forward(Link *link) { - const char *p = NULL; + const char *p = NULL, *v; int r; + if (link->flags & IFF_LOOPBACK) + return 0; + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) return 0; p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding"); - r = write_string_file_no_create(p, one_zero(link_ipv4_forward_enabled(link))); - if (r < 0) + v = one_zero(link_ipv4_forward_enabled(link)); + + r = write_string_file_no_create(p, v); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, v) > 0) + return 0; + log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname); + } return 0; } static int link_set_ipv6_forward(Link *link) { - const char *p = NULL; + const char *p = NULL, *v = NULL; int r; /* Make this a NOP if IPv6 is not available */ if (!socket_ipv6_is_supported()) return 0; + if (link->flags & IFF_LOOPBACK) + return 0; + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) return 0; p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding"); - r = write_string_file_no_create(p, one_zero(link_ipv6_forward_enabled(link))); - if (r < 0) + v = one_zero(link_ipv6_forward_enabled(link)); + + r = write_string_file_no_create(p, v); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, v) > 0) + return 0; + log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m"); + } + + return 0; +} + +static int link_set_ipv6_privacy_extensions(Link *link) { + char buf[DECIMAL_STR_MAX(unsigned) + 1]; + IPv6PrivacyExtensions s; + const char *p = NULL; + int r; + + /* Make this a NOP if IPv6 is not available */ + if (!socket_ipv6_is_supported()) + return 0; + + s = link_ipv6_privacy_extensions(link); + if (s == _IPV6_PRIVACY_EXTENSIONS_INVALID) + return 0; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr"); + xsprintf(buf, "%u", link->network->ipv6_privacy_extensions); + + r = write_string_file_no_create(p, buf); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, buf) > 0) + return 0; + + log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m"); + } return 0; } @@ -1525,6 +1584,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_ipv6_privacy_extensions(link); + if (r < 0) + return r; + if (link_ipv4ll_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index b05bc949f2..787fc2ff5b 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -15,69 +15,70 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) -Match.Path, config_parse_strv, 0, offsetof(Network, match_path) -Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) -Match.Type, config_parse_strv, 0, offsetof(Network, match_type) -Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name) -Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host) -Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt) -Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel) -Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) -Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) -Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) -Network.Description, config_parse_string, 0, offsetof(Network, description) -Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) -Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) -Network.VLAN, config_parse_netdev, 0, 0 -Network.MACVLAN, config_parse_netdev, 0, 0 -Network.IPVLAN, config_parse_netdev, 0, 0 -Network.VXLAN, config_parse_netdev, 0, 0 -Network.Tunnel, config_parse_tunnel, 0, 0 -Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) -Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) -Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) -Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) -Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) -Network.Address, config_parse_address, 0, 0 -Network.Gateway, config_parse_gateway, 0, 0 -Network.Domains, config_parse_domains, 0, offsetof(Network, domains) -Network.DNS, config_parse_strv, 0, offsetof(Network, dns) -Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr) -Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) -Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) -Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) -Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) -Address.Address, config_parse_address, 0, 0 -Address.Peer, config_parse_address, 0, 0 -Address.Broadcast, config_parse_broadcast, 0, 0 -Address.Label, config_parse_label, 0, 0 -Route.Gateway, config_parse_gateway, 0, 0 -Route.Destination, config_parse_destination, 0, 0 -Route.Source, config_parse_destination, 0, 0 -Route.Metric, config_parse_route_priority, 0, 0 -Route.Scope, config_parse_route_scope, 0, 0 -DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) -DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) -DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) -DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) -DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) -DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) -DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) -Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) -BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 -BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 +Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) +Match.Path, config_parse_strv, 0, offsetof(Network, match_path) +Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) +Match.Type, config_parse_strv, 0, offsetof(Network, match_type) +Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name) +Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host) +Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt) +Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel) +Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) +Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) +Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Network.Description, config_parse_string, 0, offsetof(Network, description) +Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) +Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) +Network.VLAN, config_parse_netdev, 0, 0 +Network.MACVLAN, config_parse_netdev, 0, 0 +Network.IPVLAN, config_parse_netdev, 0, 0 +Network.VXLAN, config_parse_netdev, 0, 0 +Network.Tunnel, config_parse_tunnel, 0, 0 +Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) +Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) +Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) +Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) +Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) +Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.Address, config_parse_address, 0, 0 +Network.Gateway, config_parse_gateway, 0, 0 +Network.Domains, config_parse_domains, 0, offsetof(Network, domains) +Network.DNS, config_parse_strv, 0, offsetof(Network, dns) +Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr) +Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) +Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) +Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) +Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) +Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) +Address.Address, config_parse_address, 0, 0 +Address.Peer, config_parse_address, 0, 0 +Address.Broadcast, config_parse_broadcast, 0, 0 +Address.Label, config_parse_label, 0, 0 +Route.Gateway, config_parse_gateway, 0, 0 +Route.Destination, config_parse_destination, 0, 0 +Route.Source, config_parse_destination, 0, 0 +Route.Metric, config_parse_route_priority, 0, 0 +Route.Scope, config_parse_route_scope, 0, 0 +DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) +DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) +DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) +DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) +DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) +DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) +DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) +DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) +Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) +BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 +BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 /* backwards compatibility: do not add new entries to this section */ -Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) -DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) +Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) +DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index ec95c8661e..a8e9ef909c 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -111,6 +111,8 @@ static int network_load_one(Manager *manager, const char *filename) { network->link_local = ADDRESS_FAMILY_IPV6; + network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; + r = config_parse(NULL, filename, file, "Match\0" "Link\0" @@ -751,3 +753,59 @@ int config_parse_address_family_boolean_with_kernel( return 0; } + +static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = { + [IPV6_PRIVACY_EXTENSIONS_NO] = "no", + [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public", + [IPV6_PRIVACY_EXTENSIONS_YES] = "yes", +}; + +DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions); + +int config_parse_ipv6_privacy_extensions( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + IPv6PrivacyExtensions *ipv6_privacy_extensions = data; + int k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(ipv6_privacy_extensions); + + /* Our enum shall be a superset of booleans, hence first try + * to parse as boolean, and then as enum */ + + k = parse_boolean(rvalue); + if (k > 0) + *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES; + else if (k == 0) + *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; + else { + IPv6PrivacyExtensions s; + + s = ipv6_privacy_extensions_from_string(rvalue); + if (s < 0) { + + if (streq(rvalue, "kernel")) + s = _IPV6_PRIVACY_EXTENSIONS_INVALID; + else { + log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue); + return 0; + } + } + + *ipv6_privacy_extensions = s; + } + + return 0; +} diff --git a/src/network/networkd.h b/src/network/networkd.h index ac6e2c8a8e..f98c640822 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -90,6 +90,15 @@ typedef enum DCHPClientIdentifier { _DHCP_CLIENT_ID_INVALID = -1, } DCHPClientIdentifier; +typedef enum IPv6PrivacyExtensions { + /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ + IPV6_PRIVACY_EXTENSIONS_NO, + IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, + IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ + _IPV6_PRIVACY_EXTENSIONS_MAX, + _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, +} IPv6PrivacyExtensions; + struct FdbEntry { Network *network; unsigned section; @@ -145,6 +154,8 @@ struct Network { AddressFamilyBoolean ip_forward; bool ip_masquerade; + IPv6PrivacyExtensions ipv6_privacy_extensions; + struct ether_addr *mac; unsigned mtu; @@ -455,3 +466,10 @@ int config_parse_address_family_boolean_with_kernel(const char *unit, const char const char* link_operstate_to_string(LinkOperationalState s) _const_; LinkOperationalState link_operstate_from_string(const char *s) _pure_; + +/* IPv6 privacy extensions support */ + +const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; +IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; + +int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 1ba248f6d6..ab9fbaf138 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -341,6 +341,11 @@ static int custom_mounts_prepare(void) { for (i = 0; i < arg_n_custom_mounts; i++) { CustomMount *m = &arg_custom_mounts[i]; + if (arg_userns && arg_uid_shift == UID_INVALID && path_equal(m->destination, "/")) { + log_error("--private-users with automatic UID shift may not be combined with custom root mounts."); + return -EINVAL; + } + if (m->type != CUSTOM_MOUNT_OVERLAY) continue; @@ -1028,6 +1033,7 @@ static int tmpfs_patch_options(const char *options, char **ret) { char *buf = NULL; if (arg_userns && arg_uid_shift != 0) { + assert(arg_uid_shift != UID_INVALID); if (options) (void) asprintf(&buf, "%s,uid=" UID_FMT ",gid=" UID_FMT, options, arg_uid_shift, arg_uid_shift); @@ -4259,6 +4265,7 @@ static int outer_child( int pid_socket, int kmsg_socket, int rtnl_socket, + int uid_shift_socket, FDSet *fds, int argc, char *argv[]) { @@ -4317,6 +4324,16 @@ static int outer_child( if (r < 0) return r; + if (arg_userns) { + l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL); + if (l < 0) + return log_error_errno(errno, "Failed to send UID shift: %m"); + if (l != sizeof(arg_uid_shift)) { + log_error("Short write while sending UID shift."); + return -EIO; + } + } + /* Turn directory into bind mount */ if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0) return log_error_errno(errno, "Failed to make bind mount: %m"); @@ -4397,6 +4414,7 @@ static int outer_child( if (pid == 0) { pid_socket = safe_close(pid_socket); + uid_shift_socket = safe_close(uid_shift_socket); /* The inner child has all namespaces that are * requested, so that we all are owned by the user if @@ -4687,7 +4705,8 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }; + _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, + uid_shift_socket_pair[2] = { -1, -1 }; ContainerStatus container_status; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { @@ -4696,10 +4715,10 @@ int main(int argc, char *argv[]) { }; int ifi = 0; ssize_t l; - _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_(pty_forward_freep) PTYForward *forward = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - char last_char = 0; + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(pty_forward_freep) PTYForward *forward = NULL; + _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + char last_char = 0; r = barrier_create(&barrier); if (r < 0) { @@ -4722,6 +4741,12 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_userns) + if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { + r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); + goto finish; + } + /* Child can be killed before execv(), so handle SIGCHLD * in order to interrupt parent's blocking calls and * give it a chance to call wait() and terminate. */ @@ -4756,6 +4781,7 @@ int main(int argc, char *argv[]) { kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); pid_socket_pair[0] = safe_close(pid_socket_pair[0]); + uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); (void) reset_all_signal_handlers(); (void) reset_signal_mask(); @@ -4771,6 +4797,7 @@ int main(int argc, char *argv[]) { pid_socket_pair[1], kmsg_socket_pair[1], rtnl_socket_pair[1], + uid_shift_socket_pair[1], fds, argc, argv); if (r < 0) @@ -4819,6 +4846,17 @@ int main(int argc, char *argv[]) { goto finish; } + l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0); + if (l < 0) { + r = log_error_errno(errno, "Failed to read UID shift: %m"); + goto finish; + } + if (l != sizeof(arg_uid_shift)) { + log_error("Short read while reading UID shift: %m"); + r = EIO; + goto finish; + } + r = setup_uid_map(pid); if (r < 0) goto finish; diff --git a/src/test/test-pty.c b/src/test/test-pty.c index 3f97a64ccd..fbab3d4ebe 100644 --- a/src/test/test-pty.c +++ b/src/test/test-pty.c @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) { /* Oh, there're ugly races in the TTY layer regarding HUP vs IN. Turns * out they appear only 10% of the time. I fixed all of them and - * don't see them, anymore. But lets be safe and run this 1000 times + * don't see them, anymore. But let's be safe and run this 1000 times * so we catch any new ones, in case they appear again. */ for (i = 0; i < 1000; ++i) test_pty(); |