Commit ec66e7c6 authored by Ariadne Conill's avatar Ariadne Conill 🐰
Browse files

main/openrc: add mitigation for CVE-2018-21269

parent 5c8621ff
......@@ -2,7 +2,7 @@
pkgname=openrc
pkgver=0.42.1
_ver=${pkgver/_git*/}
pkgrel=2
pkgrel=3
pkgdesc="OpenRC manages the services, startup and shutdown of a host"
url="https://github.com/OpenRC/openrc"
arch="all"
......@@ -25,6 +25,8 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/OpenRC/openrc/archive/$pkgve
0009-Support-early-loading-of-keymap-if-kdb-is-installed.patch
0010-rc-mount-make-timeout-invocation-compatible-with-bus.patch
CVE-2018-21269.patch
openrc.logrotate
hostname.initd
hwdrivers.initd
......@@ -36,6 +38,10 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/OpenRC/openrc/archive/$pkgve
firstboot.initd
"
# secfixes:
# 0.42.1-r3:
# - CVE-2018-21269
prepare() {
default_prepare
sed -i -e '/^sed/d' "$builddir"/pkgconfig/Makefile
......@@ -113,7 +119,8 @@ zshcomp() {
rm -rf "$pkgdir"/usr/share/zsh
}
sha512sums="579b9bfbb151b945a364a2c12b037d2e15991820ca99a07ac18e9bdc50074e67fbf0dcf9865aa4deabe2bf82092e4623be51c9e0b4014384951e0a92ac1e7646 openrc-0.42.1.tar.gz
sha512sums="
579b9bfbb151b945a364a2c12b037d2e15991820ca99a07ac18e9bdc50074e67fbf0dcf9865aa4deabe2bf82092e4623be51c9e0b4014384951e0a92ac1e7646 openrc-0.42.1.tar.gz
71fce711adbcb411189a089f1d49567c50348e12c42b7a9c9b582dae5d18051f88ccf81c768337e87d6792d953e84d1e8b93d7978a1947d7d20ef3b1cd330875 0001-call-sbin-mkmntdirs-in-localmount-OpenRC-service.patch
b1cedd38badda4fc308decdff06f9644b96fe35617792da8d6d62407409841705fd71b5b57d1804a6395095604a70898f80830c76395ec99f715038a0809d815 0002-force-root-be-rw-before-localmount.patch
9dea3fcdb90e3e8078a771beefeba3ca91b9966a1b8ee9ff96cf460e7dd21abbc4a46a501a960c3edf5a76c083c2cf60ccb06d9da7a4c6df2a50660745beb278 0003-sysctl-add-compatibility-for-busybox-sysctl.patch
......@@ -124,6 +131,7 @@ dbe3f170440f0f357f31ac4d49c56a9a7ec22172df2701bf4a0afdee22aedda1f88b9fa5ffdbe19a
d2b8700f56b05579926352855de8fcee5cf78f0c13200643a5195f8c60e2b5082d476b42cc77b13246b9fb883aa002d723237b0fc7ae84ccd7ebe3b25690cf50 0008-fix-undeclared-UT_LINESIZE.patch
667085d89e194f7e2255d5c098c3d8de272f54cb925710cb98d5e7a6b58982d0acfe15f97b574cfc646b139cd7aa5b527ba700ef9b8048a6d6d9dee8cc74913c 0009-Support-early-loading-of-keymap-if-kdb-is-installed.patch
ff9bf2f6e4f55633a9641385398f70a2e591e2b3b56b1903f168a97b07bd56dc5a65d151deeab94229452b2e892b597c16dc3d57d5d47ec35a48cf5343190c36 0010-rc-mount-make-timeout-invocation-compatible-with-bus.patch
715016b4f481a6d4d2ab37d23659e6cacc023b02fa6908b566391ee2744369076ea74e54f0fe576e2cc1d3371d4d9e3818395ca3f417233358fc70a9edc4dba6 CVE-2018-21269.patch
12bb6354e808fbf47bbab963de55ee7901738b4a912659982c57ef2777fff9a670e867fcb8ec316a76b151032c92dc89a950d7d1d835ef53f753a8f3b41d2cec openrc.logrotate
493f27d588e64bb2bb542b32493ed05873f4724e8ad1751002982d7b4e07963cfb72f93603b2d678f305177cf9556d408a87b793744c6b7cd46cf9be4b744c02 hostname.initd
c06eac7264f6cc6888563feeae5ca745aae538323077903de1b19102e4f16baa34c18b8c27af5dd5423e7670834e2261e9aa55f2b1ec8d8fdc2be105fe894d55 hwdrivers.initd
......@@ -132,4 +140,5 @@ b04058ec630e19de0bafefe06198dc1bff8c8d5d2c89e4660dd83dda8bb82a76cdb1d8661cce88e4
e45e8f0f8746d949c4f2a49cdc5451b4722b66f280c844b1895e91e2886b7ed351ab46eae1cdeb88051a0035dd65c5fc72c25bf769db34ed2e2e90f38193e0aa networking.initd
80e43ded522e2d48b876131c7c9997debd43f3790e0985801a8c1dd60bc6e09f625b35a127bf225eb45a65eec7808a50d1c08a5e8abceafc61726211e061e0a2 modloop.confd
d76c75c58e6f4b0801edac4e081b725ef3d50a9a8c9bbb5692bf4d0f804af7d383bf71a73d5d03ed348a89741ef0b2427eb6a7cbf5a9b9ff60a240639fa6ec88 sysfsconf.initd
f65b061b4272463071022e88a7392d5573f2d95f91e42c8b4f3ef69171604460ddd3d426dfbab382f73a3fac68d4b4ff3a923fdc49fb6fd9f27ebd3ab24e0d0e firstboot.initd"
f65b061b4272463071022e88a7392d5573f2d95f91e42c8b4f3ef69171604460ddd3d426dfbab382f73a3fac68d4b4ff3a923fdc49fb6fd9f27ebd3ab24e0d0e firstboot.initd
"
From 577f00abe5f8ec6da40ac79d77df3e514593090d Mon Sep 17 00:00:00 2001
From: William Hubbs <w.d.hubbs@gmail.com>
Date: Wed, 11 Nov 2020 10:28:50 -0600
Subject: [PATCH] checkpath: fix CVE-2018-21269
This walks the directory path to the file we are going to manipulate to make
sure that when we create the file and change the ownership and permissions
we are working on the same file.
Also, all non-terminal symbolic links must be owned by root. This will
keep a non-root user from making a symbolic link as described in the
bug. If root creates the symbolic link, it is assumed to be trusted.
On non-linux platforms, we no longer follow non-terminal symbolic links
by default. If you need to do that, add the -s option on the checkpath
command line, but keep in mind that this is not secure.
This fixes #201.
---
man/openrc-run.8 | 6 +++
src/rc/checkpath.c | 103 ++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 102 insertions(+), 7 deletions(-)
diff --git a/man/openrc-run.8 b/man/openrc-run.8
index 1102daaa..ec4b88de 100644
--- a/man/openrc-run.8
+++ b/man/openrc-run.8
@@ -461,6 +461,7 @@ Mark the service as inactive.
.Op Fl p , -pipe
.Op Fl m , -mode Ar mode
.Op Fl o , -owner Ar owner
+.Op Fl s , -symlinks
.Op Fl W , -writable
.Op Fl q , -quiet
.Ar path ...
@@ -481,6 +482,11 @@ or with names, and are separated by a colon.
The truncate options (-D and -F) cause the directory or file to be
cleared of all contents.
.Pp
+If -s is not specified on a non-linux platform, checkpath will refuse to
+allow non-terminal symbolic links to exist in the path. This is for
+security reasons so that a non-root user can't create a symbolic link to
+a root-owned file and take ownership of that file.
+.Pp
If -W is specified, checkpath checks to see if the first path given on
the command line is writable. This is different from how the test
command in the shell works, because it also checks to make sure the file
diff --git a/src/rc/checkpath.c b/src/rc/checkpath.c
index 448c9cf8..ff54a892 100644
--- a/src/rc/checkpath.c
+++ b/src/rc/checkpath.c
@@ -16,6 +16,7 @@
* except according to the terms contained in the LICENSE file.
*/
+#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
@@ -23,6 +24,7 @@
#include <fcntl.h>
#include <getopt.h>
#include <grp.h>
+#include <libgen.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -44,7 +46,7 @@ typedef enum {
const char *applet = NULL;
const char *extraopts ="path1 [path2] [...]";
-const char *getoptstring = "dDfFpm:o:W" getoptstring_COMMON;
+const char *getoptstring = "dDfFpm:o:sW" getoptstring_COMMON;
const struct option longopts[] = {
{ "directory", 0, NULL, 'd'},
{ "directory-truncate", 0, NULL, 'D'},
@@ -53,6 +55,7 @@ const struct option longopts[] = {
{ "pipe", 0, NULL, 'p'},
{ "mode", 1, NULL, 'm'},
{ "owner", 1, NULL, 'o'},
+ { "symlinks", 0, NULL, 's'},
{ "writable", 0, NULL, 'W'},
longopts_COMMON
};
@@ -64,15 +67,92 @@ const char * const longopts_help[] = {
"Create a named pipe (FIFO) if not exists",
"Mode to check",
"Owner to check (user:group)",
+ "follow symbolic links (irrelivent on linux)",
"Check whether the path is writable or not",
longopts_help_COMMON
};
const char *usagestring = NULL;
+static int get_dirfd(char *path, bool symlinks) {
+ char *ch;
+ char *item;
+ char *linkpath = NULL;
+ char *path_dupe;
+ char *str;
+ int components = 0;
+ int dirfd;
+ int flags = 0;
+ int new_dirfd;
+ struct stat st;
+ ssize_t linksize;
+
+ if (!path || *path != '/')
+ eerrorx("%s: empty or relative path", applet);
+ dirfd = openat(dirfd, "/", O_RDONLY);
+ if (dirfd == -1)
+ eerrorx("%s: unable to open the root directory: %s",
+ applet, strerror(errno));
+ path_dupe = xstrdup(path);
+ ch = path_dupe;
+ while (*ch) {
+ if (*ch == '/')
+ components++;
+ ch++;
+ }
+ item = strtok(path_dupe, "/");
+#ifdef O_PATH
+ flags |= O_PATH;
+#endif
+ if (!symlinks)
+ flags |= O_NOFOLLOW;
+ flags |= O_RDONLY;
+ while (dirfd > 0 && item && components > 1) {
+ str = xstrdup(linkpath ? linkpath : item);
+ new_dirfd = openat(dirfd, str, flags);
+ if (new_dirfd == -1)
+ eerrorx("%s: %s: could not open %s: %s", applet, path, str,
+ strerror(errno));
+ if (fstat(new_dirfd, &st) == -1)
+ eerrorx("%s: %s: unable to stat %s: %s", applet, path, item,
+ strerror(errno));
+ if (S_ISLNK(st.st_mode) ) {
+ if (st.st_uid != 0)
+ eerrorx("%s: %s: synbolic link %s not owned by root",
+ applet, path, str);
+ linksize = st.st_size+1;
+ if (linkpath)
+ free(linkpath);
+ linkpath = xmalloc(linksize);
+ memset(linkpath, 0, linksize);
+ if (readlinkat(new_dirfd, "", linkpath, linksize) != st.st_size)
+ eerrorx("%s: symbolic link destination changed", applet);
+ /*
+ * now follow the symlink.
+ */
+ close(new_dirfd);
+ } else {
+ close(dirfd);
+ dirfd = new_dirfd;
+ free(linkpath);
+ linkpath = NULL;
+ item = strtok(NULL, "/");
+ components--;
+ }
+ }
+ free(path_dupe);
+ if (linkpath) {
+ free(linkpath);
+ linkpath = NULL;
+ }
+ return dirfd;
+}
+
static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
- inode_t type, bool trunc, bool chowner, bool selinux_on)
+ inode_t type, bool trunc, bool chowner, bool symlinks, bool selinux_on)
{
struct stat st;
+ char *name = NULL;
+ int dirfd;
int fd;
int flags;
int r;
@@ -93,14 +173,16 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
#endif
if (trunc)
flags |= O_TRUNC;
- readfd = open(path, readflags);
+ xasprintf(&name, "%s", basename_c(path));
+ dirfd = get_dirfd(path, symlinks);
+ readfd = openat(dirfd, name, readflags);
if (readfd == -1 || (type == inode_file && trunc)) {
if (type == inode_file) {
einfo("%s: creating file", path);
if (!mode) /* 664 */
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
u = umask(0);
- fd = open(path, flags, mode);
+ fd = openat(dirfd, name, flags, mode);
umask(u);
if (fd == -1) {
eerror("%s: open: %s", applet, strerror(errno));
@@ -122,7 +204,7 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
strerror (errno));
return -1;
}
- readfd = open(path, readflags);
+ readfd = openat(dirfd, name, readflags);
if (readfd == -1) {
eerror("%s: unable to open directory: %s", applet,
strerror(errno));
@@ -140,7 +222,7 @@ static int do_check(char *path, uid_t uid, gid_t gid, mode_t mode,
strerror (errno));
return -1;
}
- readfd = open(path, readflags);
+ readfd = openat(dirfd, name, readflags);
if (readfd == -1) {
eerror("%s: unable to open fifo: %s", applet,
strerror(errno));
@@ -259,6 +341,7 @@ int main(int argc, char **argv)
int retval = EXIT_SUCCESS;
bool trunc = false;
bool chowner = false;
+ bool symlinks = false;
bool writable = false;
bool selinux_on = false;
@@ -293,6 +376,11 @@ int main(int argc, char **argv)
eerrorx("%s: owner `%s' not found",
applet, optarg);
break;
+ case 's':
+#ifndef O_PATH
+ symlinks = true;
+#endif
+ break;
case 'W':
writable = true;
break;
@@ -320,7 +408,8 @@ int main(int argc, char **argv)
while (optind < argc) {
if (writable)
exit(!is_writable(argv[optind]));
- if (do_check(argv[optind], uid, gid, mode, type, trunc, chowner, selinux_on))
+ if (do_check(argv[optind], uid, gid, mode, type, trunc, chowner,
+ symlinks, selinux_on))
retval = EXIT_FAILURE;
optind++;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment