mirror of
https://github.com/systemd/systemd.git
synced 2025-02-04 21:47:31 +03:00
Merge pull request #7964 from poettering/tmpfiles-more-fixes
a number of tmpfiles fixes
This commit is contained in:
commit
dad105c678
15
UIDS-GIDS.md
15
UIDS-GIDS.md
@ -17,13 +17,14 @@ i.e. 0…4294967295. However, four UIDs are special on Linux:
|
||||
1. 0 → The `root` super-user
|
||||
|
||||
2. 65534 → The `nobody` UID, also called the "overflow" UID or similar. It's
|
||||
where various subsystems map unmappable users to, for example NFS or user
|
||||
namespacing. (The latter can be changed with a sysctl during runtime, but
|
||||
that's not supported on `systemd`. If you do change it you void your
|
||||
warranty.) Because Fedora is a bit confused the `nobody` user is called
|
||||
`nfsnobody` there (and they have a different `nobody` user at UID 99). I
|
||||
hope this will be corrected eventually though. (Also, some distributions
|
||||
call the `nobody` group `nogroup`. I wish they didn't.)
|
||||
where various subsystems map unmappable users to, for example file systems
|
||||
only supporting 16bit UIDs, NFS or user namespacing. (The latter can be
|
||||
changed with a sysctl during runtime, but that's not supported on
|
||||
`systemd`. If you do change it you void your warranty.) Because Fedora is a
|
||||
bit confused the `nobody` user is called `nfsnobody` there (and they have a
|
||||
different `nobody` user at UID 99). I hope this will be corrected eventually
|
||||
though. (Also, some distributions call the `nobody` group `nogroup`. I wish
|
||||
they didn't.)
|
||||
|
||||
3. 4294967295, aka "32bit `(uid_t) -1`" → This UID is not a valid user ID, as
|
||||
`setresuid()`, `chown()` and friends treat -1 as a special request to not
|
||||
|
@ -1349,7 +1349,7 @@ evdev:input:b0003v1038p0310*
|
||||
KEYBOARD_KEY_70030=f9
|
||||
KEYBOARD_KEY_7002f=f11
|
||||
KEYBOARD_KEY_70046=f6
|
||||
|
||||
|
||||
###########################################################
|
||||
# Other
|
||||
###########################################################
|
||||
|
@ -484,6 +484,13 @@ r! /tmp/.X[0-9]*-lock</programlisting>
|
||||
The second line in contrast to the first one would break a
|
||||
running system, and will only be executed with
|
||||
<option>--boot</option>.</para>
|
||||
|
||||
<para>Note that for all line types that result in creation of any kind of file node
|
||||
(i.e. <varname>f</varname>/<varname>F</varname>,
|
||||
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
|
||||
<varname>p</varname>, <varname>L</varname>, <varname>c</varname>/<varname>b</varname> and <varname>C</varname>)
|
||||
leading directories are implicitly created if needed, owned by root with an access mode of 0755. In order to
|
||||
create them with different modes or ownership make sure to add appropriate <varname>d</varname> lines.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
|
@ -753,13 +753,50 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool dangerous_hardlinks(void) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
static int cached = -1;
|
||||
int r;
|
||||
|
||||
/* Check whether the fs.protected_hardlinks sysctl is on. If we can't determine it we assume its off, as that's
|
||||
* what the upstream default is. */
|
||||
|
||||
if (cached >= 0)
|
||||
return cached;
|
||||
|
||||
r = read_one_line_file("/proc/sys/fs/protected_hardlinks", &value);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read fs.protected_hardlinks sysctl: %m");
|
||||
return true;
|
||||
}
|
||||
|
||||
r = parse_boolean(value);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to parse fs.protected_hardlinks sysctl: %m");
|
||||
return true;
|
||||
}
|
||||
|
||||
cached = r == 0;
|
||||
return cached;
|
||||
}
|
||||
|
||||
static bool hardlink_vulnerable(struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
return !S_ISDIR(st->st_mode) && st->st_nlink > 1 && dangerous_hardlinks();
|
||||
}
|
||||
|
||||
static int path_set_perms(Item *i, const char *path) {
|
||||
char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
||||
_cleanup_close_ int fd = -1;
|
||||
struct stat st;
|
||||
|
||||
assert(i);
|
||||
assert(path);
|
||||
|
||||
if (!i->mode_set && !i->uid_set && !i->gid_set)
|
||||
goto shortcut;
|
||||
|
||||
/* We open the file with O_PATH here, to make the operation
|
||||
* somewhat atomic. Also there's unfortunately no fchmodat()
|
||||
* with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
|
||||
@ -777,21 +814,23 @@ static int path_set_perms(Item *i, const char *path) {
|
||||
}
|
||||
|
||||
log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
|
||||
return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
|
||||
|
||||
if (S_ISLNK(st.st_mode))
|
||||
log_debug("Skipping mode and owner fix for symlink %s.", path);
|
||||
else {
|
||||
char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
||||
xsprintf(fn, "/proc/self/fd/%i", fd);
|
||||
if (hardlink_vulnerable(&st)) {
|
||||
log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* not using i->path directly because it may be a glob */
|
||||
if (i->mode_set) {
|
||||
xsprintf(fn, "/proc/self/fd/%i", fd);
|
||||
|
||||
if (i->mode_set) {
|
||||
if (S_ISLNK(st.st_mode))
|
||||
log_debug("Skipping mode fix for symlink %s.", path);
|
||||
else {
|
||||
mode_t m = i->mode;
|
||||
|
||||
if (i->mask_perms) {
|
||||
@ -806,29 +845,32 @@ static int path_set_perms(Item *i, const char *path) {
|
||||
}
|
||||
|
||||
if (m == (st.st_mode & 07777))
|
||||
log_debug("\"%s\" has right mode %o", path, st.st_mode);
|
||||
log_debug("\"%s\" has correct mode %o already.", path, st.st_mode);
|
||||
else {
|
||||
log_debug("chmod \"%s\" to mode %o", path, m);
|
||||
log_debug("Changing \"%s\" to mode %o.", path, m);
|
||||
|
||||
if (chmod(fn, m) < 0)
|
||||
return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((i->uid != st.st_uid || i->gid != st.st_gid) &&
|
||||
(i->uid_set || i->gid_set)) {
|
||||
log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
|
||||
path,
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID);
|
||||
if (chown(fn,
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID) < 0)
|
||||
return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn);
|
||||
}
|
||||
if ((i->uid_set && i->uid != st.st_uid) ||
|
||||
(i->gid_set && i->gid != st.st_gid)) {
|
||||
log_debug("Changing \"%s\" to owner "UID_FMT":"GID_FMT,
|
||||
path,
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID);
|
||||
|
||||
if (chown(fn,
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID) < 0)
|
||||
return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn);
|
||||
}
|
||||
|
||||
fd = safe_close(fd);
|
||||
|
||||
shortcut:
|
||||
return label_fix(path, false, false);
|
||||
}
|
||||
|
||||
@ -967,6 +1009,11 @@ static int path_set_acls(Item *item, const char *path) {
|
||||
if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
|
||||
return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
|
||||
|
||||
if (hardlink_vulnerable(&st)) {
|
||||
log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
log_debug("Skipping ACL fix for symlink %s.", path);
|
||||
return 0;
|
||||
@ -1296,14 +1343,24 @@ static int create_item(Item *i) {
|
||||
|
||||
case CREATE_FILE:
|
||||
case TRUNCATE_FILE:
|
||||
RUN_WITH_UMASK(0000)
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
|
||||
r = write_one_file(i, i->path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case COPY_FILES: {
|
||||
|
||||
RUN_WITH_UMASK(0000)
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
|
||||
log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
|
||||
r = copy_tree(i->argument, i->path, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID, COPY_REFLINK);
|
||||
r = copy_tree(i->argument, i->path,
|
||||
i->uid_set ? i->uid : UID_INVALID,
|
||||
i->gid_set ? i->gid : GID_INVALID,
|
||||
COPY_REFLINK);
|
||||
|
||||
if (r == -EROFS && stat(i->path, &st) == 0)
|
||||
r = -EEXIST;
|
||||
@ -1345,7 +1402,7 @@ static int create_item(Item *i) {
|
||||
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||
RUN_WITH_UMASK(0000)
|
||||
mkdir_parents_label(i->path, 0755);
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
|
||||
if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
|
||||
|
||||
@ -1427,6 +1484,8 @@ static int create_item(Item *i) {
|
||||
|
||||
case CREATE_FIFO:
|
||||
RUN_WITH_UMASK(0000) {
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
|
||||
mac_selinux_create_file_prepare(i->path, S_IFIFO);
|
||||
r = mkfifo(i->path, i->mode);
|
||||
mac_selinux_create_file_clear();
|
||||
@ -1469,6 +1528,9 @@ static int create_item(Item *i) {
|
||||
}
|
||||
|
||||
case CREATE_SYMLINK: {
|
||||
RUN_WITH_UMASK(0000)
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
|
||||
mac_selinux_create_file_prepare(i->path, S_IFLNK);
|
||||
r = symlink(i->argument, i->path);
|
||||
mac_selinux_create_file_clear();
|
||||
@ -1527,6 +1589,9 @@ static int create_item(Item *i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
RUN_WITH_UMASK(0000)
|
||||
(void) mkdir_parents_label(i->path, 0755);
|
||||
|
||||
file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
|
||||
|
||||
RUN_WITH_UMASK(0000) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user