2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2012-04-17 22:25:24 +02:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-27 00:42:07 +01:00
|
|
|
#include "dev-setup.h"
|
2012-04-17 22:25:24 +02:00
|
|
|
#include "label.h"
|
2015-12-03 21:13:37 +01:00
|
|
|
#include "log.h"
|
2019-03-14 13:14:33 +01:00
|
|
|
#include "nulstr-util.h"
|
2015-05-21 16:30:58 +02:00
|
|
|
#include "path-util.h"
|
2018-07-27 18:04:11 +02:00
|
|
|
#include "umask-util.h"
|
2015-10-27 00:42:07 +01:00
|
|
|
#include "user-util.h"
|
2012-04-17 22:25:24 +02:00
|
|
|
|
2015-05-21 16:30:58 +02:00
|
|
|
int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
|
2012-04-17 22:25:24 +02:00
|
|
|
static const char symlinks[] =
|
2013-06-10 14:50:59 +02:00
|
|
|
"-/proc/kcore\0" "/dev/core\0"
|
2012-04-17 22:25:24 +02:00
|
|
|
"/proc/self/fd\0" "/dev/fd\0"
|
|
|
|
"/proc/self/fd/0\0" "/dev/stdin\0"
|
|
|
|
"/proc/self/fd/1\0" "/dev/stdout\0"
|
|
|
|
"/proc/self/fd/2\0" "/dev/stderr\0";
|
|
|
|
|
2015-05-21 16:30:58 +02:00
|
|
|
const char *j, *k;
|
|
|
|
int r;
|
|
|
|
|
2012-08-15 02:00:30 +02:00
|
|
|
NULSTR_FOREACH_PAIR(j, k, symlinks) {
|
2015-05-21 16:30:58 +02:00
|
|
|
_cleanup_free_ char *link_name = NULL;
|
|
|
|
const char *n;
|
|
|
|
|
2013-06-10 14:50:59 +02:00
|
|
|
if (j[0] == '-') {
|
|
|
|
j++;
|
|
|
|
|
2014-03-19 16:23:32 +01:00
|
|
|
if (access(j, F_OK) < 0)
|
2013-06-10 14:50:59 +02:00
|
|
|
continue;
|
|
|
|
}
|
2012-08-15 02:00:30 +02:00
|
|
|
|
2012-08-21 17:23:03 +02:00
|
|
|
if (prefix) {
|
2019-06-19 15:20:13 +02:00
|
|
|
link_name = path_join(prefix, k);
|
2014-01-20 19:54:51 +01:00
|
|
|
if (!link_name)
|
|
|
|
return -ENOMEM;
|
2012-08-15 02:00:30 +02:00
|
|
|
|
2015-05-21 16:30:58 +02:00
|
|
|
n = link_name;
|
2012-08-21 17:23:03 +02:00
|
|
|
} else
|
2015-05-21 16:30:58 +02:00
|
|
|
n = k;
|
|
|
|
|
|
|
|
r = symlink_label(j, n);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to symlink %s to %s: %m", j, n);
|
|
|
|
|
|
|
|
if (uid != UID_INVALID || gid != GID_INVALID)
|
|
|
|
if (lchown(n, uid, gid) < 0)
|
|
|
|
log_debug_errno(errno, "Failed to chown %s: %m", n);
|
2012-08-15 02:00:30 +02:00
|
|
|
}
|
2014-01-20 19:54:51 +01:00
|
|
|
|
|
|
|
return 0;
|
2012-04-17 22:25:24 +02:00
|
|
|
}
|
2018-07-27 18:04:11 +02:00
|
|
|
|
2020-06-09 16:22:24 +02:00
|
|
|
int make_inaccessible_nodes(
|
2020-08-14 18:56:54 +02:00
|
|
|
const char *parent_dir,
|
2020-06-09 16:22:24 +02:00
|
|
|
uid_t uid,
|
|
|
|
gid_t gid) {
|
|
|
|
|
2018-07-27 18:04:11 +02:00
|
|
|
static const struct {
|
|
|
|
const char *name;
|
|
|
|
mode_t mode;
|
|
|
|
} table[] = {
|
2020-08-14 18:56:54 +02:00
|
|
|
{ "inaccessible", S_IFDIR | 0755 },
|
|
|
|
{ "inaccessible/reg", S_IFREG | 0000 },
|
|
|
|
{ "inaccessible/dir", S_IFDIR | 0000 },
|
|
|
|
{ "inaccessible/fifo", S_IFIFO | 0000 },
|
|
|
|
{ "inaccessible/sock", S_IFSOCK | 0000 },
|
2018-07-27 18:04:11 +02:00
|
|
|
|
|
|
|
/* The following two are likely to fail if we lack the privs for it (for example in an userns
|
2020-08-20 11:23:26 +02:00
|
|
|
* environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibits creation of
|
|
|
|
* device nodes with a major/minor of 0). But that's entirely fine. Consumers of these files
|
|
|
|
* should implement falling back to use a different node then, for example
|
|
|
|
* <root>/inaccessible/sock, which is close enough in behaviour and semantics for most uses.
|
|
|
|
*/
|
2020-08-14 18:56:54 +02:00
|
|
|
{ "inaccessible/chr", S_IFCHR | 0000 },
|
|
|
|
{ "inaccessible/blk", S_IFBLK | 0000 },
|
2018-07-27 18:04:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
_cleanup_umask_ mode_t u;
|
|
|
|
int r;
|
|
|
|
|
2020-08-14 18:56:54 +02:00
|
|
|
if (!parent_dir)
|
|
|
|
parent_dir = "/run/systemd";
|
2020-06-09 16:22:24 +02:00
|
|
|
|
2018-07-27 18:04:11 +02:00
|
|
|
u = umask(0000);
|
|
|
|
|
|
|
|
/* Set up inaccessible (and empty) file nodes of all types. This are used to as mount sources for over-mounting
|
|
|
|
* ("masking") file nodes that shall become inaccessible and empty for specific containers or services. We try
|
|
|
|
* to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the
|
|
|
|
* underlying file, i.e. in the best case we offer the same node type as the underlying node. */
|
|
|
|
|
2020-08-14 18:56:54 +02:00
|
|
|
for (size_t i = 0; i < ELEMENTSOF(table); i++) {
|
2018-07-27 18:04:11 +02:00
|
|
|
_cleanup_free_ char *path = NULL;
|
|
|
|
|
2020-08-14 18:56:54 +02:00
|
|
|
path = path_join(parent_dir, table[i].name);
|
2018-07-27 18:04:11 +02:00
|
|
|
if (!path)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
if (S_ISDIR(table[i].mode))
|
2020-07-10 21:48:02 +02:00
|
|
|
r = mkdir_label(path, table[i].mode & 07777);
|
2018-07-27 18:04:11 +02:00
|
|
|
else
|
2020-07-10 21:48:02 +02:00
|
|
|
r = mknod_label(path, table[i].mode, makedev(0, 0));
|
2018-07-27 18:04:11 +02:00
|
|
|
if (r < 0) {
|
2020-08-14 18:56:54 +02:00
|
|
|
log_debug_errno(r, "Failed to create '%s', ignoring: %m", path);
|
2018-07-27 18:04:11 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uid != UID_INVALID || gid != GID_INVALID) {
|
|
|
|
if (lchown(path, uid, gid) < 0)
|
|
|
|
log_debug_errno(errno, "Failed to chown '%s': %m", path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|