summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/syscall/getcwd.c
diff options
context:
space:
mode:
authorDan McDonald <danmcd@joyent.com>2021-03-19 11:38:16 -0400
committerDan McDonald <danmcd@joyent.com>2021-03-19 11:38:16 -0400
commita1ce764f98e19204e95ee78d66746478d10ea59c (patch)
treeb210134e2dd21bde06dae97ddebffce293b3d39d /usr/src/uts/common/syscall/getcwd.c
parent1d684b54ff06842338ae5e57f8873ec9b9d24df3 (diff)
parentfc1e9305ae86a296023d90240041e860548ba1bd (diff)
downloadillumos-joyent-a1ce764f98e19204e95ee78d66746478d10ea59c.tar.gz
[illumos-gate merge]
commit fc1e9305ae86a296023d90240041e860548ba1bd 13627 chown(2) mixes up chown() and fchown() commit 173f6047c6877d03cbb55428e6ec95f07c9cbb83 13622 Memory leak in coretemp_create_sensor commit 1b1c4b089b04ffa47f04c2923dc78c7fcafcf964 13575 loader: use display pixel density for font autoselection commit 5fbc1fe0da7f34cf8155bf7624c94583cc98e47c 13526 cmd/availdevs always rebuilds commit b2761fb273089c452ca34297d7ab4a1d1c1f1012 13599 ahci(7d) requires alias for HP AHCI SATA controller commit 6edc7986d8c0034d072afac8b25477b983bf8f55 13586 getcwd() should accept a 0 length argument (fix mandoc) commit d6f391ef39bc41c64e16ac5d7b10c1c8d5b1761e 4149 ksh head builtin does not like newlines commit aa15372140b6b509a26742fd85fe78dd77d9a642 13586 getcwd() should accept a 0 length argument commit f38f28fdbc29b3c5020295a6c6cb1ac52e949978 13574 loader.efi: efifb_gop_get_edid() is broken commit 8781de92560745751daa24953330574a84de46e6 13632 smntemp doesn't need smntemp alias commit 7eb8c88abb70697edf48045434d2c18bb82ad2e7 9620 getcwd() syscall has unbounded memory allocation commit f9bbf53b825c087ef99dd9b3e51570ec68a51463 12558 Builtin command "printf" of ksh93 does not behave as specified commit 4162633a7c5961f388fdc51bcecb3016104b359f 3782 ksh93's builtin chown fails with numeric ids
Diffstat (limited to 'usr/src/uts/common/syscall/getcwd.c')
-rw-r--r--usr/src/uts/common/syscall/getcwd.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/usr/src/uts/common/syscall/getcwd.c b/usr/src/uts/common/syscall/getcwd.c
index b0c9b83d8b..4c83278314 100644
--- a/usr/src/uts/common/syscall/getcwd.c
+++ b/usr/src/uts/common/syscall/getcwd.c
@@ -22,10 +22,9 @@
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/copyops.h>
#include <sys/errno.h>
#include <sys/kmem.h>
@@ -44,31 +43,49 @@ getcwd(char *buf, size_t buflen)
size_t kbuflen;
/*
+ * If the buffer cannot accommodate one character and nul terminator,
+ * it is too small.
+ */
+ if (buflen < 2)
+ return (set_errno(ERANGE));
+
+ /*
* The user should be able to specify any size buffer, but we don't want
* to arbitrarily allocate huge kernel buffers just because the user
* requests it. So we'll start with MAXPATHLEN (which should hold any
- * normal path), and only increase it if we fail with ERANGE.
+ * normal path), and only increase it if we fail with
+ * ERANGE / ENAMETOOLONG.
+ *
+ * To protect against unbounded memory usage, cap to kmem_max_cached.
+ * This is far bigger than the length of any practical path on the
+ * system, and avoids allocating memory from the kmem_oversized arena.
*/
kbuflen = MIN(buflen, MAXPATHLEN);
- for (;;) {
+ while (kbuflen <= kmem_max_cached) {
kbuf = kmem_alloc(kbuflen, KM_SLEEP);
if (((err = dogetcwd(kbuf, kbuflen)) == 0) &&
- (copyout(kbuf, buf, strlen(kbuf) + 1) != 0))
+ (copyout(kbuf, buf, strlen(kbuf) + 1) != 0)) {
err = EFAULT;
+ }
kmem_free(kbuf, kbuflen);
- if (err == ENAMETOOLONG) {
+ /*
+ * dogetcwd() inconsistently returns ERANGE or ENAMETOOLONG
+ * depending on whether it calls dirtopath() and then whether
+ * the subsequent operations run out of space whilst
+ * evaluating a cached vnode path or otherwise.
+ */
+ if (err == ENAMETOOLONG || err == ERANGE) {
+ /* For some reason, getcwd() uses ERANGE. */
+ err = ERANGE;
/*
* If the user's buffer really was too small, give up.
- * For some reason, getcwd() uses ERANGE for this case.
*/
- if (kbuflen == buflen) {
- err = ERANGE;
+ if (kbuflen == buflen)
break;
- }
kbuflen = MIN(kbuflen * 2, buflen);
} else {
break;