mirror of
https://github.com/systemd/systemd
synced 2026-03-23 15:24:54 +01:00
Compare commits
17 Commits
d844b033a4
...
f571d9d5f0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f571d9d5f0 | ||
|
|
80362ec56f | ||
|
|
a11e7c0b4c | ||
|
|
d2e84b6018 | ||
|
|
f6f4ec7951 | ||
|
|
14f4b1b568 | ||
|
|
878e32b614 | ||
|
|
6999521ba9 | ||
|
|
cbcf371abc | ||
|
|
45a68ed307 | ||
|
|
3e24e8cd64 | ||
|
|
3bd6a01c01 | ||
|
|
6bf3c6c900 | ||
|
|
9c46228b7d | ||
|
|
becbc6dfa8 | ||
|
|
946f7ce32c | ||
|
|
ce266330fc |
3
TODO
3
TODO
@ -1189,6 +1189,9 @@ Features:
|
|||||||
- introduce API for "making room", that grows/shrinks home directory
|
- introduce API for "making room", that grows/shrinks home directory
|
||||||
according to elastic parameters, discards blocks, and removes additional snapshots. Call it
|
according to elastic parameters, discards blocks, and removes additional snapshots. Call it
|
||||||
either from UI when disk space gets low
|
either from UI when disk space gets low
|
||||||
|
- when homed is in use, maybe start the user session manager in a mount namespace with MS_SLAVE,
|
||||||
|
so that mounts propagate down but not up - eg, user A setting up a backup volume
|
||||||
|
doesn't mean user B sees it
|
||||||
|
|
||||||
* homed: during login resize fs automatically towards size goal. Specifically,
|
* homed: during login resize fs automatically towards size goal. Specifically,
|
||||||
resize to diskSize if possible, but leave a certain amount (configured by a
|
resize to diskSize if possible, but leave a certain amount (configured by a
|
||||||
|
|||||||
@ -847,6 +847,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnTrekStor:pnSurfTabtwin10.1:*
|
|||||||
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR*:pnPrimetabS11B:*
|
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR*:pnPrimetabS11B:*
|
||||||
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR:pnPrimetabT13B:*
|
sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR:pnPrimetabT13B:*
|
||||||
sensor:modalias:acpi:BOSC0200*:dmi:*:svnTrekStor*:pnSurfTabtwin11.6:*
|
sensor:modalias:acpi:BOSC0200*:dmi:*:svnTrekStor*:pnSurfTabtwin11.6:*
|
||||||
|
sensor:modalias:acpi:BOSC0200*:dmi:*:svnTrekStor*:pnSurfTabduoW110.1(VT4):*
|
||||||
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
|
||||||
|
|
||||||
# alternative version of Trekstor's SurfTab Twin 11.6
|
# alternative version of Trekstor's SurfTab Twin 11.6
|
||||||
|
|||||||
@ -73,13 +73,17 @@
|
|||||||
<para>To activate the NSS modules, add <literal>myhostname</literal> to the line starting with
|
<para>To activate the NSS modules, add <literal>myhostname</literal> to the line starting with
|
||||||
<literal>hosts:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
|
<literal>hosts:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
|
||||||
|
|
||||||
<para>It is recommended to place <literal>myhostname</literal> either between <literal>resolve</literal>
|
<para>It is recommended to place <literal>myhostname</literal> after <literal>file</literal> and before <literal>dns</literal>.
|
||||||
and "traditional" modules like <literal>dns</literal>, or after them. In the first version, well-known
|
This resolves well-known hostnames like <literal>localhost</literal>
|
||||||
names like <literal>localhost</literal> and the machine hostname are given higher priority than the
|
and the machine hostnames locally. It is consistent with the behaviour
|
||||||
external configuration. This is recommended when the external DNS servers and network are not absolutely
|
of <command>nss-resolve</command>, and still allows overriding via
|
||||||
trusted. In the second version, external configuration is given higher priority and
|
<filename>/etc/hosts</filename>.</para>
|
||||||
<command>nss-myhostname</command> only provides a fallback mechanism. This might be suitable in closely
|
|
||||||
controlled networks, for example on a company LAN.</para>
|
<para>Please keep in mind that <command>nss-myhostname</command> (and <command>nss-resolve</command>) also resolve
|
||||||
|
in the other direction — from locally attached IP adresses to
|
||||||
|
hostnames. If you rely on that lookup being provided by DNS, you might
|
||||||
|
want to order things differently.
|
||||||
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -95,10 +99,7 @@ shadow: compat systemd
|
|||||||
gshadow: files systemd
|
gshadow: files systemd
|
||||||
|
|
||||||
|
|
||||||
# Either (untrusted network, see above):
|
|
||||||
hosts: mymachines resolve [!UNAVAIL=return] files <command>myhostname</command> dns
|
hosts: mymachines resolve [!UNAVAIL=return] files <command>myhostname</command> dns
|
||||||
# Or (only trusted networks):
|
|
||||||
hosts: mymachines resolve [!UNAVAIL=return] files dns <command>myhostname</command>
|
|
||||||
networks: files
|
networks: files
|
||||||
|
|
||||||
protocols: db files
|
protocols: db files
|
||||||
|
|||||||
@ -52,6 +52,12 @@
|
|||||||
it is still recommended (see examples below) to keep <command>nss-myhostname</command> configured in
|
it is still recommended (see examples below) to keep <command>nss-myhostname</command> configured in
|
||||||
<filename>/etc/nsswitch.conf</filename>, to keep those names resolveable if
|
<filename>/etc/nsswitch.conf</filename>, to keep those names resolveable if
|
||||||
<command>systemd-resolved</command> is not running.</para>
|
<command>systemd-resolved</command> is not running.</para>
|
||||||
|
|
||||||
|
<para>Please keep in mind that <command>nss-myhostname</command> (and <command>nss-resolve</command>) also resolve
|
||||||
|
in the other direction — from locally attached IP adresses to
|
||||||
|
hostnames. If you rely on that lookup being provided by DNS, you might
|
||||||
|
want to order things differently.
|
||||||
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|||||||
@ -294,7 +294,7 @@
|
|||||||
<title>EFI Variables</title>
|
<title>EFI Variables</title>
|
||||||
|
|
||||||
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the vendor
|
<para>The following EFI variables are defined, set and read by <command>systemd-boot</command>, under the vendor
|
||||||
UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4</literal>, for communication between the OS and the boot
|
UUID <literal>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</literal>, for communication between the OS and the boot
|
||||||
loader:</para>
|
loader:</para>
|
||||||
|
|
||||||
<variablelist class='efi-variables'>
|
<variablelist class='efi-variables'>
|
||||||
|
|||||||
@ -208,10 +208,9 @@ static int get_max_fd(void) {
|
|||||||
return (int) (m - 1);
|
return (int) (m - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int close_all_fds(const int except[], size_t n_except) {
|
int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
|
||||||
static bool have_close_range = true; /* Assume we live in the future */
|
static bool have_close_range = true; /* Assume we live in the future */
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
struct dirent *de;
|
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
assert(n_except == 0 || except);
|
assert(n_except == 0 || except);
|
||||||
@ -227,129 +226,104 @@ int close_all_fds(const int except[], size_t n_except) {
|
|||||||
/* Close everything. Yay! */
|
/* Close everything. Yay! */
|
||||||
|
|
||||||
if (close_range(3, -1, 0) >= 0)
|
if (close_range(3, -1, 0) >= 0)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
|
||||||
|
have_close_range = false;
|
||||||
|
else
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
have_close_range = false;
|
|
||||||
} else {
|
} else {
|
||||||
_cleanup_free_ int *sorted_malloc = NULL;
|
typesafe_qsort(except, n_except, cmp_int);
|
||||||
size_t n_sorted;
|
|
||||||
int *sorted;
|
|
||||||
|
|
||||||
assert(n_except < SIZE_MAX);
|
for (size_t i = 0; i < n_except; i++) {
|
||||||
n_sorted = n_except + 1;
|
int start = i == 0 ? 2 : MAX(except[i-1], 2); /* The first three fds shall always remain open */
|
||||||
|
int end = MAX(except[i], 2);
|
||||||
|
|
||||||
if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
|
assert(end >= start);
|
||||||
sorted = sorted_malloc = new(int, n_sorted);
|
|
||||||
else
|
|
||||||
sorted = newa(int, n_sorted);
|
|
||||||
|
|
||||||
if (sorted) {
|
if (end - start <= 1)
|
||||||
int c = 0;
|
continue;
|
||||||
|
|
||||||
memcpy(sorted, except, n_except * sizeof(int));
|
|
||||||
|
|
||||||
/* Let's add fd 2 to the list of fds, to simplify the loop below, as this
|
|
||||||
* allows us to cover the head of the array the same way as the body */
|
|
||||||
sorted[n_sorted-1] = 2;
|
|
||||||
|
|
||||||
typesafe_qsort(sorted, n_sorted, cmp_int);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n_sorted-1; i++) {
|
|
||||||
int start, end;
|
|
||||||
|
|
||||||
start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
|
|
||||||
end = MAX(sorted[i+1], 2);
|
|
||||||
|
|
||||||
assert(end >= start);
|
|
||||||
|
|
||||||
if (end - start <= 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Close everything between the start and end fds (both of which shall stay open) */
|
|
||||||
if (close_range(start + 1, end - 1, 0) < 0) {
|
|
||||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
|
/* Close everything between the start and end fds (both of which shall stay open) */
|
||||||
|
if (close_range(start + 1, end - 1, 0) < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
|
||||||
have_close_range = false;
|
have_close_range = false;
|
||||||
break;
|
else
|
||||||
}
|
|
||||||
|
|
||||||
c += end - start - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_close_range) {
|
|
||||||
/* The loop succeeded. Let's now close everything beyond the end */
|
|
||||||
|
|
||||||
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
|
|
||||||
return c;
|
|
||||||
|
|
||||||
if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
|
|
||||||
return c + 1;
|
|
||||||
|
|
||||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
|
||||||
return -errno;
|
return -errno;
|
||||||
|
goto opendir_fallback;
|
||||||
have_close_range = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Fallback on OOM or if close_range() is not supported */
|
/* The loop succeeded. Let's now close everything beyond the end */
|
||||||
|
|
||||||
|
if (except[n_except-1] >= INT_MAX) /* Don't let the addition below overflow */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int start = MAX(except[n_except-1], 2);
|
||||||
|
|
||||||
|
if (close_range(start + 1, -1, 0) >= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
|
||||||
|
have_close_range = false;
|
||||||
|
else
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = opendir("/proc/self/fd");
|
/* Fallback for when close_range() is not supported */
|
||||||
if (!d) {
|
opendir_fallback:
|
||||||
int fd, max_fd;
|
d = allow_alloc ? opendir("/proc/self/fd") : NULL;
|
||||||
|
if (d) {
|
||||||
|
struct dirent *de;
|
||||||
|
|
||||||
/* When /proc isn't available (for example in chroots) the fallback is brute forcing through
|
FOREACH_DIRENT(de, d, return -errno) {
|
||||||
* the fd table */
|
int fd = -1, q;
|
||||||
|
|
||||||
max_fd = get_max_fd();
|
if (safe_atoi(de->d_name, &fd) < 0)
|
||||||
if (max_fd < 0)
|
/* Let's better ignore this, just in case */
|
||||||
return max_fd;
|
continue;
|
||||||
|
|
||||||
/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
|
if (fd < 3)
|
||||||
* spin the CPU for a long time. */
|
continue;
|
||||||
if (max_fd > MAX_FD_LOOP_LIMIT)
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
|
|
||||||
"/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
|
|
||||||
max_fd);
|
|
||||||
|
|
||||||
for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
|
if (fd == dirfd(d))
|
||||||
int q;
|
continue;
|
||||||
|
|
||||||
if (fd_in_set(fd, except, n_except))
|
if (fd_in_set(fd, except, n_except))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
q = close_nointr(fd);
|
q = close_nointr(fd);
|
||||||
if (q < 0 && q != -EBADF && r >= 0)
|
if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
|
||||||
r = q;
|
r = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_DIRENT(de, d, return -errno) {
|
/* Fallback for when /proc isn't available (for example in chroots) or when we cannot allocate by
|
||||||
int fd = -1, q;
|
* brute-forcing through the file descriptor table. */
|
||||||
|
|
||||||
if (safe_atoi(de->d_name, &fd) < 0)
|
int max_fd = get_max_fd();
|
||||||
/* Let's better ignore this, just in case */
|
if (max_fd < 0)
|
||||||
continue;
|
return max_fd;
|
||||||
|
|
||||||
if (fd < 3)
|
/* Refuse to do the loop over more too many elements. It's better to fail immediately than to
|
||||||
continue;
|
* spin the CPU for a long time. */
|
||||||
|
if (max_fd > MAX_FD_LOOP_LIMIT)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
|
||||||
|
"/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
|
||||||
|
max_fd);
|
||||||
|
|
||||||
if (fd == dirfd(d))
|
for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
|
||||||
continue;
|
int q;
|
||||||
|
|
||||||
if (fd_in_set(fd, except, n_except))
|
if (fd_in_set(fd, except, n_except))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
q = close_nointr(fd);
|
q = close_nointr(fd);
|
||||||
if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
|
if (q < 0 && q != -EBADF && r >= 0)
|
||||||
r = q;
|
r = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
|
|||||||
int fd_nonblock(int fd, bool nonblock);
|
int fd_nonblock(int fd, bool nonblock);
|
||||||
int fd_cloexec(int fd, bool cloexec);
|
int fd_cloexec(int fd, bool cloexec);
|
||||||
|
|
||||||
int close_all_fds(const int except[], size_t n_except);
|
int close_all_fds_full(int except[], size_t n_except, bool allow_alloc);
|
||||||
|
static inline int close_all_fds(int except[], size_t n_except) {
|
||||||
|
return close_all_fds_full(except, n_except, true);
|
||||||
|
}
|
||||||
|
|
||||||
int same_fd(int a, int b);
|
int same_fd(int a, int b);
|
||||||
|
|
||||||
|
|||||||
@ -1037,34 +1037,6 @@ bool is_main_thread(void) {
|
|||||||
return cached > 0;
|
return cached > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_noreturn_ void freeze(void) {
|
|
||||||
|
|
||||||
log_close();
|
|
||||||
|
|
||||||
/* Make sure nobody waits for us on a socket anymore */
|
|
||||||
(void) close_all_fds(NULL, 0);
|
|
||||||
|
|
||||||
sync();
|
|
||||||
|
|
||||||
/* Let's not freeze right away, but keep reaping zombies. */
|
|
||||||
for (;;) {
|
|
||||||
int r;
|
|
||||||
siginfo_t si = {};
|
|
||||||
|
|
||||||
r = waitid(P_ALL, 0, &si, WEXITED);
|
|
||||||
if (r < 0 && errno != EINTR)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* waitid() failed with an unexpected error, things are really borked. Freeze now! */
|
|
||||||
for (;;)
|
|
||||||
pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool oom_score_adjust_is_valid(int oa) {
|
|
||||||
return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long personality_from_string(const char *p) {
|
unsigned long personality_from_string(const char *p) {
|
||||||
int architecture;
|
int architecture;
|
||||||
|
|
||||||
@ -1271,7 +1243,7 @@ static void restore_sigsetp(sigset_t **ssp) {
|
|||||||
|
|
||||||
int safe_fork_full(
|
int safe_fork_full(
|
||||||
const char *name,
|
const char *name,
|
||||||
const int except_fds[],
|
int except_fds[],
|
||||||
size_t n_except_fds,
|
size_t n_except_fds,
|
||||||
ForkFlags flags,
|
ForkFlags flags,
|
||||||
pid_t *ret_pid) {
|
pid_t *ret_pid) {
|
||||||
@ -1466,7 +1438,7 @@ int safe_fork_full(
|
|||||||
int namespace_fork(
|
int namespace_fork(
|
||||||
const char *outer_name,
|
const char *outer_name,
|
||||||
const char *inner_name,
|
const char *inner_name,
|
||||||
const int except_fds[],
|
int except_fds[],
|
||||||
size_t n_except_fds,
|
size_t n_except_fds,
|
||||||
ForkFlags flags,
|
ForkFlags flags,
|
||||||
int pidns_fd,
|
int pidns_fd,
|
||||||
@ -1482,7 +1454,8 @@ int namespace_fork(
|
|||||||
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
|
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
|
||||||
* /proc/self/fd works correctly. */
|
* /proc/self/fd works correctly. */
|
||||||
|
|
||||||
r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
|
r = safe_fork_full(outer_name, except_fds, n_except_fds,
|
||||||
|
(flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
@ -1517,86 +1490,10 @@ int namespace_fork(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
|
|
||||||
bool stdout_is_tty, stderr_is_tty;
|
|
||||||
size_t n, i;
|
|
||||||
va_list ap;
|
|
||||||
char **l;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(path);
|
|
||||||
|
|
||||||
/* Spawns a temporary TTY agent, making sure it goes away when we go away */
|
|
||||||
|
|
||||||
r = safe_fork_full(name,
|
|
||||||
except,
|
|
||||||
n_except,
|
|
||||||
FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
|
|
||||||
ret_pid);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* In the child: */
|
|
||||||
|
|
||||||
stdout_is_tty = isatty(STDOUT_FILENO);
|
|
||||||
stderr_is_tty = isatty(STDERR_FILENO);
|
|
||||||
|
|
||||||
if (!stdout_is_tty || !stderr_is_tty) {
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* Detach from stdout/stderr. and reopen
|
|
||||||
* /dev/tty for them. This is important to
|
|
||||||
* ensure that when systemctl is started via
|
|
||||||
* popen() or a similar call that expects to
|
|
||||||
* read EOF we actually do generate EOF and
|
|
||||||
* not delay this indefinitely by because we
|
|
||||||
* keep an unused copy of stdin around. */
|
|
||||||
fd = open("/dev/tty", O_WRONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
log_error_errno(errno, "Failed to open /dev/tty: %m");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
|
|
||||||
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
|
|
||||||
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_close_above_stdio(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) rlimit_nofile_safe();
|
|
||||||
|
|
||||||
/* Count arguments */
|
|
||||||
va_start(ap, path);
|
|
||||||
for (n = 0; va_arg(ap, char*); n++)
|
|
||||||
;
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
/* Allocate strv */
|
|
||||||
l = newa(char*, n + 1);
|
|
||||||
|
|
||||||
/* Fill in arguments */
|
|
||||||
va_start(ap, path);
|
|
||||||
for (i = 0; i <= n; i++)
|
|
||||||
l[i] = va_arg(ap, char*);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
execv(path, l);
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int set_oom_score_adjust(int value) {
|
int set_oom_score_adjust(int value) {
|
||||||
char t[DECIMAL_STR_MAX(int)];
|
char t[DECIMAL_STR_MAX(int)];
|
||||||
|
|
||||||
sprintf(t, "%i", value);
|
xsprintf(t, "%i", value);
|
||||||
|
|
||||||
return write_string_file("/proc/self/oom_score_adj", t,
|
return write_string_file("/proc/self/oom_score_adj", t,
|
||||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||||
|
|||||||
@ -82,10 +82,6 @@ int pid_from_same_root_fs(pid_t pid);
|
|||||||
|
|
||||||
bool is_main_thread(void);
|
bool is_main_thread(void);
|
||||||
|
|
||||||
_noreturn_ void freeze(void);
|
|
||||||
|
|
||||||
bool oom_score_adjust_is_valid(int oa);
|
|
||||||
|
|
||||||
#ifndef PERSONALITY_INVALID
|
#ifndef PERSONALITY_INVALID
|
||||||
/* personality(7) documents that 0xffffffffUL is used for querying the
|
/* personality(7) documents that 0xffffffffUL is used for querying the
|
||||||
* current personality, hence let's use that here as error
|
* current personality, hence let's use that here as error
|
||||||
@ -168,15 +164,13 @@ typedef enum ForkFlags {
|
|||||||
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
|
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
|
||||||
} ForkFlags;
|
} ForkFlags;
|
||||||
|
|
||||||
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
int safe_fork_full(const char *name, int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||||
|
|
||||||
static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
||||||
return safe_fork_full(name, NULL, 0, flags, ret_pid);
|
return safe_fork_full(name, NULL, 0, flags, ret_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
|
int namespace_fork(const char *outer_name, const char *inner_name, int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
|
||||||
|
|
||||||
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...) _sentinel_;
|
|
||||||
|
|
||||||
int set_oom_score_adjust(int value);
|
int set_oom_score_adjust(int value);
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <linux/oom.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
@ -94,6 +95,10 @@ static int property_get_environment_files(
|
|||||||
return sd_bus_message_close_container(reply);
|
return sd_bus_message_close_container(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool oom_score_adjust_is_valid(int oa) {
|
||||||
|
return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
static int property_get_oom_score_adjust(
|
static int property_get_oom_score_adjust(
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *path,
|
const char *path,
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "sd-event.h"
|
#include "sd-event.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "exec-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|||||||
@ -1791,6 +1791,9 @@ static int verify_shutdown_creds(
|
|||||||
assert(message);
|
assert(message);
|
||||||
assert(w >= 0);
|
assert(w >= 0);
|
||||||
assert(w <= _INHIBIT_WHAT_MAX);
|
assert(w <= _INHIBIT_WHAT_MAX);
|
||||||
|
assert(action);
|
||||||
|
assert(action_multiple_sessions);
|
||||||
|
assert(action_ignore_inhibit);
|
||||||
|
|
||||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1808,7 +1811,7 @@ static int verify_shutdown_creds(
|
|||||||
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
|
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
|
||||||
interactive = flags & SD_LOGIND_INTERACTIVE;
|
interactive = flags & SD_LOGIND_INTERACTIVE;
|
||||||
|
|
||||||
if (multiple_sessions && action_multiple_sessions) {
|
if (multiple_sessions) {
|
||||||
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
|
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1822,16 +1825,14 @@ static int verify_shutdown_creds(
|
|||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED,
|
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED,
|
||||||
"Access denied to root due to active block inhibitor");
|
"Access denied to root due to active block inhibitor");
|
||||||
|
|
||||||
if (action_ignore_inhibit) {
|
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
|
||||||
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
|
if (r < 0)
|
||||||
if (r < 0)
|
return r;
|
||||||
return r;
|
if (r == 0)
|
||||||
if (r == 0)
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!multiple_sessions && !blocked && action) {
|
if (!multiple_sessions && !blocked) {
|
||||||
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
|
r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -1208,6 +1208,7 @@ int image_read_metadata(Image *i) {
|
|||||||
DISSECT_IMAGE_GENERIC_ROOT |
|
DISSECT_IMAGE_GENERIC_ROOT |
|
||||||
DISSECT_IMAGE_REQUIRE_ROOT |
|
DISSECT_IMAGE_REQUIRE_ROOT |
|
||||||
DISSECT_IMAGE_RELAX_VAR_CHECK |
|
DISSECT_IMAGE_RELAX_VAR_CHECK |
|
||||||
|
DISSECT_IMAGE_READ_ONLY |
|
||||||
DISSECT_IMAGE_USR_NO_ROOT,
|
DISSECT_IMAGE_USR_NO_ROOT,
|
||||||
&m);
|
&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -448,6 +448,29 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) {
|
|||||||
return 1 << idx;
|
return 1 << idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_noreturn_ void freeze(void) {
|
||||||
|
log_close();
|
||||||
|
|
||||||
|
/* Make sure nobody waits for us on a socket anymore */
|
||||||
|
(void) close_all_fds_full(NULL, 0, false);
|
||||||
|
|
||||||
|
sync();
|
||||||
|
|
||||||
|
/* Let's not freeze right away, but keep reaping zombies. */
|
||||||
|
for (;;) {
|
||||||
|
int r;
|
||||||
|
siginfo_t si = {};
|
||||||
|
|
||||||
|
r = waitid(P_ALL, 0, &si, WEXITED);
|
||||||
|
if (r < 0 && errno != EINTR)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* waitid() failed with an unexpected error, things are really borked. Freeze now! */
|
||||||
|
for (;;)
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
|
||||||
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
|
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
|
||||||
#if ENABLE_FEXECVE
|
#if ENABLE_FEXECVE
|
||||||
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
|
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
|
||||||
@ -470,3 +493,76 @@ int fexecve_or_execve(int executable_fd, const char *executable, char *const arg
|
|||||||
execve(executable, argv, envp);
|
execve(executable, argv, envp);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fork_agent(const char *name, int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
|
||||||
|
bool stdout_is_tty, stderr_is_tty;
|
||||||
|
size_t n, i;
|
||||||
|
va_list ap;
|
||||||
|
char **l;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
/* Spawns a temporary TTY agent, making sure it goes away when we go away */
|
||||||
|
|
||||||
|
r = safe_fork_full(name,
|
||||||
|
except,
|
||||||
|
n_except,
|
||||||
|
FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
|
||||||
|
ret_pid);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* In the child: */
|
||||||
|
|
||||||
|
stdout_is_tty = isatty(STDOUT_FILENO);
|
||||||
|
stderr_is_tty = isatty(STDERR_FILENO);
|
||||||
|
|
||||||
|
if (!stdout_is_tty || !stderr_is_tty) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Detach from stdout/stderr and reopen /dev/tty for them. This is important to ensure that
|
||||||
|
* when systemctl is started via popen() or a similar call that expects to read EOF we
|
||||||
|
* actually do generate EOF and not delay this indefinitely by keeping an unused copy of
|
||||||
|
* stdin around. */
|
||||||
|
fd = open("/dev/tty", O_WRONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_error_errno(errno, "Failed to open /dev/tty: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
|
||||||
|
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
|
||||||
|
log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_close_above_stdio(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) rlimit_nofile_safe();
|
||||||
|
|
||||||
|
/* Count arguments */
|
||||||
|
va_start(ap, path);
|
||||||
|
for (n = 0; va_arg(ap, char*); n++)
|
||||||
|
;
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/* Allocate strv */
|
||||||
|
l = newa(char*, n + 1);
|
||||||
|
|
||||||
|
/* Fill in arguments */
|
||||||
|
va_start(ap, path);
|
||||||
|
for (i = 0; i <= n; i++)
|
||||||
|
l[i] = va_arg(ap, char*);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
execv(path, l);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|||||||
@ -47,4 +47,8 @@ extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
|
|||||||
const char* exec_command_flags_to_string(ExecCommandFlags i);
|
const char* exec_command_flags_to_string(ExecCommandFlags i);
|
||||||
ExecCommandFlags exec_command_flags_from_string(const char *s);
|
ExecCommandFlags exec_command_flags_from_string(const char *s);
|
||||||
|
|
||||||
|
_noreturn_ void freeze(void);
|
||||||
|
|
||||||
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);
|
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);
|
||||||
|
|
||||||
|
int fork_agent(const char *name, int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) _sentinel_;
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "dissect-image.h"
|
#include "dissect-image.h"
|
||||||
|
#include "exec-util.h"
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
@ -1010,11 +1011,9 @@ static int make_userns(uid_t uid_shift, uid_t uid_range) {
|
|||||||
r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
|
r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0) {
|
if (r == 0)
|
||||||
/* Child. We do nothing here, just freeze until somebody kills us. */
|
/* Child. We do nothing here, just freeze until somebody kills us. */
|
||||||
freeze();
|
freeze();
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, uid_shift, uid_range);
|
xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, uid_shift, uid_range);
|
||||||
|
|
||||||
|
|||||||
@ -310,6 +310,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
|
|||||||
"getpgrp\0"
|
"getpgrp\0"
|
||||||
"getpid\0"
|
"getpid\0"
|
||||||
"getppid\0"
|
"getppid\0"
|
||||||
|
"getrandom\0"
|
||||||
"getresgid\0"
|
"getresgid\0"
|
||||||
"getresgid32\0"
|
"getresgid32\0"
|
||||||
"getresuid\0"
|
"getresuid\0"
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "exec-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "spawn-ask-password-agent.h"
|
#include "spawn-ask-password-agent.h"
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "exec-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|||||||
@ -26,6 +26,7 @@ done
|
|||||||
|
|
||||||
# figure out if we have entered the rate limit state
|
# figure out if we have entered the rate limit state
|
||||||
|
|
||||||
|
entered_rl=0
|
||||||
exited_rl=0
|
exited_rl=0
|
||||||
timeout="$(date -ud "2 minutes" +%s)"
|
timeout="$(date -ud "2 minutes" +%s)"
|
||||||
while [[ $(date -u +%s) -le ${timeout} ]]; do
|
while [[ $(date -u +%s) -le ${timeout} ]]; do
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user