This macro will read a pointer of any type, return it, and set the
pointer to NULL. This is useful as an explicit concept of passing
ownership of a memory area between pointers.
This takes inspiration from Rust:
https://doc.rust-lang.org/std/option/enum.Option.html#method.take
and was suggested by Alan Jenkins (@sourcejedi).
It drops ~160 lines of code from our codebase, which makes me like it.
Also, I think it clarifies passing of ownership, and thus helps
readability a bit (at least for the initiated who know the new macro)
Using wait_for_terminate_and_check() instead of wait_for_terminate()
let's us simplify, shorten and unify the return value checking and
logging of waitid(). Hence, let's use it all over the place.
This adds a new safe_fork() wrapper around fork() and makes use of it
everywhere. The new wrapper does a couple of things we previously did
manually and separately in a safer, more correct and automatic way:
1. Optionally resets signal handlers/mask in the child
2. Sets a name on all processes we fork off right after forking off (and
the patch assigns useful names for all processes we fork off now,
following a systematic naming scheme: always enclosed in () – in order
to indicate that these are not proper, exec()ed processes, but only
forked off children, and if the process is long-running with only our
own code, without execve()'ing something else, it gets am "sd-" prefix.)
3. Optionally closes all file descriptors in the child
4. Optionally sets a PR_SET_DEATHSIG to SIGTERM in the child, in a safe
way so that the parent dying before this happens being handled
safely.
5. Optionally reopens the logs
6. Optionally connects stdin/stdout/stderr to /dev/null
7. Debug logs about the forked off processes.
Already, path_is_safe() refused paths container the "." dir. Doing that
isn't strictly necessary to be "safe" by most definitions of the word.
But it is necessary in order to consider a path "normalized". Hence,
"path_is_safe()" is slightly misleading a name, but
"path_is_normalize()" is more descriptive, hence let's rename things
accordingly.
No functional changes.
If you use machinectl to bind a file into a container, it responds with a confusing error message about a temporary directory not being a directory.
I just swapped it to error with the source that was passed, rather than the tmpdir.
It would also be nice to be able to bind files, but that's a separate issue (#7195).
Before the change:
root@epona /var/lib/sandbox $ cat bar/foo
Hello world!
root@epona /var/lib/sandbox $ machinectl bind testing /var/lib/sandbox/bar/foo /foo
Failed to bind mount: Failed to overmount /tmp/propagate.W5TNsj/mount: Not a directory
After the change:
root@epona /var/lib/sandbox $ machinectl bind testing /var/lib/sandbox/bar/foo /foo
Failed to bind mount: Failed to overmount /var/lib/sandbox/bar/foo: Not a directory
As the kernel won't map the UIDs this is simply not safe, and hence we
should generate a clean error and refuse it.
We can restore this feature later should a "shiftfs" become available in
the kernel.
This changes the file copy logic of machined to set the UID/GID of all
copied files to 0 if the host and container do not share the same user
namespace.
Fixes: #4078
This adds a unified "copy_flags" parameter to all copy_xyz() function
calls, replacing the various boolean flags so far used. This should make
many invocations more readable as it is clear what behaviour is
precisely requested. This also prepares ground for adding support for
more modes later on.
UID/GID mapping with userns can be arbitrarily complex. Let's break this
down to a single admin-friendly parameter: let's expose the UID/GID
shift of a container via a new bus call for each container, and let's
show this as part of "machinectl status" if it is not 0.
This should work for pretty much all real-life full OS container setups
(i.e. the stuff machined is suppose to be useful for). For everything
else we generate a clean error, clarifying that we can't expose the
mapping.
This adds a bus call GetImageOSRelease() to the Manager interface that
retrieves the /etc/os-release file of a machine image. It matches the existing
GetMachineOSRelease() call, however operates on a disk image rather than a
running container.
The backend for this call on .raw images is implemented via the generalized
image dissector, which makes this scheme relatively easy to implement.
We don't have plural in the name of any other -util files and this
inconsistency trips me up every time I try to type this file name
from memory. "formats-util" is even hard to pronounce.
This is a follow-up to 5d2036b5f3, and also makes
the "machinectl clean" verb asynchronous, after all it's little more than a
series of image removals.
The changes required to make this happen are a bit more comprehensive as we
need to pass information about deleted images back to the client, as well as
information about the image we failed on if we failed on one. Hence, create a
temporary file in /tmp, serialize that data into, and read it from the parent
after the operation is complete.
There's no point in explicitly closing the errno pipe, if we exit right after
anyway. It doesn't hurt doing this either, but let's do this the same way for
all cases where we use the "Operation" object right now, and in all other cases
we do not close the pipe explicitly, hence don't do so here either.
This new call returns a file descriptor for the root directory of a container.
This file descriptor may then be used to access the rest of the container's
file system, via openat() and similar calls. Since the file descriptor returned
is for the file system namespace inside of the container it may be used to
access all files of the container exactly the way the container itself would
see them. This is particularly useful for containers run directly from
loopback media, for example via systemd-nspawn's --image= switch. It also
provides access to directories such as /run of a container that are normally
not accessible to the outside of a container.
This replaces PR #2870.
Fixes: #2870
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
With this change we'll open the shell's tty right from machined and then
pass it to the transient unit we create. This way we make sure the pty
is opened exactly as long as the transient service is around, and no
longer, and vice versa. This way pty forwarders do not have to deal with
EIO problems due to vhangup, as the pty is open all the time from the
point we set things up to the point where the service goes away.
If set to ~ the working directory is set to the home directory of the
user configured in User=.
This change also exposes the existing switch for the working directory
that allowed making missing working directories non-fatal.
This also changes "machinectl shell" to make use of this to ensure that
the invoked shell is by default in the user's home directory.
Fixes#1268.
off_t is a really weird type as it is usually 64bit these days (at least
in sane programs), but could theoretically be 32bit. We don't support
off_t as 32bit builds though, but still constantly deal with safely
converting from off_t to other types and back for no point.
Hence, never use the type anymore. Always use uint64_t instead. This has
various benefits, including that we can expose these values directly as
D-Bus properties, and also that the values parse the same in all cases.
Now that we get useful error messages from sd-bus for container
connections, let's make use of this and report better errors back to
machined clients.
Fixes#685.
Extra details for an action can be supplied when calling polkit's
CheckAuthorization method. Details are a list of key/value string pairs.
Custom policy can use these details when making authorization decisions.
Introduce separate actions for creating login or shell sessions for
the local host or a local container. By default allow local unprivileged
clients to create new login sessions (which is safe, since getty will
ask for username and authentication).
Also, imply login privs from shell privs, as well as shell and login
privs from manage privs.
Some of the operations machined/machinectl implement are also very
useful when applied to the host system (such as machinectl login,
machinectl shell or machinectl status), hence introduce a pseudo-machine
by the name of ".host" in machined that refers to the host system, and
may be used top execute operations on the host system with.
This copies the pseudo-image ".host" machined already implements for
image related commands.
(This commit also adds a PK privilege for opening a PTY in a container,
which was previously not accessible for non-root.)
This new bus call opens an interactive shell in a container. It works
like the existing OpenLogin() call, but does not involve getty, and
instead opens an arbitrary command line.
This is similar to "systemd-run -t -M" but is controlled by a specific
PolicyKit privilege.
To be able to use `systemd-run` or `machinectl login` on a container
that is in a private user namespace, the sub-process must have entered
the user namespace before connecting to the container's D-Bus, otherwise
the UID and GID in the peer credentials are garbage.
So we extend namespace_open and namespace_enter to support UID namespaces,
and we enter the UID namespace in bus_container_connect_{socket,kernel}.
namespace_open will degrade to a no-op if user namespaces are not enabled
in the kernel.
Special handling is required for the setns call in namespace_enter with
a user namespace, since transitioning to your own namespace is forbidden,
as it would result in re-entering your user namespace as root.
Arguably it may be valid to check this at the call site, rather than
inside namespace_enter, but it is less code to do it inside, and if the
intention of calling namespace_enter is to *be* in the target namespace,
rather than to transition to the target namespace, it is a reasonable
approach.
The check for whether the user namespace is the same must happen before
entering namespaces, as we may not be able to access /proc during the
intermediate transition stage.
We can't instead attempt to enter the user namespace and then ignore
the failure from it being the same namespace, since the error code is
not distinct, and we can't compare namespaces while mid-transition.
Absolute paths should be sufficient to prevent funny business,
and while path_is_safe() checks this, it also checks whether the path
contains . or .. components, which while odd, aren't a security risk.
It is no different to return 0 over 1 in the property
callback. It is confusing to return 1 which made me think
1 has a special purpose. This way code is consistent with
the rest of the tree.
./configure --enable/disable-kdbus can be used to set the default
behavior regarding kdbus.
If no kdbus kernel support is available, dbus-dameon will be used.
With --enable-kdbus, the kernel command line option "kdbus=0" can
be used to disable kdbus.
With --disable-kdbus, the kernel command line option "kdbus=1" is
required to enable kdbus support.
XDG refers to X Desktop Group, a former name for freedesktop.org.
This group is responsible for specifications like basedirs,
.desktop files and icon naming, but as far as I know, it has never
tried to redefine basename().
I think these references were meant to say XPG (X/Open Portability
Guide), a precursor of POSIX. POSIX is better-known and less easily
confused with XDG, and is how the basename(3) man page describes
the libgen.h version of basename().
The other version of basename() is glibc-specific and is described
in basename(3) as "the GNU version"; specifically mention that
version, to disambiguate.