mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-12 08:58:20 +03:00
Merge pull request #8940 from poettering/nspawn-attrs
nspawn: make a couple of additional container parameters configurable
This commit is contained in:
commit
7fbb5dd5e2
@ -373,6 +373,22 @@
|
||||
instead.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--hostname=</option></term>
|
||||
|
||||
<listitem><para>Controls the hostname to set within the container, if different from the machine name. Expects
|
||||
a valid hostname as argument. If this option is used, the kernel hostname of the container will be set to this
|
||||
value, otherwise it will be initialized to the machine name as controlled by the <option>--machine=</option>
|
||||
option described above. The machine name is used for various aspect of identification of the container from the
|
||||
outside, the kernel hostname configurable with this option is useful for the container to identify itself from
|
||||
the inside. It is usually a good idea to keep both forms of identification synchronized, in order to avoid
|
||||
confusion. It is hence recommended to avoid usage of this option, and use <option>--machine=</option>
|
||||
exclusively. Note that regardless whether the container's hostname is initialized from the name set with
|
||||
<option>--hostname=</option> or the one set with <option>--machine=</option>, the container can later override
|
||||
its kernel hostname freely on its own as well.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--uuid=</option></term>
|
||||
|
||||
@ -717,13 +733,24 @@
|
||||
above).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-new-privileges=</option></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. Specifies the value of the <constant>PR_SET_NO_NEW_PRIVS</constant>
|
||||
flag for the container payload. Defaults to off. When turned on the payload code of the container cannot
|
||||
acquire new privileges, i.e. the "setuid" file bit as well as file system capabilities will not have an effect
|
||||
anymore. See <citerefentry
|
||||
project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details
|
||||
about this flag. </para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--system-call-filter=</option></term>
|
||||
|
||||
<listitem><para>Alter the system call filter applied to containers. Takes a space-separated list of system call
|
||||
names or group names (the latter prefixed with <literal>@</literal>, as listed by the
|
||||
<command>syscall-filter</command> command of <citerefentry
|
||||
project='man-pages'><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
|
||||
<command>syscall-filter</command> command of
|
||||
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
|
||||
system calls will be permitted. The list may optionally be prefixed by <literal>~</literal>, in which case all
|
||||
listed system calls are prohibited. If this command line option is used multiple times the configured lists are
|
||||
combined. If both a positive and a negative list (that is one system call list without and one with the
|
||||
@ -734,16 +761,60 @@
|
||||
capabilities are passed using the <command>--capabilities=</command>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--rlimit=</option></term>
|
||||
|
||||
<listitem><para>Sets the specified POSIX resource limit for the container payload. Expects an assignment of the
|
||||
form
|
||||
<literal><replaceable>LIMIT</replaceable>=<replaceable>SOFT</replaceable>:<replaceable>HARD</replaceable></literal>
|
||||
or <literal><replaceable>LIMIT</replaceable>=<replaceable>VALUE</replaceable></literal>, where
|
||||
<replaceable>LIMIT</replaceable> should refer to a resource limit type, such as
|
||||
<constant>RLIMIT_NOFILE</constant> or <constant>RLIMIT_NICE</constant>. The <replaceable>SOFT</replaceable> and
|
||||
<replaceable>HARD</replaceable> fields should refer to the numeric soft and hard resource limit values. If the
|
||||
second form is used, <replaceable>VALUE</replaceable> may specifiy a value that is used both as soft and hard
|
||||
limit. In place of a numeric value the special string <literal>infinity</literal> may be used to turn off
|
||||
resource limiting for the specific type of resource. This command line option may be used multiple times to
|
||||
control limits on multiple limit types. If used multiple times for the same limit type, the last last use
|
||||
wins. For details about resource limits see <citerefentry
|
||||
project='man-pages'><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>. By default
|
||||
resource limits for the container's init process (PID 1) are set to the same values the Linux kernel originally
|
||||
passed to the host init system. Note that some resource limits are enforced on resources counted per user, in
|
||||
particular <constant>RLIMIT_NPROC</constant>. This means that unless user namespacing is deployed
|
||||
(i.e. <option>--private-users=</option> is used, see above), any limits set will be applied to the resource
|
||||
usage of the same user on all local containers as well as the host. This means particular care needs to be
|
||||
taken with these limits as they might be triggered by possibly less trusted code. Example:
|
||||
<literal>--rlimit=RLIMIT_NOFILE=8192:16384</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--oom-score-adjust=</option></term>
|
||||
|
||||
<listitem><para>Changes the OOM ("Out Of Memory") score adjustment value for the container payload. This controls
|
||||
<filename>/proc/self/oom_score_adj</filename> which influences the preference with which this container is
|
||||
terminated when memory becomes scarce. For details see <citerefentry
|
||||
project='man-pages'><refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Takes an
|
||||
integer in the range -1000…1000.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--cpu-affinity=</option></term>
|
||||
|
||||
<listitem><para>Controls the CPU affinity of the container payload. Takes a comma separated list of CPU numbers
|
||||
or number ranges (the latter's start and end value separated by dashes). See <citerefentry
|
||||
project='man-pages'><refentrytitle>sched_setaffinity</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--kill-signal=</option></term>
|
||||
|
||||
<listitem><para>Specify the process signal to send to the
|
||||
container's PID 1 when nspawn itself receives SIGTERM, in
|
||||
order to trigger an orderly shutdown of the
|
||||
container. Defaults to SIGRTMIN+3 if <option>--boot</option>
|
||||
is used (on systemd-compatible init systems SIGRTMIN+3
|
||||
triggers an orderly shutdown). For a list of valid signals, see
|
||||
<citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
|
||||
<listitem><para>Specify the process signal to send to the container's PID 1 when nspawn itself receives
|
||||
<constant>SIGTERM</constant>, in order to trigger an orderly shutdown of the container. Defaults to
|
||||
<constant>SIGRTMIN+3</constant> if <option>--boot</option> is used (on systemd-compatible init systems
|
||||
<constant>SIGRTMIN+3</constant> triggers an orderly shutdown). If <option>--boot</option> is not used and this
|
||||
option is not specified the container's processes are terminated abrubtly via <constant>SIGKILL</constant>. For
|
||||
a list of valid signals, see <citerefentry
|
||||
project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -222,6 +222,17 @@
|
||||
all cases.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>NoNewPrivileges=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument that controls the <constant>PR_SET_NO_NEW_PRIVS</constant> flag for
|
||||
the container payload. This is equivalent to the
|
||||
<option>--no-new-privileges=</option> command line switch. See
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>KillSignal=</varname></term>
|
||||
|
||||
@ -278,6 +289,57 @@
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LimitCPU=</varname></term>
|
||||
<term><varname>LimitFSIZE=</varname></term>
|
||||
<term><varname>LimitDATA=</varname></term>
|
||||
<term><varname>LimitSTACK=</varname></term>
|
||||
<term><varname>LimitCORE=</varname></term>
|
||||
<term><varname>LimitRSS=</varname></term>
|
||||
<term><varname>LimitNOFILE=</varname></term>
|
||||
<term><varname>LimitAS=</varname></term>
|
||||
<term><varname>LimitNPROC=</varname></term>
|
||||
<term><varname>LimitMEMLOCK=</varname></term>
|
||||
<term><varname>LimitLOCKS=</varname></term>
|
||||
<term><varname>LimitSIGPENDING=</varname></term>
|
||||
<term><varname>LimitMSGQUEUE=</varname></term>
|
||||
<term><varname>LimitNICE=</varname></term>
|
||||
<term><varname>LimitRTPRIO=</varname></term>
|
||||
<term><varname>LimitRTTIME=</varname></term>
|
||||
|
||||
<listitem><para>Configures various types of resource limits applied to containers. This is equivalent to the
|
||||
<option>--rlimit=</option> command line switch, and takes the same arguments. See
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>OOMScoreAdjust=</varname></term>
|
||||
|
||||
<listitem><para>Configures the OOM score adjustment value. This is equivalent to the
|
||||
<option>--oom-score-adjust=</option> command line switch, and takes the same argument. See
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>CPUAffinity=</varname></term>
|
||||
|
||||
<listitem><para>Configures the CPU affinity. This is equivalent to the <option>--cpu-affinity=</option> command
|
||||
line switch, and takes the same argument. See
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Hostname=</varname></term>
|
||||
|
||||
<listitem><para>Configures the kernel hostname set for the container. This is equivalent to the
|
||||
<option>--hostname=</option> command line switch, and takes the same argument. See
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
@ -199,15 +199,22 @@ int close_all_fds(const int except[], size_t n_except) {
|
||||
|
||||
d = opendir("/proc/self/fd");
|
||||
if (!d) {
|
||||
int fd;
|
||||
struct rlimit rl;
|
||||
int fd, max_fd;
|
||||
|
||||
/* When /proc isn't available (for example in chroots)
|
||||
* the fallback is brute forcing through the fd
|
||||
/* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd
|
||||
* table */
|
||||
|
||||
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
|
||||
for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
|
||||
|
||||
if (rl.rlim_max == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Let's take special care if the resource limit is set to unlimited, or actually larger than the range
|
||||
* of 'int'. Let's avoid implicit overflows. */
|
||||
max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1);
|
||||
|
||||
for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
|
||||
int q;
|
||||
|
||||
if (fd_in_set(fd, except, n_except))
|
||||
|
@ -676,3 +676,20 @@ int parse_dev(const char *s, dev_t *ret) {
|
||||
*ret = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_oom_score_adjust(const char *s, int *ret) {
|
||||
int r, v;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
r = safe_atoi(s, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = v;
|
||||
return 0;
|
||||
}
|
||||
|
@ -118,3 +118,5 @@ int parse_percent(const char *p);
|
||||
int parse_nice(const char *p, int *ret);
|
||||
|
||||
int parse_ip_port(const char *s, uint16_t *ret);
|
||||
|
||||
int parse_oom_score_adjust(const char *s, int *ret);
|
||||
|
@ -685,11 +685,12 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
|
||||
return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
|
||||
|
||||
path_kill_slashes(p);
|
||||
if (suppress_root && path_equal(p, "/"))
|
||||
if (suppress_root && empty_or_root(p))
|
||||
p = mfree(p);
|
||||
|
||||
free(*arg);
|
||||
*arg = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1445,6 +1445,15 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int set_oom_score_adjust(int value) {
|
||||
char t[DECIMAL_STR_MAX(int)];
|
||||
|
||||
sprintf(t, "%i", value);
|
||||
|
||||
return write_string_file("/proc/self/oom_score_adj", t,
|
||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
|
@ -173,6 +173,8 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
||||
|
||||
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...);
|
||||
|
||||
int set_oom_score_adjust(int value);
|
||||
|
||||
#if SIZEOF_PID_T == 4
|
||||
/* The highest possibly (theoretic) pid_t value on this architecture. */
|
||||
#define PID_T_MAX ((pid_t) INT32_MAX)
|
||||
|
@ -33,6 +33,11 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
|
||||
if (getrlimit(resource, &highest) < 0)
|
||||
return -errno;
|
||||
|
||||
/* If the hard limit is unbounded anyway, then the EPERM had other reasons, let's propagate the original EPERM
|
||||
* then */
|
||||
if (highest.rlim_max == RLIM_INFINITY)
|
||||
return -EPERM;
|
||||
|
||||
fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
|
||||
fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
|
||||
|
||||
@ -42,6 +47,32 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setrlimit_closest_all(const struct rlimit *const *rlim, int *which_failed) {
|
||||
int i, r;
|
||||
|
||||
assert(rlim);
|
||||
|
||||
/* On failure returns the limit's index that failed in *which_failed, but only if non-NULL */
|
||||
|
||||
for (i = 0; i < _RLIMIT_MAX; i++) {
|
||||
if (!rlim[i])
|
||||
continue;
|
||||
|
||||
r = setrlimit_closest(i, rlim[i]);
|
||||
if (r < 0) {
|
||||
if (which_failed)
|
||||
*which_failed = i;
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (which_failed)
|
||||
*which_failed = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rlimit_parse_u64(const char *val, rlim_t *ret) {
|
||||
uint64_t u;
|
||||
int r;
|
||||
@ -289,22 +320,48 @@ int rlimit_format(const struct rlimit *rl, char **ret) {
|
||||
}
|
||||
|
||||
static const char* const rlimit_table[_RLIMIT_MAX] = {
|
||||
[RLIMIT_CPU] = "LimitCPU",
|
||||
[RLIMIT_FSIZE] = "LimitFSIZE",
|
||||
[RLIMIT_DATA] = "LimitDATA",
|
||||
[RLIMIT_STACK] = "LimitSTACK",
|
||||
[RLIMIT_CORE] = "LimitCORE",
|
||||
[RLIMIT_RSS] = "LimitRSS",
|
||||
[RLIMIT_NOFILE] = "LimitNOFILE",
|
||||
[RLIMIT_AS] = "LimitAS",
|
||||
[RLIMIT_NPROC] = "LimitNPROC",
|
||||
[RLIMIT_MEMLOCK] = "LimitMEMLOCK",
|
||||
[RLIMIT_LOCKS] = "LimitLOCKS",
|
||||
[RLIMIT_SIGPENDING] = "LimitSIGPENDING",
|
||||
[RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
|
||||
[RLIMIT_NICE] = "LimitNICE",
|
||||
[RLIMIT_RTPRIO] = "LimitRTPRIO",
|
||||
[RLIMIT_RTTIME] = "LimitRTTIME"
|
||||
[RLIMIT_AS] = "AS",
|
||||
[RLIMIT_CORE] = "CORE",
|
||||
[RLIMIT_CPU] = "CPU",
|
||||
[RLIMIT_DATA] = "DATA",
|
||||
[RLIMIT_FSIZE] = "FSIZE",
|
||||
[RLIMIT_LOCKS] = "LOCKS",
|
||||
[RLIMIT_MEMLOCK] = "MEMLOCK",
|
||||
[RLIMIT_MSGQUEUE] = "MSGQUEUE",
|
||||
[RLIMIT_NICE] = "NICE",
|
||||
[RLIMIT_NOFILE] = "NOFILE",
|
||||
[RLIMIT_NPROC] = "NPROC",
|
||||
[RLIMIT_RSS] = "RSS",
|
||||
[RLIMIT_RTPRIO] = "RTPRIO",
|
||||
[RLIMIT_RTTIME] = "RTTIME",
|
||||
[RLIMIT_SIGPENDING] = "SIGPENDING",
|
||||
[RLIMIT_STACK] = "STACK",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
|
||||
|
||||
int rlimit_from_string_harder(const char *s) {
|
||||
const char *suffix;
|
||||
|
||||
/* The official prefix */
|
||||
suffix = startswith(s, "RLIMIT_");
|
||||
if (suffix)
|
||||
return rlimit_from_string(suffix);
|
||||
|
||||
/* Our own unit file setting prefix */
|
||||
suffix = startswith(s, "Limit");
|
||||
if (suffix)
|
||||
return rlimit_from_string(suffix);
|
||||
|
||||
return rlimit_from_string(s);
|
||||
}
|
||||
|
||||
void rlimit_free_all(struct rlimit **rl) {
|
||||
int i;
|
||||
|
||||
if (!rl)
|
||||
return;
|
||||
|
||||
for (i = 0; i < _RLIMIT_MAX; i++)
|
||||
rl[i] = mfree(rl[i]);
|
||||
}
|
||||
|
@ -13,12 +13,16 @@
|
||||
|
||||
const char *rlimit_to_string(int i) _const_;
|
||||
int rlimit_from_string(const char *s) _pure_;
|
||||
int rlimit_from_string_harder(const char *s) _pure_;
|
||||
|
||||
int setrlimit_closest(int resource, const struct rlimit *rlim);
|
||||
int setrlimit_closest_all(const struct rlimit * const *rlim, int *which_failed);
|
||||
|
||||
int rlimit_parse_one(int resource, const char *val, rlim_t *ret);
|
||||
int rlimit_parse(int resource, const char *val, struct rlimit *ret);
|
||||
|
||||
int rlimit_format(const struct rlimit *rl, char **ret);
|
||||
|
||||
void rlimit_free_all(struct rlimit **rl);
|
||||
|
||||
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
|
||||
|
@ -1091,8 +1091,8 @@ int bus_exec_context_set_transient_property(
|
||||
UnitWriteFlags flags,
|
||||
sd_bus_error *error) {
|
||||
|
||||
const char *soft = NULL;
|
||||
int r, ri;
|
||||
const char *suffix;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(c);
|
||||
@ -2313,73 +2313,77 @@ int bus_exec_context_set_transient_property(
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ri = rlimit_from_string(name);
|
||||
if (ri < 0) {
|
||||
soft = endswith(name, "Soft");
|
||||
if (soft) {
|
||||
const char *n;
|
||||
} else if ((suffix = startswith(name, "Limit"))) {
|
||||
const char *soft = NULL;
|
||||
int ri;
|
||||
|
||||
n = strndupa(name, soft - name);
|
||||
ri = rlimit_from_string(n);
|
||||
if (ri >= 0)
|
||||
name = n;
|
||||
ri = rlimit_from_string(suffix);
|
||||
if (ri < 0) {
|
||||
soft = endswith(suffix, "Soft");
|
||||
if (soft) {
|
||||
const char *n;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ri >= 0) {
|
||||
uint64_t rl;
|
||||
rlim_t x;
|
||||
|
||||
r = sd_bus_message_read(message, "t", &rl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (rl == (uint64_t) -1)
|
||||
x = RLIM_INFINITY;
|
||||
else {
|
||||
x = (rlim_t) rl;
|
||||
|
||||
if ((uint64_t) x != rl)
|
||||
return -ERANGE;
|
||||
n = strndupa(suffix, soft - suffix);
|
||||
ri = rlimit_from_string(n);
|
||||
if (ri >= 0)
|
||||
name = strjoina("Limit", n);
|
||||
}
|
||||
}
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
struct rlimit nl;
|
||||
if (ri >= 0) {
|
||||
uint64_t rl;
|
||||
rlim_t x;
|
||||
|
||||
if (c->rlimit[ri]) {
|
||||
nl = *c->rlimit[ri];
|
||||
|
||||
if (soft)
|
||||
nl.rlim_cur = x;
|
||||
else
|
||||
nl.rlim_max = x;
|
||||
} else
|
||||
/* When the resource limit is not initialized yet, then assign the value to both fields */
|
||||
nl = (struct rlimit) {
|
||||
.rlim_cur = x,
|
||||
.rlim_max = x,
|
||||
};
|
||||
|
||||
r = rlimit_format(&nl, &f);
|
||||
r = sd_bus_message_read(message, "t", &rl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c->rlimit[ri])
|
||||
*c->rlimit[ri] = nl;
|
||||
if (rl == (uint64_t) -1)
|
||||
x = RLIM_INFINITY;
|
||||
else {
|
||||
c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
|
||||
if (!c->rlimit[ri])
|
||||
return -ENOMEM;
|
||||
x = (rlim_t) rl;
|
||||
|
||||
if ((uint64_t) x != rl)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
unit_write_settingf(u, flags, name, "%s=%s", name, f);
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
struct rlimit nl;
|
||||
|
||||
if (c->rlimit[ri]) {
|
||||
nl = *c->rlimit[ri];
|
||||
|
||||
if (soft)
|
||||
nl.rlim_cur = x;
|
||||
else
|
||||
nl.rlim_max = x;
|
||||
} else
|
||||
/* When the resource limit is not initialized yet, then assign the value to both fields */
|
||||
nl = (struct rlimit) {
|
||||
.rlim_cur = x,
|
||||
.rlim_max = x,
|
||||
};
|
||||
|
||||
r = rlimit_format(&nl, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (c->rlimit[ri])
|
||||
*c->rlimit[ri] = nl;
|
||||
else {
|
||||
c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
|
||||
if (!c->rlimit[ri])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
unit_write_settingf(u, flags, name, "%s=%s", name, f);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2727,7 +2727,7 @@ static int exec_child(
|
||||
#endif
|
||||
uid_t uid = UID_INVALID;
|
||||
gid_t gid = GID_INVALID;
|
||||
int i, r, ngids = 0;
|
||||
int r, ngids = 0;
|
||||
size_t n_fds;
|
||||
ExecDirectoryType dt;
|
||||
int secure_bits;
|
||||
@ -2916,15 +2916,9 @@ static int exec_child(
|
||||
}
|
||||
|
||||
if (context->oom_score_adjust_set) {
|
||||
char t[DECIMAL_STR_MAX(context->oom_score_adjust)];
|
||||
|
||||
/* When we can't make this change due to EPERM, then
|
||||
* let's silently skip over it. User namespaces
|
||||
* prohibit write access to this file, and we
|
||||
* shouldn't trip up over that. */
|
||||
|
||||
sprintf(t, "%i", context->oom_score_adjust);
|
||||
r = write_string_file("/proc/self/oom_score_adj", t, 0);
|
||||
/* When we can't make this change due to EPERM, then let's silently skip over it. User namespaces
|
||||
* prohibit write access to this file, and we shouldn't trip up over that. */
|
||||
r = set_oom_score_adjust(context->oom_score_adjust);
|
||||
if (IN_SET(r, -EPERM, -EACCES))
|
||||
log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
|
||||
else if (r < 0) {
|
||||
@ -3167,17 +3161,12 @@ static int exec_child(
|
||||
|
||||
if (needs_sandboxing) {
|
||||
uint64_t bset;
|
||||
int which_failed;
|
||||
|
||||
for (i = 0; i < _RLIMIT_MAX; i++) {
|
||||
|
||||
if (!context->rlimit[i])
|
||||
continue;
|
||||
|
||||
r = setrlimit_closest(i, context->rlimit[i]);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_LIMITS;
|
||||
return log_unit_error_errno(unit, r, "Failed to adjust resource limit %s: %m", rlimit_to_string(i));
|
||||
}
|
||||
r = setrlimit_closest_all((const struct rlimit* const *) context->rlimit, &which_failed);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_LIMITS;
|
||||
return log_unit_error_errno(unit, r, "Failed to adjust resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
|
||||
}
|
||||
|
||||
/* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
|
||||
@ -3574,8 +3563,7 @@ void exec_context_done(ExecContext *c) {
|
||||
c->pass_environment = strv_free(c->pass_environment);
|
||||
c->unset_environment = strv_free(c->unset_environment);
|
||||
|
||||
for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
|
||||
c->rlimit[l] = mfree(c->rlimit[l]);
|
||||
rlimit_free_all(c->rlimit);
|
||||
|
||||
for (l = 0; l < 3; l++) {
|
||||
c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
|
||||
@ -3975,9 +3963,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||
|
||||
for (i = 0; i < RLIM_NLIMITS; i++)
|
||||
if (c->rlimit[i]) {
|
||||
fprintf(f, "%s%s: " RLIM_FMT "\n",
|
||||
fprintf(f, "Limit%s%s: " RLIM_FMT "\n",
|
||||
prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
|
||||
fprintf(f, "%s%sSoft: " RLIM_FMT "\n",
|
||||
fprintf(f, "Limit%s%sSoft: " RLIM_FMT "\n",
|
||||
prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
|
||||
}
|
||||
|
||||
|
@ -82,22 +82,22 @@ $1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CO
|
||||
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||
$1.LockPersonality, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
|
||||
$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitFSIZE, config_parse_rlimit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitDATA, config_parse_rlimit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSTACK, config_parse_rlimit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitCORE, config_parse_rlimit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRSS, config_parse_rlimit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNOFILE, config_parse_rlimit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitAS, config_parse_rlimit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNPROC, config_parse_rlimit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMEMLOCK, config_parse_rlimit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitLOCKS, config_parse_rlimit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitSIGPENDING, config_parse_rlimit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
|
||||
$1.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
|
||||
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
|
||||
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
|
||||
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#if HAVE_SECCOMP
|
||||
#include "seccomp-util.h"
|
||||
#endif
|
||||
@ -507,16 +506,17 @@ int config_parse_exec_nice(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_exec_oom_score_adjust(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) {
|
||||
int config_parse_exec_oom_score_adjust(
|
||||
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) {
|
||||
|
||||
ExecContext *c = data;
|
||||
int oa, r;
|
||||
@ -526,14 +526,18 @@ int config_parse_exec_oom_score_adjust(const char* unit,
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = safe_atoi(rvalue, &oa);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
|
||||
if (isempty(rvalue)) {
|
||||
c->oom_score_adjust_set = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
|
||||
r = parse_oom_score_adjust(rvalue, &oa);
|
||||
if (r == -ERANGE) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1370,47 +1374,6 @@ int config_parse_capability_set(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_limit(
|
||||
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) {
|
||||
|
||||
struct rlimit **rl = data, d = {};
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = rlimit_parse(ltype, rvalue, &d);
|
||||
if (r == -EILSEQ) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rl[ltype])
|
||||
*rl[ltype] = d;
|
||||
else {
|
||||
rl[ltype] = newdup(struct rlimit, &d, 1);
|
||||
if (!rl[ltype])
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAVE_SYSV_COMPAT
|
||||
int config_parse_sysv_priority(const char *unit,
|
||||
const char *filename,
|
||||
@ -4926,7 +4889,7 @@ void unit_dump_config_items(FILE *f) {
|
||||
{ config_parse_log_level, "LEVEL" },
|
||||
{ config_parse_exec_secure_bits, "SECUREBITS" },
|
||||
{ config_parse_capability_set, "BOUNDINGSET" },
|
||||
{ config_parse_limit, "LIMIT" },
|
||||
{ config_parse_rlimit, "LIMIT" },
|
||||
{ config_parse_unit_deps, "UNIT [...]" },
|
||||
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
|
||||
{ config_parse_service_type, "SERVICETYPE" },
|
||||
|
@ -43,7 +43,6 @@ int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, uns
|
||||
int config_parse_exec_cpu_affinity(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);
|
||||
int config_parse_exec_secure_bits(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);
|
||||
int config_parse_capability_set(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);
|
||||
int config_parse_limit(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);
|
||||
int config_parse_sysv_priority(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);
|
||||
int config_parse_kill_signal(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);
|
||||
int config_parse_exec_mount_flags(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);
|
||||
|
@ -675,22 +675,22 @@ static int parse_config_file(void) {
|
||||
{ "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
|
||||
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
|
||||
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
|
||||
{ "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitCPU", config_parse_rlimit, RLIMIT_CPU, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitFSIZE", config_parse_rlimit, RLIMIT_FSIZE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitDATA", config_parse_rlimit, RLIMIT_DATA, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitSTACK", config_parse_rlimit, RLIMIT_STACK, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitCORE", config_parse_rlimit, RLIMIT_CORE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRSS", config_parse_rlimit, RLIMIT_RSS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNOFILE", config_parse_rlimit, RLIMIT_NOFILE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitAS", config_parse_rlimit, RLIMIT_AS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNPROC", config_parse_rlimit, RLIMIT_NPROC, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitMEMLOCK", config_parse_rlimit, RLIMIT_MEMLOCK, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitLOCKS", config_parse_rlimit, RLIMIT_LOCKS, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitSIGPENDING", config_parse_rlimit, RLIMIT_SIGPENDING, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitMSGQUEUE", config_parse_rlimit, RLIMIT_MSGQUEUE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitNICE", config_parse_rlimit, RLIMIT_NICE, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRTPRIO", config_parse_rlimit, RLIMIT_RTPRIO, arg_default_rlimit },
|
||||
{ "Manager", "DefaultLimitRTTIME", config_parse_rlimit, RLIMIT_RTTIME, arg_default_rlimit },
|
||||
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
|
||||
{ "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting },
|
||||
{ "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting },
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "ratelimit.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "signal-util.h"
|
||||
#include "socket-util.h"
|
||||
@ -1174,7 +1175,6 @@ static void manager_clear_jobs_and_units(Manager *m) {
|
||||
|
||||
Manager* manager_free(Manager *m) {
|
||||
UnitType c;
|
||||
int i;
|
||||
ExecDirectoryType dt;
|
||||
|
||||
if (!m)
|
||||
@ -1242,8 +1242,7 @@ Manager* manager_free(Manager *m) {
|
||||
free(m->switch_root);
|
||||
free(m->switch_root_init);
|
||||
|
||||
for (i = 0; i < _RLIMIT_MAX; i++)
|
||||
m->rlimit[i] = mfree(m->rlimit[i]);
|
||||
rlimit_free_all(m->rlimit);
|
||||
|
||||
assert(hashmap_isempty(m->units_requiring_mounts_for));
|
||||
hashmap_free(m->units_requiring_mounts_for);
|
||||
|
@ -18,35 +18,55 @@ struct ConfigPerfItem;
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Exec.Boot, config_parse_boot, 0, 0
|
||||
Exec.ProcessTwo, config_parse_pid2, 0, 0
|
||||
Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters)
|
||||
Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
|
||||
Exec.User, config_parse_string, 0, offsetof(Settings, user)
|
||||
Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability)
|
||||
Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability)
|
||||
Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal)
|
||||
Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
|
||||
Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
|
||||
Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
|
||||
Exec.PivotRoot, config_parse_pivot_root, 0, 0
|
||||
Exec.PrivateUsers, config_parse_private_users, 0, 0
|
||||
Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
|
||||
Exec.SystemCallFilter, config_parse_syscall_filter,0, 0,
|
||||
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
|
||||
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
|
||||
Files.Bind, config_parse_bind, 0, 0
|
||||
Files.BindReadOnly, config_parse_bind, 1, 0
|
||||
Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0
|
||||
Files.Overlay, config_parse_overlay, 0, 0
|
||||
Files.OverlayReadOnly, config_parse_overlay, 1, 0
|
||||
Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown)
|
||||
Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network)
|
||||
Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces)
|
||||
Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan)
|
||||
Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan)
|
||||
Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
|
||||
Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
|
||||
Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)
|
||||
Network.Zone, config_parse_network_zone, 0, 0
|
||||
Network.Port, config_parse_expose_port, 0, 0
|
||||
Exec.Boot, config_parse_boot, 0, 0
|
||||
Exec.ProcessTwo, config_parse_pid2, 0, 0
|
||||
Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters)
|
||||
Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
|
||||
Exec.User, config_parse_string, 0, offsetof(Settings, user)
|
||||
Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability)
|
||||
Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability)
|
||||
Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal)
|
||||
Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
|
||||
Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
|
||||
Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
|
||||
Exec.PivotRoot, config_parse_pivot_root, 0, 0
|
||||
Exec.PrivateUsers, config_parse_private_users, 0, 0
|
||||
Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
|
||||
Exec.SystemCallFilter, config_parse_syscall_filter, 0, 0,
|
||||
Exec.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof(Settings, rlimit)
|
||||
Exec.LimitFSIZE, config_parse_rlimit, RLIMIT_FSIZE, offsetof(Settings, rlimit)
|
||||
Exec.LimitDATA, config_parse_rlimit, RLIMIT_DATA, offsetof(Settings, rlimit)
|
||||
Exec.LimitSTACK, config_parse_rlimit, RLIMIT_STACK, offsetof(Settings, rlimit)
|
||||
Exec.LimitCORE, config_parse_rlimit, RLIMIT_CORE, offsetof(Settings, rlimit)
|
||||
Exec.LimitRSS, config_parse_rlimit, RLIMIT_RSS, offsetof(Settings, rlimit)
|
||||
Exec.LimitNOFILE, config_parse_rlimit, RLIMIT_NOFILE, offsetof(Settings, rlimit)
|
||||
Exec.LimitAS, config_parse_rlimit, RLIMIT_AS, offsetof(Settings, rlimit)
|
||||
Exec.LimitNPROC, config_parse_rlimit, RLIMIT_NPROC, offsetof(Settings, rlimit)
|
||||
Exec.LimitMEMLOCK, config_parse_rlimit, RLIMIT_MEMLOCK, offsetof(Settings, rlimit)
|
||||
Exec.LimitLOCKS, config_parse_rlimit, RLIMIT_LOCKS, offsetof(Settings, rlimit)
|
||||
Exec.LimitSIGPENDING, config_parse_rlimit, RLIMIT_SIGPENDING, offsetof(Settings, rlimit)
|
||||
Exec.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, offsetof(Settings, rlimit)
|
||||
Exec.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof(Settings, rlimit)
|
||||
Exec.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof(Settings, rlimit)
|
||||
Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof(Settings, rlimit)
|
||||
Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname)
|
||||
Exec.NoNewPrivileges, config_parse_tristate, 0, offsetof(Settings, no_new_privileges)
|
||||
Exec.OOMScoreAdjust, config_parse_oom_score_adjust, 0, 0
|
||||
Exec.CPUAffinity, config_parse_cpu_affinity, 0, 0
|
||||
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
|
||||
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
|
||||
Files.Bind, config_parse_bind, 0, 0
|
||||
Files.BindReadOnly, config_parse_bind, 1, 0
|
||||
Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0
|
||||
Files.Overlay, config_parse_overlay, 0, 0
|
||||
Files.OverlayReadOnly, config_parse_overlay, 1, 0
|
||||
Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown)
|
||||
Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network)
|
||||
Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces)
|
||||
Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan)
|
||||
Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan)
|
||||
Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
|
||||
Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
|
||||
Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)
|
||||
Network.Zone, config_parse_network_zone, 0, 0
|
||||
Network.Port, config_parse_expose_port, 0, 0
|
||||
|
@ -8,10 +8,13 @@
|
||||
#include "alloc-util.h"
|
||||
#include "cap-list.h"
|
||||
#include "conf-parser.h"
|
||||
#include "cpu-set-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "nspawn-network.h"
|
||||
#include "nspawn-settings.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@ -34,6 +37,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
|
||||
s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
|
||||
s->uid_shift = UID_INVALID;
|
||||
s->uid_range = UID_INVALID;
|
||||
s->no_new_privileges = -1;
|
||||
|
||||
s->read_only = -1;
|
||||
s->volatile_mode = _VOLATILE_MODE_INVALID;
|
||||
@ -80,6 +84,9 @@ Settings* settings_free(Settings *s) {
|
||||
free(s->working_directory);
|
||||
strv_free(s->syscall_whitelist);
|
||||
strv_free(s->syscall_blacklist);
|
||||
rlimit_free_all(s->rlimit);
|
||||
free(s->hostname);
|
||||
s->cpuset = cpu_set_mfree(s->cpuset);
|
||||
|
||||
strv_free(s->network_interfaces);
|
||||
strv_free(s->network_macvlan);
|
||||
@ -601,3 +608,119 @@ int config_parse_syscall_filter(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_hostname(
|
||||
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) {
|
||||
|
||||
char **s = data;
|
||||
|
||||
assert(rvalue);
|
||||
assert(s);
|
||||
|
||||
if (!hostname_is_valid(rvalue, false)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
|
||||
return log_oom();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_oom_score_adjust(
|
||||
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) {
|
||||
|
||||
Settings *settings = data;
|
||||
int oa, r;
|
||||
|
||||
assert(rvalue);
|
||||
assert(settings);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
settings->oom_score_adjust_set = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_oom_score_adjust(rvalue, &oa);
|
||||
if (r == -ERANGE) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
settings->oom_score_adjust = oa;
|
||||
settings->oom_score_adjust_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_cpu_affinity(
|
||||
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) {
|
||||
|
||||
_cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
|
||||
Settings *settings = data;
|
||||
int ncpus;
|
||||
|
||||
assert(rvalue);
|
||||
assert(settings);
|
||||
|
||||
ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
|
||||
if (ncpus < 0)
|
||||
return ncpus;
|
||||
|
||||
if (ncpus == 0) {
|
||||
/* An empty assignment resets the CPU list */
|
||||
settings->cpuset = cpu_set_mfree(settings->cpuset);
|
||||
settings->cpuset_ncpus = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!settings->cpuset) {
|
||||
settings->cpuset = TAKE_PTR(cpuset);
|
||||
settings->cpuset_ncpus = (unsigned) ncpus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (settings->cpuset_ncpus < (unsigned) ncpus) {
|
||||
CPU_OR_S(CPU_ALLOC_SIZE(settings->cpuset_ncpus), cpuset, settings->cpuset, cpuset);
|
||||
CPU_FREE(settings->cpuset);
|
||||
settings->cpuset = TAKE_PTR(cpuset);
|
||||
settings->cpuset_ncpus = (unsigned) ncpus;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus), settings->cpuset, settings->cpuset, cpuset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
Copyright 2015 Lennart Poettering
|
||||
***/
|
||||
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
@ -32,24 +33,30 @@ typedef enum UserNamespaceMode {
|
||||
} UserNamespaceMode;
|
||||
|
||||
typedef enum SettingsMask {
|
||||
SETTING_START_MODE = 1 << 0,
|
||||
SETTING_ENVIRONMENT = 1 << 1,
|
||||
SETTING_USER = 1 << 2,
|
||||
SETTING_CAPABILITY = 1 << 3,
|
||||
SETTING_KILL_SIGNAL = 1 << 4,
|
||||
SETTING_PERSONALITY = 1 << 5,
|
||||
SETTING_MACHINE_ID = 1 << 6,
|
||||
SETTING_NETWORK = 1 << 7,
|
||||
SETTING_EXPOSE_PORTS = 1 << 8,
|
||||
SETTING_READ_ONLY = 1 << 9,
|
||||
SETTING_VOLATILE_MODE = 1 << 10,
|
||||
SETTING_CUSTOM_MOUNTS = 1 << 11,
|
||||
SETTING_WORKING_DIRECTORY = 1 << 12,
|
||||
SETTING_USERNS = 1 << 13,
|
||||
SETTING_NOTIFY_READY = 1 << 14,
|
||||
SETTING_PIVOT_ROOT = 1 << 15,
|
||||
SETTING_SYSCALL_FILTER = 1 << 16,
|
||||
_SETTINGS_MASK_ALL = (1 << 17) -1
|
||||
SETTING_START_MODE = UINT64_C(1) << 0,
|
||||
SETTING_ENVIRONMENT = UINT64_C(1) << 1,
|
||||
SETTING_USER = UINT64_C(1) << 2,
|
||||
SETTING_CAPABILITY = UINT64_C(1) << 3,
|
||||
SETTING_KILL_SIGNAL = UINT64_C(1) << 4,
|
||||
SETTING_PERSONALITY = UINT64_C(1) << 5,
|
||||
SETTING_MACHINE_ID = UINT64_C(1) << 6,
|
||||
SETTING_NETWORK = UINT64_C(1) << 7,
|
||||
SETTING_EXPOSE_PORTS = UINT64_C(1) << 8,
|
||||
SETTING_READ_ONLY = UINT64_C(1) << 9,
|
||||
SETTING_VOLATILE_MODE = UINT64_C(1) << 10,
|
||||
SETTING_CUSTOM_MOUNTS = UINT64_C(1) << 11,
|
||||
SETTING_WORKING_DIRECTORY = UINT64_C(1) << 12,
|
||||
SETTING_USERNS = UINT64_C(1) << 13,
|
||||
SETTING_NOTIFY_READY = UINT64_C(1) << 14,
|
||||
SETTING_PIVOT_ROOT = UINT64_C(1) << 15,
|
||||
SETTING_SYSCALL_FILTER = UINT64_C(1) << 16,
|
||||
SETTING_HOSTNAME = UINT64_C(1) << 17,
|
||||
SETTING_NO_NEW_PRIVILEGES = UINT64_C(1) << 18,
|
||||
SETTING_OOM_SCORE_ADJUST = UINT64_C(1) << 19,
|
||||
SETTING_CPU_AFFINITY = UINT64_C(1) << 20,
|
||||
SETTING_RLIMIT_FIRST = UINT64_C(1) << 21, /* we define one bit per resource limit here */
|
||||
SETTING_RLIMIT_LAST = UINT64_C(1) << (21 + _RLIMIT_MAX - 1),
|
||||
_SETTINGS_MASK_ALL = (UINT64_C(1) << (21 + _RLIMIT_MAX)) - 1
|
||||
} SettingsMask;
|
||||
|
||||
typedef struct Settings {
|
||||
@ -71,6 +78,13 @@ typedef struct Settings {
|
||||
bool notify_ready;
|
||||
char **syscall_whitelist;
|
||||
char **syscall_blacklist;
|
||||
struct rlimit *rlimit[_RLIMIT_MAX];
|
||||
char *hostname;
|
||||
int no_new_privileges;
|
||||
int oom_score_adjust;
|
||||
bool oom_score_adjust_set;
|
||||
cpu_set_t *cpuset;
|
||||
unsigned cpuset_ncpus;
|
||||
|
||||
/* [Image] */
|
||||
int read_only;
|
||||
@ -115,3 +129,6 @@ int config_parse_boot(const char *unit, const char *filename, unsigned line, con
|
||||
int config_parse_pid2(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);
|
||||
int config_parse_private_users(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);
|
||||
int config_parse_syscall_filter(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);
|
||||
int config_parse_hostname(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);
|
||||
int config_parse_oom_score_adjust(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);
|
||||
int config_parse_cpu_affinity(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);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "capability-util.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "copy.h"
|
||||
#include "cpu-set-util.h"
|
||||
#include "dev-setup.h"
|
||||
#include "dissect-image.h"
|
||||
#include "env-util.h"
|
||||
@ -75,12 +76,14 @@
|
||||
#include "nspawn-settings.h"
|
||||
#include "nspawn-setuid.h"
|
||||
#include "nspawn-stub-pid1.h"
|
||||
#include "pager.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "ptyfwd.h"
|
||||
#include "random-util.h"
|
||||
#include "raw-clone.h"
|
||||
#include "rlimit-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "selinux-util.h"
|
||||
#include "signal-util.h"
|
||||
@ -127,7 +130,8 @@ static char *arg_pivot_root_new = NULL;
|
||||
static char *arg_pivot_root_old = NULL;
|
||||
static char *arg_user = NULL;
|
||||
static sd_id128_t arg_uuid = {};
|
||||
static char *arg_machine = NULL;
|
||||
static char *arg_machine = NULL; /* The name used by the host to refer to this */
|
||||
static char *arg_hostname = NULL; /* The name the payload sees by default */
|
||||
static const char *arg_selinux_context = NULL;
|
||||
static const char *arg_selinux_apifs_context = NULL;
|
||||
static const char *arg_slice = NULL;
|
||||
@ -200,8 +204,17 @@ static void *arg_root_hash = NULL;
|
||||
static size_t arg_root_hash_size = 0;
|
||||
static char **arg_syscall_whitelist = NULL;
|
||||
static char **arg_syscall_blacklist = NULL;
|
||||
static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
|
||||
static bool arg_no_new_privileges = false;
|
||||
static int arg_oom_score_adjust = 0;
|
||||
static bool arg_oom_score_adjust_set = false;
|
||||
static cpu_set_t *arg_cpuset = NULL;
|
||||
static unsigned arg_cpuset_ncpus = 0;
|
||||
|
||||
static void help(void) {
|
||||
|
||||
(void) pager_open(false, false);
|
||||
|
||||
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
|
||||
"Spawn a minimal namespace container for debugging, testing and building.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
@ -221,6 +234,7 @@ static void help(void) {
|
||||
" Pivot root to given directory in the container\n"
|
||||
" -u --user=USER Run the command under specified user or uid\n"
|
||||
" -M --machine=NAME Set the machine name for the container\n"
|
||||
" --hostname=NAME Override the hostname for the container\n"
|
||||
" --uuid=UUID Set a specific machine UUID for the container\n"
|
||||
" -S --slice=SLICE Place the container in the specified slice\n"
|
||||
" --property=NAME=VALUE Set scope unit property\n"
|
||||
@ -264,6 +278,10 @@ static void help(void) {
|
||||
" --drop-capability=CAP Drop the specified capability from the default set\n"
|
||||
" --system-call-filter=LIST|~LIST\n"
|
||||
" Permit/prohibit specific system calls\n"
|
||||
" --rlimit=NAME=LIMIT Set a resource limit for the payload\n"
|
||||
" --oom-score-adjust=VALUE\n"
|
||||
" Adjust the OOM score value for the payload\n"
|
||||
" --cpu-affinity=CPUS Adjust the CPU affinity of the container\n"
|
||||
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
|
||||
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
|
||||
" host, try-guest, try-host\n"
|
||||
@ -439,6 +457,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_NOTIFY_READY,
|
||||
ARG_ROOT_HASH,
|
||||
ARG_SYSTEM_CALL_FILTER,
|
||||
ARG_RLIMIT,
|
||||
ARG_HOSTNAME,
|
||||
ARG_NO_NEW_PRIVILEGES,
|
||||
ARG_OOM_SCORE_ADJUST,
|
||||
ARG_CPU_AFFINITY,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -455,6 +478,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
|
||||
{ "capability", required_argument, NULL, ARG_CAPABILITY },
|
||||
{ "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY },
|
||||
{ "no-new-privileges", required_argument, NULL, ARG_NO_NEW_PRIVILEGES },
|
||||
{ "link-journal", required_argument, NULL, ARG_LINK_JOURNAL },
|
||||
{ "bind", required_argument, NULL, ARG_BIND },
|
||||
{ "bind-ro", required_argument, NULL, ARG_BIND_RO },
|
||||
@ -462,6 +486,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "overlay", required_argument, NULL, ARG_OVERLAY },
|
||||
{ "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO },
|
||||
{ "machine", required_argument, NULL, 'M' },
|
||||
{ "hostname", required_argument, NULL, ARG_HOSTNAME },
|
||||
{ "slice", required_argument, NULL, 'S' },
|
||||
{ "setenv", required_argument, NULL, 'E' },
|
||||
{ "selinux-context", required_argument, NULL, 'Z' },
|
||||
@ -492,6 +517,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "notify-ready", required_argument, NULL, ARG_NOTIFY_READY },
|
||||
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
||||
{ "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER },
|
||||
{ "rlimit", required_argument, NULL, ARG_RLIMIT },
|
||||
{ "oom-score-adjust", required_argument, NULL, ARG_OOM_SCORE_ADJUST },
|
||||
{ "cpu-affinity", required_argument, NULL, ARG_CPU_AFFINITY },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -696,6 +724,23 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_HOSTNAME:
|
||||
if (isempty(optarg))
|
||||
arg_hostname = mfree(arg_hostname);
|
||||
else {
|
||||
if (!hostname_is_valid(optarg, false)) {
|
||||
log_error("Invalid hostname: %s", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = free_and_strdup(&arg_hostname, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
arg_settings_mask |= SETTING_HOSTNAME;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
arg_selinux_context = optarg;
|
||||
break;
|
||||
@ -747,6 +792,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_NO_NEW_PRIVILEGES:
|
||||
r = parse_boolean(optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --no-new-privileges= argument: %s", optarg);
|
||||
|
||||
arg_no_new_privileges = r;
|
||||
arg_settings_mask |= SETTING_NO_NEW_PRIVILEGES;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
arg_link_journal = LINK_GUEST;
|
||||
arg_link_journal_try = true;
|
||||
@ -1094,6 +1148,66 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_RLIMIT: {
|
||||
const char *eq;
|
||||
char *name;
|
||||
int rl;
|
||||
|
||||
eq = strchr(optarg, '=');
|
||||
if (!eq) {
|
||||
log_error("--rlimit= expects an '=' assignment.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
name = strndup(optarg, eq - optarg);
|
||||
if (!name)
|
||||
return log_oom();
|
||||
|
||||
rl = rlimit_from_string_harder(name);
|
||||
if (rl < 0) {
|
||||
log_error("Unknown resource limit: %s", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!arg_rlimit[rl]) {
|
||||
arg_rlimit[rl] = new0(struct rlimit, 1);
|
||||
if (!arg_rlimit[rl])
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = rlimit_parse(rl, eq + 1, arg_rlimit[rl]);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse resource limit: %s", eq + 1);
|
||||
|
||||
arg_settings_mask |= SETTING_RLIMIT_FIRST << rl;
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_OOM_SCORE_ADJUST:
|
||||
r = parse_oom_score_adjust(optarg, &arg_oom_score_adjust);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --oom-score-adjust= parameter: %s", optarg);
|
||||
|
||||
arg_oom_score_adjust_set = true;
|
||||
arg_settings_mask |= SETTING_OOM_SCORE_ADJUST;
|
||||
break;
|
||||
|
||||
case ARG_CPU_AFFINITY: {
|
||||
_cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
|
||||
|
||||
r = parse_cpu_set(optarg, &cpuset);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse CPU affinity mask: %s", optarg);
|
||||
|
||||
if (arg_cpuset)
|
||||
CPU_FREE(arg_cpuset);
|
||||
|
||||
arg_cpuset = TAKE_PTR(cpuset);
|
||||
arg_cpuset_ncpus = r;
|
||||
arg_settings_mask |= SETTING_CPU_AFFINITY;
|
||||
break;
|
||||
}
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -1718,12 +1832,14 @@ static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *user
|
||||
}
|
||||
|
||||
static int setup_hostname(void) {
|
||||
int r;
|
||||
|
||||
if ((arg_clone_ns_flags & CLONE_NEWUTS) == 0)
|
||||
return 0;
|
||||
|
||||
if (sethostname_idempotent(arg_machine) < 0)
|
||||
return -errno;
|
||||
r = sethostname_idempotent(arg_hostname ?: arg_machine);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set hostname: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2282,7 +2398,6 @@ static int inner_child(
|
||||
NULL
|
||||
};
|
||||
const char *exec_target;
|
||||
|
||||
_cleanup_strv_free_ char **env_use = NULL;
|
||||
int r;
|
||||
|
||||
@ -2377,11 +2492,21 @@ static int inner_child(
|
||||
rtnl_socket = safe_close(rtnl_socket);
|
||||
}
|
||||
|
||||
if (arg_oom_score_adjust_set) {
|
||||
r = set_oom_score_adjust(arg_oom_score_adjust);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to adjust OOM score: %m");
|
||||
}
|
||||
|
||||
if (arg_cpuset)
|
||||
if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
|
||||
return log_error_errno(errno, "Failed to set CPU affinity: %m");
|
||||
|
||||
r = drop_capabilities();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "drop_capabilities() failed: %m");
|
||||
|
||||
setup_hostname();
|
||||
(void) setup_hostname();
|
||||
|
||||
if (arg_personality != PERSONALITY_INVALID) {
|
||||
r = safe_personality(arg_personality);
|
||||
@ -2403,6 +2528,10 @@ static int inner_child(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_no_new_privileges)
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
|
||||
return log_error_errno(errno, "Failed to disable new privileges: %m");
|
||||
|
||||
/* LXC sets container=lxc, so follow the scheme here */
|
||||
envp[n_env++] = strjoina("container=", arg_container_service_name);
|
||||
|
||||
@ -2559,10 +2688,10 @@ static int outer_child(
|
||||
FDSet *fds,
|
||||
int netns_fd) {
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r, which_failed;
|
||||
pid_t pid;
|
||||
ssize_t l;
|
||||
int r;
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
assert(barrier);
|
||||
assert(directory);
|
||||
@ -2805,6 +2934,10 @@ static int outer_child(
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
r = setrlimit_closest_all((const struct rlimit *const*) arg_rlimit, &which_failed);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to apply resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
|
||||
|
||||
pid = raw_clone(SIGCHLD|CLONE_NEWNS|
|
||||
arg_clone_ns_flags |
|
||||
(arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0));
|
||||
@ -3041,6 +3174,206 @@ static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pi
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int merge_settings(Settings *settings, const char *path) {
|
||||
int rl;
|
||||
|
||||
assert(settings);
|
||||
assert(path);
|
||||
|
||||
/* Copy over bits from the settings, unless they have been explicitly masked by command line switches. Note
|
||||
* that this steals the fields of the Settings* structure, and hence modifies it. */
|
||||
|
||||
if ((arg_settings_mask & SETTING_START_MODE) == 0 &&
|
||||
settings->start_mode >= 0) {
|
||||
arg_start_mode = settings->start_mode;
|
||||
strv_free_and_replace(arg_parameters, settings->parameters);
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_PIVOT_ROOT) == 0 &&
|
||||
settings->pivot_root_new) {
|
||||
free_and_replace(arg_pivot_root_new, settings->pivot_root_new);
|
||||
free_and_replace(arg_pivot_root_old, settings->pivot_root_old);
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_WORKING_DIRECTORY) == 0 &&
|
||||
settings->working_directory)
|
||||
free_and_replace(arg_chdir, settings->working_directory);
|
||||
|
||||
if ((arg_settings_mask & SETTING_ENVIRONMENT) == 0 &&
|
||||
settings->environment)
|
||||
strv_free_and_replace(arg_setenv, settings->environment);
|
||||
|
||||
if ((arg_settings_mask & SETTING_USER) == 0 &&
|
||||
settings->user)
|
||||
free_and_replace(arg_user, settings->user);
|
||||
|
||||
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
|
||||
uint64_t plus;
|
||||
|
||||
plus = settings->capability;
|
||||
if (settings_private_network(settings))
|
||||
plus |= (1ULL << CAP_NET_ADMIN);
|
||||
|
||||
if (!arg_settings_trusted && plus != 0) {
|
||||
if (settings->capability != 0)
|
||||
log_warning("Ignoring Capability= setting, file %s is not trusted.", path);
|
||||
} else
|
||||
arg_caps_retain |= plus;
|
||||
|
||||
arg_caps_retain &= ~settings->drop_capability;
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 &&
|
||||
settings->kill_signal > 0)
|
||||
arg_kill_signal = settings->kill_signal;
|
||||
|
||||
if ((arg_settings_mask & SETTING_PERSONALITY) == 0 &&
|
||||
settings->personality != PERSONALITY_INVALID)
|
||||
arg_personality = settings->personality;
|
||||
|
||||
if ((arg_settings_mask & SETTING_MACHINE_ID) == 0 &&
|
||||
!sd_id128_is_null(settings->machine_id)) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring MachineID= setting, file %s is not trusted.", path);
|
||||
else
|
||||
arg_uuid = settings->machine_id;
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_READ_ONLY) == 0 &&
|
||||
settings->read_only >= 0)
|
||||
arg_read_only = settings->read_only;
|
||||
|
||||
if ((arg_settings_mask & SETTING_VOLATILE_MODE) == 0 &&
|
||||
settings->volatile_mode != _VOLATILE_MODE_INVALID)
|
||||
arg_volatile_mode = settings->volatile_mode;
|
||||
|
||||
if ((arg_settings_mask & SETTING_CUSTOM_MOUNTS) == 0 &&
|
||||
settings->n_custom_mounts > 0) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring TemporaryFileSystem=, Bind= and BindReadOnly= settings, file %s is not trusted.", path);
|
||||
else {
|
||||
custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
|
||||
arg_custom_mounts = TAKE_PTR(settings->custom_mounts);
|
||||
arg_n_custom_mounts = settings->n_custom_mounts;
|
||||
settings->n_custom_mounts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_NETWORK) == 0 &&
|
||||
(settings->private_network >= 0 ||
|
||||
settings->network_veth >= 0 ||
|
||||
settings->network_bridge ||
|
||||
settings->network_zone ||
|
||||
settings->network_interfaces ||
|
||||
settings->network_macvlan ||
|
||||
settings->network_ipvlan ||
|
||||
settings->network_veth_extra)) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring network settings, file %s is not trusted.", path);
|
||||
else {
|
||||
arg_network_veth = settings_network_veth(settings);
|
||||
arg_private_network = settings_private_network(settings);
|
||||
|
||||
strv_free_and_replace(arg_network_interfaces, settings->network_interfaces);
|
||||
strv_free_and_replace(arg_network_macvlan, settings->network_macvlan);
|
||||
strv_free_and_replace(arg_network_ipvlan, settings->network_ipvlan);
|
||||
strv_free_and_replace(arg_network_veth_extra, settings->network_veth_extra);
|
||||
|
||||
free_and_replace(arg_network_bridge, settings->network_bridge);
|
||||
free_and_replace(arg_network_zone, settings->network_zone);
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_EXPOSE_PORTS) == 0 &&
|
||||
settings->expose_ports) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring Port= setting, file %s is not trusted.", path);
|
||||
else {
|
||||
expose_port_free_all(arg_expose_ports);
|
||||
arg_expose_ports = TAKE_PTR(settings->expose_ports);
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_USERNS) == 0 &&
|
||||
settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", path);
|
||||
else {
|
||||
arg_userns_mode = settings->userns_mode;
|
||||
arg_uid_shift = settings->uid_shift;
|
||||
arg_uid_range = settings->uid_range;
|
||||
arg_userns_chown = settings->userns_chown;
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0)
|
||||
arg_notify_ready = settings->notify_ready;
|
||||
|
||||
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
|
||||
|
||||
if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist))
|
||||
log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path);
|
||||
else {
|
||||
strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist);
|
||||
strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist);
|
||||
}
|
||||
}
|
||||
|
||||
for (rl = 0; rl < _RLIMIT_MAX; rl ++) {
|
||||
if ((arg_settings_mask & (SETTING_RLIMIT_FIRST << rl)))
|
||||
continue;
|
||||
|
||||
if (!settings->rlimit[rl])
|
||||
continue;
|
||||
|
||||
if (!arg_settings_trusted) {
|
||||
log_warning("Ignoring Limit%s= setting, file '%s' is not trusted.", rlimit_to_string(rl), path);
|
||||
continue;
|
||||
}
|
||||
|
||||
free_and_replace(arg_rlimit[rl], settings->rlimit[rl]);
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_HOSTNAME) == 0 &&
|
||||
settings->hostname)
|
||||
free_and_replace(arg_hostname, settings->hostname);
|
||||
|
||||
if ((arg_settings_mask & SETTING_NO_NEW_PRIVILEGES) == 0 &&
|
||||
settings->no_new_privileges >= 0)
|
||||
arg_no_new_privileges = settings->no_new_privileges;
|
||||
|
||||
if ((arg_settings_mask & SETTING_OOM_SCORE_ADJUST) == 0 &&
|
||||
settings->oom_score_adjust_set) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring OOMScoreAdjust= setting, file '%s' is not trusted.", path);
|
||||
else {
|
||||
arg_oom_score_adjust = settings->oom_score_adjust;
|
||||
arg_oom_score_adjust_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 &&
|
||||
settings->cpuset) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path);
|
||||
else {
|
||||
if (arg_cpuset)
|
||||
CPU_FREE(arg_cpuset);
|
||||
arg_cpuset = TAKE_PTR(settings->cpuset);
|
||||
arg_cpuset_ncpus = settings->cpuset_ncpus;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_settings(void) {
|
||||
_cleanup_(settings_freep) Settings *settings = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
@ -3112,151 +3445,7 @@ static int load_settings(void) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Copy over bits from the settings, unless they have been
|
||||
* explicitly masked by command line switches. */
|
||||
|
||||
if ((arg_settings_mask & SETTING_START_MODE) == 0 &&
|
||||
settings->start_mode >= 0) {
|
||||
arg_start_mode = settings->start_mode;
|
||||
strv_free_and_replace(arg_parameters, settings->parameters);
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_PIVOT_ROOT) == 0 &&
|
||||
settings->pivot_root_new) {
|
||||
free_and_replace(arg_pivot_root_new, settings->pivot_root_new);
|
||||
free_and_replace(arg_pivot_root_old, settings->pivot_root_old);
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_WORKING_DIRECTORY) == 0 &&
|
||||
settings->working_directory)
|
||||
free_and_replace(arg_chdir, settings->working_directory);
|
||||
|
||||
if ((arg_settings_mask & SETTING_ENVIRONMENT) == 0 &&
|
||||
settings->environment)
|
||||
strv_free_and_replace(arg_setenv, settings->environment);
|
||||
|
||||
if ((arg_settings_mask & SETTING_USER) == 0 &&
|
||||
settings->user)
|
||||
free_and_replace(arg_user, settings->user);
|
||||
|
||||
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
|
||||
uint64_t plus;
|
||||
|
||||
plus = settings->capability;
|
||||
if (settings_private_network(settings))
|
||||
plus |= (1ULL << CAP_NET_ADMIN);
|
||||
|
||||
if (!arg_settings_trusted && plus != 0) {
|
||||
if (settings->capability != 0)
|
||||
log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
|
||||
} else
|
||||
arg_caps_retain |= plus;
|
||||
|
||||
arg_caps_retain &= ~settings->drop_capability;
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 &&
|
||||
settings->kill_signal > 0)
|
||||
arg_kill_signal = settings->kill_signal;
|
||||
|
||||
if ((arg_settings_mask & SETTING_PERSONALITY) == 0 &&
|
||||
settings->personality != PERSONALITY_INVALID)
|
||||
arg_personality = settings->personality;
|
||||
|
||||
if ((arg_settings_mask & SETTING_MACHINE_ID) == 0 &&
|
||||
!sd_id128_is_null(settings->machine_id)) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring MachineID= setting, file %s is not trusted.", p);
|
||||
else
|
||||
arg_uuid = settings->machine_id;
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_READ_ONLY) == 0 &&
|
||||
settings->read_only >= 0)
|
||||
arg_read_only = settings->read_only;
|
||||
|
||||
if ((arg_settings_mask & SETTING_VOLATILE_MODE) == 0 &&
|
||||
settings->volatile_mode != _VOLATILE_MODE_INVALID)
|
||||
arg_volatile_mode = settings->volatile_mode;
|
||||
|
||||
if ((arg_settings_mask & SETTING_CUSTOM_MOUNTS) == 0 &&
|
||||
settings->n_custom_mounts > 0) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring TemporaryFileSystem=, Bind= and BindReadOnly= settings, file %s is not trusted.", p);
|
||||
else {
|
||||
custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
|
||||
arg_custom_mounts = TAKE_PTR(settings->custom_mounts);
|
||||
arg_n_custom_mounts = settings->n_custom_mounts;
|
||||
settings->n_custom_mounts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_NETWORK) == 0 &&
|
||||
(settings->private_network >= 0 ||
|
||||
settings->network_veth >= 0 ||
|
||||
settings->network_bridge ||
|
||||
settings->network_zone ||
|
||||
settings->network_interfaces ||
|
||||
settings->network_macvlan ||
|
||||
settings->network_ipvlan ||
|
||||
settings->network_veth_extra)) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring network settings, file %s is not trusted.", p);
|
||||
else {
|
||||
arg_network_veth = settings_network_veth(settings);
|
||||
arg_private_network = settings_private_network(settings);
|
||||
|
||||
strv_free_and_replace(arg_network_interfaces, settings->network_interfaces);
|
||||
strv_free_and_replace(arg_network_macvlan, settings->network_macvlan);
|
||||
strv_free_and_replace(arg_network_ipvlan, settings->network_ipvlan);
|
||||
strv_free_and_replace(arg_network_veth_extra, settings->network_veth_extra);
|
||||
|
||||
free_and_replace(arg_network_bridge, settings->network_bridge);
|
||||
free_and_replace(arg_network_zone, settings->network_zone);
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_EXPOSE_PORTS) == 0 &&
|
||||
settings->expose_ports) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring Port= setting, file %s is not trusted.", p);
|
||||
else {
|
||||
expose_port_free_all(arg_expose_ports);
|
||||
arg_expose_ports = TAKE_PTR(settings->expose_ports);
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_USERNS) == 0 &&
|
||||
settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) {
|
||||
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", p);
|
||||
else {
|
||||
arg_userns_mode = settings->userns_mode;
|
||||
arg_uid_shift = settings->uid_shift;
|
||||
arg_uid_range = settings->uid_range;
|
||||
arg_userns_chown = settings->userns_chown;
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0)
|
||||
arg_notify_ready = settings->notify_ready;
|
||||
|
||||
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
|
||||
|
||||
if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist))
|
||||
log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", p);
|
||||
else {
|
||||
strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist);
|
||||
strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return merge_settings(settings, p);
|
||||
}
|
||||
|
||||
static int run(int master,
|
||||
@ -3680,20 +3869,20 @@ static int run(int master,
|
||||
"STATUS=Container running.\n"
|
||||
"X_NSPAWN_LEADER_PID=" PID_FMT, *pid);
|
||||
if (!arg_notify_ready)
|
||||
sd_notify(false, "READY=1\n");
|
||||
(void) sd_notify(false, "READY=1\n");
|
||||
|
||||
if (arg_kill_signal > 0) {
|
||||
/* Try to kill the init system on SIGINT or SIGTERM */
|
||||
sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(*pid));
|
||||
sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, PID_TO_PTR(*pid));
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(*pid));
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, PID_TO_PTR(*pid));
|
||||
} else {
|
||||
/* Immediately exit */
|
||||
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
||||
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Exit when the child exits */
|
||||
sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid));
|
||||
(void) sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid));
|
||||
|
||||
if (arg_expose_ports) {
|
||||
r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, exposed, &rtnl);
|
||||
@ -3767,6 +3956,71 @@ static int run(int master,
|
||||
return 1; /* loop again */
|
||||
}
|
||||
|
||||
static int initialize_rlimits(void) {
|
||||
|
||||
/* The default resource limits the kernel passes to PID 1, as per kernel 4.16. Let's pass our container payload
|
||||
* the same values as the kernel originally passed to PID 1, in order to minimize differences between host and
|
||||
* container execution environments. */
|
||||
|
||||
static const struct rlimit kernel_defaults[_RLIMIT_MAX] = {
|
||||
[RLIMIT_AS] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_CORE] = { 0, RLIM_INFINITY },
|
||||
[RLIMIT_CPU] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_DATA] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_FSIZE] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_MEMLOCK] = { 65536, 65536 },
|
||||
[RLIMIT_MSGQUEUE] = { 819200, 819200 },
|
||||
[RLIMIT_NICE] = { 0, 0 },
|
||||
[RLIMIT_NOFILE] = { 1024, 4096 },
|
||||
[RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_RTPRIO] = { 0, 0 },
|
||||
[RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY },
|
||||
[RLIMIT_STACK] = { 8388608, RLIM_INFINITY },
|
||||
|
||||
/* The kernel scales the default for RLIMIT_NPROC and RLIMIT_SIGPENDING based on the system's amount of
|
||||
* RAM. To provide best compatibility we'll read these limits off PID 1 instead of hardcoding them
|
||||
* here. This is safe as we know that PID 1 doesn't change these two limits and thus the original
|
||||
* kernel's initialization should still be valid during runtime — at least if PID 1 is systemd. Note
|
||||
* that PID 1 changes a number of other resource limits during early initialization which is why we
|
||||
* don't read the other limits from PID 1 but prefer the static table above. */
|
||||
};
|
||||
|
||||
int rl;
|
||||
|
||||
for (rl = 0; rl < _RLIMIT_MAX; rl++) {
|
||||
|
||||
/* Let's only fill in what the user hasn't explicitly configured anyway */
|
||||
if ((arg_settings_mask & (SETTING_RLIMIT_FIRST << rl)) == 0) {
|
||||
const struct rlimit *v;
|
||||
struct rlimit buffer;
|
||||
|
||||
if (IN_SET(rl, RLIMIT_NPROC, RLIMIT_SIGPENDING)) {
|
||||
/* For these two let's read the limits off PID 1. See above for an explanation. */
|
||||
|
||||
if (prlimit(1, rl, NULL, &buffer) < 0)
|
||||
return log_error_errno(errno, "Failed to read resource limit RLIMIT_%s of PID 1: %m", rlimit_to_string(rl));
|
||||
|
||||
v = &buffer;
|
||||
} else
|
||||
v = kernel_defaults + rl;
|
||||
|
||||
arg_rlimit[rl] = newdup(struct rlimit, v, 1);
|
||||
if (!arg_rlimit[rl])
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *k = NULL;
|
||||
|
||||
(void) rlimit_format(arg_rlimit[rl], &k);
|
||||
log_debug("Setting RLIMIT_%s to %s.", rlimit_to_string(rl), k);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
_cleanup_free_ char *console = NULL;
|
||||
@ -3799,6 +4053,10 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = initialize_rlimits();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = determine_names();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@ -4077,7 +4335,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
|
||||
|
||||
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
|
||||
if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) < 0) {
|
||||
r = log_error_errno(errno, "Failed to become subreaper: %m");
|
||||
goto finish;
|
||||
}
|
||||
@ -4112,6 +4370,8 @@ finish:
|
||||
if (pid > 0)
|
||||
(void) wait_for_terminate(pid, NULL);
|
||||
|
||||
pager_close();
|
||||
|
||||
if (remove_directory && arg_directory) {
|
||||
int k;
|
||||
|
||||
@ -4147,6 +4407,7 @@ finish:
|
||||
free(arg_template);
|
||||
free(arg_image);
|
||||
free(arg_machine);
|
||||
free(arg_hostname);
|
||||
free(arg_user);
|
||||
free(arg_pivot_root_new);
|
||||
free(arg_pivot_root_old);
|
||||
@ -4161,6 +4422,8 @@ finish:
|
||||
custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
|
||||
expose_port_free_all(arg_expose_ports);
|
||||
free(arg_root_hash);
|
||||
rlimit_free_all(arg_rlimit);
|
||||
arg_cpuset = cpu_set_mfree(arg_cpuset);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : ret;
|
||||
}
|
||||
|
@ -684,7 +684,8 @@ static int bus_append_automount_property(sd_bus_message *m, const char *field, c
|
||||
}
|
||||
|
||||
static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
|
||||
int r, rl;
|
||||
const char *suffix;
|
||||
int r;
|
||||
|
||||
if (STR_IN_SET(field,
|
||||
"User", "Group",
|
||||
@ -863,25 +864,29 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
return bus_append_byte_array(m, field, decoded, sz);
|
||||
}
|
||||
|
||||
rl = rlimit_from_string(field);
|
||||
if (rl >= 0) {
|
||||
const char *sn;
|
||||
struct rlimit l;
|
||||
if ((suffix = startswith(field, "Limit"))) {
|
||||
int rl;
|
||||
|
||||
r = rlimit_parse(rl, eq, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse resource limit: %s", eq);
|
||||
rl = rlimit_from_string(suffix);
|
||||
if (rl >= 0) {
|
||||
const char *sn;
|
||||
struct rlimit l;
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
r = rlimit_parse(rl, eq, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse resource limit: %s", eq);
|
||||
|
||||
sn = strjoina(field, "Soft");
|
||||
r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
sn = strjoina(field, "Soft");
|
||||
r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
|
||||
|
@ -1613,36 +1613,40 @@ int bus_property_get_rlimit(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
const char *is_soft;
|
||||
struct rlimit *rl;
|
||||
uint64_t u;
|
||||
rlim_t x;
|
||||
const char *is_soft;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(userdata);
|
||||
|
||||
is_soft = endswith(property, "Soft");
|
||||
|
||||
rl = *(struct rlimit**) userdata;
|
||||
if (rl)
|
||||
x = is_soft ? rl->rlim_cur : rl->rlim_max;
|
||||
else {
|
||||
struct rlimit buf = {};
|
||||
const char *s, *p;
|
||||
int z;
|
||||
const char *s;
|
||||
|
||||
/* Chop off "Soft" suffix */
|
||||
s = is_soft ? strndupa(property, is_soft - property) : property;
|
||||
|
||||
z = rlimit_from_string(strstr(s, "Limit"));
|
||||
/* Skip over any prefix, such as "Default" */
|
||||
assert_se(p = strstr(s, "Limit"));
|
||||
|
||||
z = rlimit_from_string(p + 5);
|
||||
assert(z >= 0);
|
||||
|
||||
getrlimit(z, &buf);
|
||||
(void) getrlimit(z, &buf);
|
||||
x = is_soft ? buf.rlim_cur : buf.rlim_max;
|
||||
}
|
||||
|
||||
/* rlim_t might have different sizes, let's map
|
||||
* RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
|
||||
* all archs */
|
||||
/* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all
|
||||
* archs */
|
||||
u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
|
||||
|
||||
return sd_bus_message_append(reply, "t", u);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "syslog-util.h"
|
||||
#include "time-util.h"
|
||||
#include "utf8.h"
|
||||
#include "rlimit-util.h"
|
||||
|
||||
int config_item_table_lookup(
|
||||
const void *table,
|
||||
@ -707,7 +708,7 @@ int config_parse_string(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
char **s = data, *n;
|
||||
char **s = data;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -719,16 +720,8 @@ int config_parse_string(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isempty(rvalue))
|
||||
n = NULL;
|
||||
else {
|
||||
n = strdup(rvalue);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
free(*s);
|
||||
*s = n;
|
||||
if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
|
||||
return log_oom();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1214,3 +1207,42 @@ int config_parse_mtu(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_rlimit(
|
||||
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) {
|
||||
|
||||
struct rlimit **rl = data, d = {};
|
||||
int r;
|
||||
|
||||
assert(rvalue);
|
||||
assert(rl);
|
||||
|
||||
r = rlimit_parse(ltype, rvalue, &d);
|
||||
if (r == -EILSEQ) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rl[ltype])
|
||||
*rl[ltype] = d;
|
||||
else {
|
||||
rl[ltype] = newdup(struct rlimit, &d, 1);
|
||||
if (!rl[ltype])
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -147,6 +147,7 @@ int config_parse_ifname(GENERIC_PARSER_ARGS);
|
||||
int config_parse_ip_port(GENERIC_PARSER_ARGS);
|
||||
int config_parse_join_controllers(GENERIC_PARSER_ARGS);
|
||||
int config_parse_mtu(GENERIC_PARSER_ARGS);
|
||||
int config_parse_rlimit(GENERIC_PARSER_ARGS);
|
||||
|
||||
typedef enum Disabled {
|
||||
DISABLED_CONFIGURATION,
|
||||
|
@ -42,6 +42,7 @@ int main(int argc, char *argv[]) {
|
||||
.rlim_cur = 10,
|
||||
.rlim_max = 5,
|
||||
};
|
||||
int i;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
@ -53,10 +54,41 @@ int main(int argc, char *argv[]) {
|
||||
new.rlim_max = old.rlim_max;
|
||||
assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0);
|
||||
|
||||
assert_se(rlimit_from_string("LimitNOFILE") == RLIMIT_NOFILE);
|
||||
assert_se(rlimit_from_string("NOFILE") == RLIMIT_NOFILE);
|
||||
assert_se(rlimit_from_string("LimitNOFILE") == -1);
|
||||
assert_se(rlimit_from_string("RLIMIT_NOFILE") == -1);
|
||||
assert_se(rlimit_from_string("xxxNOFILE") == -1);
|
||||
assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1);
|
||||
|
||||
assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "LimitNOFILE"));
|
||||
assert_se(rlimit_from_string_harder("NOFILE") == RLIMIT_NOFILE);
|
||||
assert_se(rlimit_from_string_harder("LimitNOFILE") == RLIMIT_NOFILE);
|
||||
assert_se(rlimit_from_string_harder("RLIMIT_NOFILE") == RLIMIT_NOFILE);
|
||||
assert_se(rlimit_from_string_harder("xxxNOFILE") == -1);
|
||||
assert_se(rlimit_from_string_harder("DefaultLimitNOFILE") == -1);
|
||||
|
||||
for (i = 0; i < _RLIMIT_MAX; i++) {
|
||||
_cleanup_free_ char *prefixed = NULL;
|
||||
const char *p;
|
||||
|
||||
assert_se(p = rlimit_to_string(i));
|
||||
log_info("%i = %s", i, p);
|
||||
|
||||
assert_se(rlimit_from_string(p) == i);
|
||||
assert_se(rlimit_from_string_harder(p) == i);
|
||||
|
||||
assert_se(prefixed = strjoin("Limit", p));
|
||||
|
||||
assert_se(rlimit_from_string(prefixed) < 0);
|
||||
assert_se(rlimit_from_string_harder(prefixed) == i);
|
||||
|
||||
prefixed = mfree(prefixed);
|
||||
assert_se(prefixed = strjoin("RLIMIT_", p));
|
||||
|
||||
assert_se(rlimit_from_string(prefixed) < 0);
|
||||
assert_se(rlimit_from_string_harder(prefixed) == i);
|
||||
}
|
||||
|
||||
assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "NOFILE"));
|
||||
assert_se(rlimit_to_string(-1) == NULL);
|
||||
|
||||
assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "all-units.h"
|
||||
#include "capability-util.h"
|
||||
#include "conf-parser.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
@ -748,22 +749,22 @@ static void test_config_parse_capability_set(void) {
|
||||
static void test_config_parse_rlimit(void) {
|
||||
struct rlimit * rl[_RLIMIT_MAX] = {};
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
|
||||
@ -772,86 +773,86 @@ static void test_config_parse_rlimit(void) {
|
||||
rl[RLIMIT_NOFILE]->rlim_max = 20;
|
||||
|
||||
/* Invalid values don't change rl */
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_NOFILE]);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10);
|
||||
assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20);
|
||||
|
||||
rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 40);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_max == 60);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_CPU]);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
|
||||
assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
|
||||
|
||||
rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
||||
assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
|
||||
assert_se(config_parse_rlimit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
|
||||
assert_se(rl[RLIMIT_RTTIME]);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
|
||||
assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
|
||||
|
Loading…
x
Reference in New Issue
Block a user