summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>2019-05-28 13:08:57 +0000
committerBob Beck <beck@cvs.openbsd.org>2019-05-28 13:08:57 +0000
commit20eca5d46140331c440996fa83a507774a6820bc (patch)
tree1a284a5ba0a12020a940d53902825c5482b4eb68
parentf61f9c0fb1539ef0841643d2c7c02a208242786a (diff)
Enable the use of the kernel __realpath() system call in the libc wrapper.
For now, this also still uses the existing realpath implmentation and emits a syslog if we see differening results. Once we have run with that for a little while we will remove the old code ok deraadt@
-rw-r--r--lib/libc/stdlib/realpath.c139
-rw-r--r--lib/libc/sys/Makefile.inc4
2 files changed, 138 insertions, 5 deletions
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c
index 5d226d9abc8..76f88562fb0 100644
--- a/lib/libc/stdlib/realpath.c
+++ b/lib/libc/stdlib/realpath.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: realpath.c,v 1.22 2017/12/24 01:50:50 millert Exp $ */
+/* $OpenBSD: realpath.c,v 1.23 2019/05/28 13:08:56 beck Exp $ */
/*
* Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
*
@@ -32,6 +32,8 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
+#include <syslog.h>
+#include <stdarg.h>
/* A slightly modified copy of this file exists in libexec/ld.so */
@@ -42,8 +44,8 @@
* components. Returns (resolved) on success, or (NULL) on failure,
* in which case the path which caused trouble is left in (resolved).
*/
-char *
-realpath(const char *path, char *resolved)
+static char *
+urealpath(const char *path, char *resolved)
{
const char *p;
char *q;
@@ -51,6 +53,7 @@ realpath(const char *path, char *resolved)
unsigned symlinks;
int serrno, mem_allocated;
ssize_t slen;
+ int trailingslash = 0;
char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
if (path == NULL) {
@@ -231,3 +234,133 @@ err:
free(resolved);
return (NULL);
}
+
+/*
+ * Copyright (c) 2019 Bob Beck <beck@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int __realpath(const char *pathname, char *resolved);
+PROTO_NORMAL(__realpath);
+
+/*
+ * wrapper for kernel __realpath
+ */
+
+char *
+realpath(const char *path, char *resolved)
+{
+ char pbuf[PATH_MAX], rbuf[PATH_MAX], expected[PATH_MAX];
+ struct syslog_data sdata = SYSLOG_DATA_INIT;
+ int usererrno = 0, kernelerrno = 0, trailingslash = 0, save_errno;
+ int kernelonly = (getenv("USE_KERNEL_REALPATH") != NULL);
+ ssize_t i;
+
+ rbuf[0] = pbuf[0] = expected[0] = '\0';
+
+ if (!kernelonly) {
+ memset(expected, 0, sizeof(expected));
+ if (urealpath(path, expected) == NULL) {
+ usererrno = errno;
+ expected[0] = '\0';
+ }
+ }
+
+ if (path == NULL) {
+ kernelerrno = EINVAL;
+ goto out;
+ }
+ if (path[0] == '\0') {
+ kernelerrno = ENOENT;
+ goto out;
+ }
+ if (strlcat(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf)) {
+ kernelerrno = ENAMETOOLONG;
+ goto out;
+ }
+
+ if (pbuf[strlen(pbuf) - 1] == '/')
+ trailingslash = 1;
+
+ if (__realpath(pbuf, rbuf) == -1)
+ kernelerrno = errno;
+
+ /*
+ * XXX XXX XXX
+ *
+ * The old userland implementation strips trailing slashes.
+ * According to Dr. POSIX, realpathing "/bsd" should be fine,
+ * realpathing "/bsd/" should return ENOTDIR.
+ *
+ * Similar, but *different* to the above, The old userland
+ * implementation allows for realpathing "/nonexistent" but
+ * not "/nonexistent/", Both those should return ENOENT
+ * according to POSIX.
+ *
+ * This hack should go away once we decide to match POSIX.
+ * which we should as soon as is convenient.
+ */
+ if (kernelerrno == ENOTDIR) {
+ /* Try again without the trailing slash. */
+ kernelerrno = 0;
+ for (i = strlen(pbuf); i > 1 && pbuf[i - 1] == '/'; i--)
+ pbuf[i - 1] = '\0';
+ rbuf[0] = '\0';
+ if (__realpath(pbuf, rbuf) == -1)
+ kernelerrno = errno;
+ }
+
+out:
+ if (!kernelonly) {
+ /* syslog if kernel and userland are different */
+ save_errno = errno;
+ if (strcmp(rbuf, expected) != 0 || (usererrno == 0 &&
+ kernelerrno != 0))
+ syslog_r(LOG_CRIT | LOG_CONS, &sdata,
+ "realpath '%s' -> '%s' errno %d, "
+ "expected '%s' errno %d", path, rbuf,
+ kernelerrno, expected, usererrno);
+ errno = save_errno;
+
+ /* use userland result */
+ if (usererrno) {
+ errno = usererrno;
+ return NULL;
+ }
+ else
+ errno = 0;
+ if (resolved == NULL)
+ resolved = strdup(expected);
+ else if (strlcpy(resolved, expected, PATH_MAX) >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ } else {
+ /* use kernel result */
+ if (kernelerrno) {
+ errno = kernelerrno;
+ return NULL;
+ }
+ else
+ errno = 0;
+ if (resolved == NULL)
+ resolved = strdup(rbuf);
+ else if (strlcpy(resolved, rbuf, PATH_MAX) >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ }
+ return (resolved);
+}
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 7cc7d93c390..5dd7f1aeb68 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile.inc,v 1.156 2019/01/11 18:46:30 deraadt Exp $
+# $OpenBSD: Makefile.inc,v 1.157 2019/05/28 13:08:56 beck Exp $
# $NetBSD: Makefile.inc,v 1.35 1995/10/16 23:49:07 jtc Exp $
# @(#)Makefile.inc 8.1 (Berkeley) 6/17/93
@@ -109,7 +109,7 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po}
SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so}
DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do}
-HIDDEN= ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
+HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o}
PHIDDEN=${HIDDEN:.o=.po}
SHIDDEN=${HIDDEN:.o=.so}
DHIDDEN=${HIDDEN:.o=.do}