From patchwork Thu Sep 10 15:19:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40390 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0230B397241F; Thu, 10 Sep 2020 15:19:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0230B397241F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1599751164; bh=jYJqx9HSkK8F3+PtytxhxdAMIvafnQ0URXH8/TcujVk=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=qmIXBQZ7gTs29qtnXF64O9BjWgNJcryd+mHGCaJRrmTjfDl8+ciW67XrKarUDoISh KVDwOeM+Cq5xMsd9MMcmVK4IgvG8aEokvOthlEv23n4NtlFi7flEOnVHaw6rTNEavA zC+XoZmhw2ZoyKG6sicjvVaEOy2aa37nnJy0Cyek= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x72d.google.com (mail-qk1-x72d.google.com [IPv6:2607:f8b0:4864:20::72d]) by sourceware.org (Postfix) with ESMTPS id 971D43857C50 for ; Thu, 10 Sep 2020 15:19:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 971D43857C50 Received: by mail-qk1-x72d.google.com with SMTP id g72so6397070qke.8 for ; Thu, 10 Sep 2020 08:19:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=jYJqx9HSkK8F3+PtytxhxdAMIvafnQ0URXH8/TcujVk=; b=P2nbkAynNdEzXxFBEBWvUaOidCpe/cr7e2L5qkeJldL8pYtmXGSvbTYW48jIn0WZ0g hPqjPI28pImh1uzoQjIoBqCKm4AY3ZLLEaKTD6aNICIXzevRwnUKd0UNtp10i+D9oINA VXHiAFyGzLpbco5BKOsX6LhxEWP/PT4lYXkPk9Mq2BddDUvdgBaqgTXBQ4KrQEwqLzlo G1kV9cP+N5fSoL7Noe+X5M8L4qe4rYhV17IEGMP78RMeNu5eE06TRmqQRQdeOsJKe8s/ Mo+z9+rZpyn75z3VxrJ0fsEGwZ7Yx7MPjtLVGFQWXO1lAGq+SCxgPOc3kRz4I6FheGy4 FbZg== X-Gm-Message-State: AOAM530/kPI7MXTafM5wcHWdZzzy0Gm75cVUUURSiTTyy3BtkjmbeEs+ ncYG3eH7NI6JPn/Bc+AHepAoHosEGoWTRw== X-Google-Smtp-Source: ABdhPJxF3g14fbKGBFA6ms8pTNnln4iQj1G31AUGtln8KHzZmUDz1GVQFcCFYlX/glNevx4rPTxU1Q== X-Received: by 2002:a37:7c4:: with SMTP id 187mr8079007qkh.112.1599751159693; Thu, 10 Sep 2020 08:19:19 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id z37sm7851090qtz.67.2020.09.10.08.19.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Sep 2020 08:19:19 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH 1/4] Sync canonicalize with gnulib [BZ #10635] Date: Thu, 10 Sep 2020 12:19:12 -0300 Message-Id: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib version 44358d4d165b with the following exceptions: - All the logic to which __getcwd use. - MAXSYMLINKS define (glibc already handles it on eloop-threshold.h). - The pathmax.h logic to handle //path (neither Linux nor Hurd makes this distinction). - Don't explict set ENOMEM on malloc failure (it is already handled by malloc itself). - The usage of malloca.h routines. Checked on x86_64-linux-gnu --- stdlib/canonicalize.c | 244 +++++++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 113 deletions(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index cbd885a3c5..c58439b3fd 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -16,8 +16,9 @@ License along with the GNU C Library; if not, see . */ -#include #include + +#include #include #include #include @@ -29,10 +30,10 @@ #include /* Return the canonical absolute name of file NAME. A canonical name - does not contain any `.', `..' components nor any repeated path + does not contain any ".", ".." components nor any repeated path separators ('/') or symlinks. All path components must exist. If RESOLVED is null, the result is malloc'd; otherwise, if the - canonical name is PATH_MAX chars or more, returns null with `errno' + canonical name is PATH_MAX chars or more, returns null with 'errno' set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the name in RESOLVED. If the name cannot be resolved and RESOLVED is non-NULL, it contains the path of the first component @@ -50,9 +51,9 @@ __realpath (const char *name, char *resolved) if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if - either parameter is a null pointer. We extend this to allow - the RESOLVED parameter to be NULL in case the we are expected to - allocate the room for the return value. */ + either parameter is a null pointer. We extend this to allow + the RESOLVED parameter to be NULL in case the we are expected to + allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } @@ -60,7 +61,7 @@ __realpath (const char *name, char *resolved) if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if - the name argument points to an empty string. */ + the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } @@ -70,152 +71,169 @@ __realpath (const char *name, char *resolved) #else path_max = __pathconf (name, _PC_PATH_MAX); if (path_max <= 0) - path_max = 1024; + path_max = 8192; #endif if (resolved == NULL) { rpath = malloc (path_max); if (rpath == NULL) - return NULL; + return NULL; } else rpath = resolved; rpath_limit = rpath + path_max; + if (name[0] != '/') { if (!__getcwd (rpath, path_max)) - { - rpath[0] = '\0'; - goto error; - } - dest = __rawmemchr (rpath, '\0'); + { + rpath[0] = '\0'; + goto error; + } + dest = strchr (rpath, '\0'); } else { - rpath[0] = '/'; - dest = rpath + 1; + dest = rpath; + *dest++ = '/'; } + start = name; - for (start = end = name; *start; start = end) + for (end = start; *start; start = end) { +#ifdef _LIBC struct stat64 st; - int n; +#else + struct stat st; +#endif /* Skip sequence of multiple path-separators. */ while (*start == '/') - ++start; + ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) - /* Nothing. */; + /* Nothing. */; if (end - start == 0) - break; + break; else if (end - start == 1 && start[0] == '.') - /* nothing */; + /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') - { - /* Back up to previous component, ignore if at root already. */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - } + { + /* Back up to previous component, ignore if at root already. */ + if (dest > rpath + 1) + for (--dest; dest > rpath && dest[-1] != '/'; --dest) + continue; + } else - { - size_t new_size; - - if (dest[-1] != '/') - *dest++ = '/'; - - if (dest + (end - start) >= rpath_limit) - { - ptrdiff_t dest_offset = dest - rpath; - char *new_rpath; - - if (resolved) - { - __set_errno (ENAMETOOLONG); - if (dest > rpath + 1) - dest--; - *dest = '\0'; - goto error; - } - new_size = rpath_limit - rpath; - if (end - start + 1 > path_max) - new_size += end - start + 1; - else - new_size += path_max; - new_rpath = (char *) realloc (rpath, new_size); - if (new_rpath == NULL) - goto error; - rpath = new_rpath; - rpath_limit = rpath + new_size; - - dest = rpath + dest_offset; - } - - dest = __mempcpy (dest, start, end - start); - *dest = '\0'; - - if (__lxstat64 (_STAT_VER, rpath, &st) < 0) - goto error; - - if (S_ISLNK (st.st_mode)) - { - char *buf = __alloca (path_max); - size_t len; - - if (++num_links > __eloop_threshold ()) - { - __set_errno (ELOOP); - goto error; - } - - n = __readlink (rpath, buf, path_max - 1); - if (n < 0) - goto error; - buf[n] = '\0'; - - if (!extra_buf) - extra_buf = __alloca (path_max); - - len = strlen (end); - if (path_max - n <= len) - { - __set_errno (ENAMETOOLONG); - goto error; - } - - /* Careful here, end may be a pointer into extra_buf... */ - memmove (&extra_buf[n], end, len + 1); - name = end = memcpy (extra_buf, buf, n); - - if (buf[0] == '/') - dest = rpath + 1; /* It's an absolute symlink */ - else - /* Back up to previous component, ignore if at root already: */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - } - else if (!S_ISDIR (st.st_mode) && *end != '\0') - { - __set_errno (ENOTDIR); - goto error; - } - } + { + size_t new_size; + + if (dest[-1] != '/') + *dest++ = '/'; + + if (dest + (end - start) >= rpath_limit) + { + ptrdiff_t dest_offset = dest - rpath; + char *new_rpath; + + if (resolved) + { + __set_errno (ENAMETOOLONG); + if (dest > rpath + 1) + dest--; + *dest = '\0'; + goto error; + } + new_size = rpath_limit - rpath; + if (end - start + 1 > path_max) + new_size += end - start + 1; + else + new_size += path_max; + new_rpath = (char *) realloc (rpath, new_size); + if (new_rpath == NULL) + goto error; + rpath = new_rpath; + rpath_limit = rpath + new_size; + + dest = rpath + dest_offset; + } + + dest = __mempcpy (dest, start, end - start); + *dest = '\0'; + + if (__lxstat64 (_STAT_VER, rpath, &st) < 0) + goto error; + + if (S_ISLNK (st.st_mode)) + { + char *buf = __alloca (path_max); + size_t len; + ssize_t n; + + if (++num_links > __eloop_threshold ()) + { + __set_errno (ELOOP); + goto error; + } + + n = __readlink (rpath, buf, path_max - 1); + if (n < 0) + goto error; + buf[n] = '\0'; + + if (!extra_buf) + extra_buf = __alloca (path_max); + + len = strlen (end); + /* Check that n + len + 1 doesn't overflow and is <= path_max. */ + if (n >= SIZE_MAX - len || n + len >= path_max) + { + __set_errno (ENAMETOOLONG); + goto error; + } + + /* Careful here, end may be a pointer into extra_buf... */ + memmove (&extra_buf[n], end, len + 1); + name = end = memcpy (extra_buf, buf, n); + + if (buf[0] == '/') + { + dest = rpath; + *dest++ = '/'; /* It's an absolute symlink */ + } + else + { + /* Back up to previous component, ignore if at root + already: */ + if (dest > rpath + 1) + for (--dest; dest > rpath && dest[-1] != '/'; --dest) + continue; + } + } + else if (!S_ISDIR (st.st_mode) && *end != '\0') + { + __set_errno (ENOTDIR); + goto error; + } + } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; - assert (resolved == NULL || resolved == rpath); return rpath; error: - assert (resolved == NULL || resolved == rpath); - if (resolved == NULL) - free (rpath); + { + int saved_errno = errno; + if (resolved == NULL) + free (rpath); + __set_errno (saved_errno); + } return NULL; } libc_hidden_def (__realpath) From patchwork Thu Sep 10 15:19:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40391 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 85169397242E; Thu, 10 Sep 2020 15:19:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 85169397242E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1599751166; bh=WYWACisDDV2ICcn8YM8YfQ6DKnsPUE7KiPqkmc4j7PM=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=cQaoW0N0ExF3jaFmFOZiyWdQPzeJ29T9qvYMM2tmAHHWKpOkP7LaKlQGdEi96H5QU ab0tQ741OSu/C1N2OvSxByXMWBGUd9gQClwndoHViyGnpX47gh3CQxN0xu8FckNCWB hXiKOJsy2QVZjUNsekb0hL69xZLE2Byiscl8zCDE= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf43.google.com (mail-qv1-xf43.google.com [IPv6:2607:f8b0:4864:20::f43]) by sourceware.org (Postfix) with ESMTPS id 0EEFE385DC2E for ; Thu, 10 Sep 2020 15:19:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 0EEFE385DC2E Received: by mail-qv1-xf43.google.com with SMTP id z18so3519171qvp.6 for ; Thu, 10 Sep 2020 08:19:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WYWACisDDV2ICcn8YM8YfQ6DKnsPUE7KiPqkmc4j7PM=; b=uHxcOCAabZ15F7Q0RzQAd7p/UCV5ghtDj473IeJbOpRq0HH4d/Vrdrt7II/wrHZA3+ kSI1WOTNydJeEKF/lzGC/bEMCvm72q6eLFyKoO/TNxVZPUTwhmppYS/FXzWpLGlJPiuS eVSY0pkLc4sA5Vv+nvXXCt8dWN93uctv6Kys53RRKj1xSEftnQvMG+5i0slVaugzDOqF vjSBd+F4j/hKmeVoejyDQSkBjJobQRGlGUrGzQPBjcARXns9fZecsV1mUHtZ8qec3eRo kNKA7FmdXHhpDpxHnaoJcrHF8B3ZnI+22Sm7djGrr2MsAHCvmAf37K4ENUPbG6/PHsh6 Zo4g== X-Gm-Message-State: AOAM533ZPhOR3L+FT2C07NaQnx51ZrK9ptF9ajVVxxVt/6VjE2qjDClw bV3hjf549QnzouHR+4qm0+5rCYfD2EVstQ== X-Google-Smtp-Source: ABdhPJwhM3ZYyqbfcHgylS4yxzi50RGu5GC+IYOMyoQSYh9halsBu1egoQir18VH89mSrS7vD7SBfA== X-Received: by 2002:a0c:c3cb:: with SMTP id p11mr9258837qvi.101.1599751161236; Thu, 10 Sep 2020 08:19:21 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id z37sm7851090qtz.67.2020.09.10.08.19.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Sep 2020 08:19:20 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v3 2/4 v2] stdlib: Use fixed buffer size for realpath [BZ #26241] Date: Thu, 10 Sep 2020 12:19:13 -0300 Message-Id: <20200910151915.1982465-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> References: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Changes from previous version [1]: - I have abandoned the scratch_buffer usage, the PATH_MAX stack usage is acceptable and it avoid the potentially malloc usage. [1] https://sourceware.org/pipermail/libc-alpha/2020-August/117078.html --- It uses both a fixed internal buffer with PATH_MAX size to read and copy the results of the readlink call. Also, if PATH_MAX is not defined it uses a default value of 1024 as for other stdlib implementations. The expected stack usage is about 8k on Linux where PATH_MAX is define as 4096 (plus some internal function usage for local variable). Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/Makefile | 3 +- stdlib/canonicalize.c | 29 +++-- stdlib/tst-canon-bz26341.c | 108 ++++++++++++++++++ support/support_set_small_thread_stack_size.c | 12 +- support/xthread.h | 2 + 5 files changed, 134 insertions(+), 20 deletions(-) create mode 100644 stdlib/tst-canon-bz26341.c diff --git a/stdlib/Makefile b/stdlib/Makefile index 4615f6dfe7..7093b8a584 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -87,7 +87,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-makecontext-align test-bz22786 tst-strtod-nan-sign \ tst-swapcontext1 tst-setcontext4 tst-setcontext5 \ tst-setcontext6 tst-setcontext7 tst-setcontext8 \ - tst-setcontext9 tst-bz20544 + tst-setcontext9 tst-bz20544 tst-canon-bz26341 tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ tst-tls-atexit tst-tls-atexit-nodelete @@ -102,6 +102,7 @@ LDLIBS-test-atexit-race = $(shared-thread-library) LDLIBS-test-at_quick_exit-race = $(shared-thread-library) LDLIBS-test-cxa_atexit-race = $(shared-thread-library) LDLIBS-test-on_exit-race = $(shared-thread-library) +LDLIBS-tst-canon-bz26341 = $(shared-thread-library) LDLIBS-test-dlclose-exit-race = $(shared-thread-library) $(libdl) LDFLAGS-test-dlclose-exit-race = $(LDFLAGS-rdynamic) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index c58439b3fd..6798ed8963 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -29,6 +29,14 @@ #include #include +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +# define PATH_MAX 1024 +# endif +#endif + /* Return the canonical absolute name of file NAME. A canonical name does not contain any ".", ".." components nor any repeated path separators ('/') or symlinks. All path components must exist. If @@ -43,10 +51,11 @@ char * __realpath (const char *name, char *resolved) { - char *rpath, *dest, *extra_buf = NULL; + char *rpath, *dest; const char *start, *end, *rpath_limit; - long int path_max; + const size_t path_max = PATH_MAX; int num_links = 0; + char extra_buf[PATH_MAX]; if (name == NULL) { @@ -66,14 +75,6 @@ __realpath (const char *name, char *resolved) return NULL; } -#ifdef PATH_MAX - path_max = PATH_MAX; -#else - path_max = __pathconf (name, _PC_PATH_MAX); - if (path_max <= 0) - path_max = 8192; -#endif - if (resolved == NULL) { rpath = malloc (path_max); @@ -170,24 +171,20 @@ __realpath (const char *name, char *resolved) if (S_ISLNK (st.st_mode)) { - char *buf = __alloca (path_max); + char buf[PATH_MAX]; size_t len; ssize_t n; if (++num_links > __eloop_threshold ()) { __set_errno (ELOOP); - goto error; - } + goto error; } n = __readlink (rpath, buf, path_max - 1); if (n < 0) goto error; buf[n] = '\0'; - if (!extra_buf) - extra_buf = __alloca (path_max); - len = strlen (end); /* Check that n + len + 1 doesn't overflow and is <= path_max. */ if (n >= SIZE_MAX - len || n + len >= path_max) diff --git a/stdlib/tst-canon-bz26341.c b/stdlib/tst-canon-bz26341.c new file mode 100644 index 0000000000..63474bddaa --- /dev/null +++ b/stdlib/tst-canon-bz26341.c @@ -0,0 +1,108 @@ +/* Check if realpath does not consume extra stack space based on symlink + existance in the path (BZ #26341) + Copyright (C) 2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +static char *filename; +static size_t filenamelen; +static char *linkname; + +static int +maxsymlinks (void) +{ +#ifdef MAXSYMLINKS + return MAXSYMLINKS; +#else + long int sysconf_symloop_max = sysconf (_SC_SYMLOOP_MAX); + return sysconf_symloop_max <= 0 + ? _POSIX_SYMLOOP_MAX + : sysconf_symloop_max; +#endif +} + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +static void +create_link (void) +{ + int fd = create_temp_file ("tst-canon-bz26341", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + char *prevlink = filename; + int maxlinks = maxsymlinks (); + for (int i = 0; i < maxlinks; i++) + { + linkname = xasprintf ("%s%d", filename, i); + xsymlink (prevlink, linkname); + add_temp_file (linkname); + prevlink = linkname; + } + + filenamelen = strlen (filename); +} + +static void * +do_realpath (void *arg) +{ + /* Old implementation of realpath allocates a PATH_MAX using alloca + for each symlink in the path, leading to MAXSYMLINKS times PATH_MAX + maximum stack usage. + This stack allocations tries fill the thread allocated stack minus + both the thread (plus some slack) and the realpath (plus some slack). + If realpath uses more than 2 * PATH_MAX plus some slack it will trigger + a stackoverflow. */ + + const size_t realpath_usage = 2 * PATH_MAX + 1024; + const size_t thread_usage = 1 * PATH_MAX + 1024; + size_t stack_size = support_small_thread_stack_size () + - realpath_usage - thread_usage; + char stack[stack_size]; + char *resolved = stack + stack_size - thread_usage + 1024; + + char *p = realpath (linkname, resolved); + TEST_VERIFY (p != NULL); + TEST_COMPARE_BLOB (resolved, filenamelen, filename, filenamelen); + + return NULL; +} + +static int +do_test (void) +{ + create_link (); + + pthread_t th = xpthread_create (support_small_stack_thread_attribute (), + do_realpath, NULL); + xpthread_join (th); + + return 0; +} + +#include diff --git a/support/support_set_small_thread_stack_size.c b/support/support_set_small_thread_stack_size.c index 69d66e97db..74a0e38a72 100644 --- a/support/support_set_small_thread_stack_size.c +++ b/support/support_set_small_thread_stack_size.c @@ -20,8 +20,8 @@ #include #include -void -support_set_small_thread_stack_size (pthread_attr_t *attr) +size_t +support_small_thread_stack_size (void) { /* Some architectures have too small values for PTHREAD_STACK_MIN which cannot be used for creating threads. Ensure that the stack @@ -31,5 +31,11 @@ support_set_small_thread_stack_size (pthread_attr_t *attr) if (stack_size < PTHREAD_STACK_MIN) stack_size = PTHREAD_STACK_MIN; #endif - xpthread_attr_setstacksize (attr, stack_size); + return stack_size; +} + +void +support_set_small_thread_stack_size (pthread_attr_t *attr) +{ + xpthread_attr_setstacksize (attr, support_small_thread_stack_size ()); } diff --git a/support/xthread.h b/support/xthread.h index 05f8d4a7d9..6ba2f5a18b 100644 --- a/support/xthread.h +++ b/support/xthread.h @@ -78,6 +78,8 @@ void xpthread_attr_setguardsize (pthread_attr_t *attr, /* Set the stack size in ATTR to a small value, but still large enough to cover most internal glibc stack usage. */ void support_set_small_thread_stack_size (pthread_attr_t *attr); +/* Return the stack size used on support_set_small_thread_stack_size. */ +size_t support_small_thread_stack_size (void); /* Return a pointer to a thread attribute which requests a small stack. The caller must not free this pointer. */ From patchwork Thu Sep 10 15:19:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40392 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 16DFC397242F; Thu, 10 Sep 2020 15:19:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 16DFC397242F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1599751168; bh=GiojlFihNm/7IHBb+qNWVNBUfbwX3SOExNpvKz2BLiE=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=ueXFic6L3V+po1yW9gNF+W9xURXF1gWL3rTql5VUNn/Z/iSNG9CPyh1EMino9kC1Z FUDFNLvaPb9jgTjONmWcuoK+nRTvJMLK8CUATBoYfNl+1db7mecVyzkCXq3BaO73rb uBHBvHEQUZZIAnL4CPriUCCeDTFgRoplKfIVxj08= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x741.google.com (mail-qk1-x741.google.com [IPv6:2607:f8b0:4864:20::741]) by sourceware.org (Postfix) with ESMTPS id 8DB593972416 for ; Thu, 10 Sep 2020 15:19:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 8DB593972416 Received: by mail-qk1-x741.google.com with SMTP id 16so6428017qkf.4 for ; Thu, 10 Sep 2020 08:19:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=GiojlFihNm/7IHBb+qNWVNBUfbwX3SOExNpvKz2BLiE=; b=JECGYeeCLgbX2sYcaZ2nYaK4fgR7gwVPabfLN2Z7hvYiRN3FLO4lthmtey1bDsnUQt 0cSrGP8OJ/ifsIIaASrY2s8SBgprILFfIvtlHZYbzVACTblKz4sPtrn2kj2p0Zthe2Pf bftGSxOFPIIVFXQL7l4j7n2gAs0oQ7PBX7zhHt3c/zStb3DJB5S35b3io7NyqTkccrgy 8gg+AN6khnXaDouj9i/D8wkx/DbTrCRZZp5SecLqTPlp4VGdepyFBPoIuHrDqVcYXcGF kcbH6/0dd5KRIl6mTmEdBp9wEZymzNttmZm5LQEw4ZnTkv1PP2qnFSYMAf5evo+islZg a2pw== X-Gm-Message-State: AOAM532E0QU+lh21BvNQH5FHUi3jvhQwKc/RAGnmubh7AZ1yTVU7MmXm ExkIZyimS+waJJBiOVms5TqlCOJQ2WPmCA== X-Google-Smtp-Source: ABdhPJy/D1pybwB6bld4n3sWpvzaAjd4v0LMkL8I9XtXPJ8aH9VqxTE3ipIaFrcLnEGO1bMftdL57w== X-Received: by 2002:a37:9f52:: with SMTP id i79mr8061752qke.109.1599751162738; Thu, 10 Sep 2020 08:19:22 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id z37sm7851090qtz.67.2020.09.10.08.19.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Sep 2020 08:19:22 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH 3/4] stdlib: Fix arithmetic overflows in realpath [BZ #26592] Date: Thu, 10 Sep 2020 12:19:14 -0300 Message-Id: <20200910151915.1982465-3-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> References: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The realpath uses an end-of-array pointer 'rpath_limit', and makes invalid (overflowing) comparisons against it to catch overflow: 117 /* Find end of path component. */ 118 if (dest + (end-start) >= rpath_limit) I could not see a easy way to stress this issue since it rely on how the input argument is layout in memory along with a large filename name that trigger the overflow comparison. However, the fix is simple enough where it simple reorganize arithmetic in the comparison. Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/canonicalize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 6798ed8963..44a25a9a59 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -136,7 +136,7 @@ __realpath (const char *name, char *resolved) if (dest[-1] != '/') *dest++ = '/'; - if (dest + (end - start) >= rpath_limit) + if (end - start >= rpath_limit - dest) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; From patchwork Thu Sep 10 15:19:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 40393 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 996173972437; Thu, 10 Sep 2020 15:19:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 996173972437 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1599751168; bh=zNjoCyV0nHdZ185LY1n+WORtjEv6Oir9KZEn4YIvXXk=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=Y1dUy1b2M69gceOclCwe0CwtIkT5Qn09dDpqQadVF9+aR5Hq1iP1O+HePpAWsIYnI q0Cnv4HoxYdiztzHSE8q1O4+/cuL4ZOfyrv0hexEcElv7b0CuM5BwctF2Ke+Ydi2UN 84lWBhEEgMyw9H13DWSsUm/NEzIXfq/fDIjk3oY0= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by sourceware.org (Postfix) with ESMTPS id 9B5763857C50 for ; Thu, 10 Sep 2020 15:19:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9B5763857C50 Received: by mail-qk1-x744.google.com with SMTP id g72so6397382qke.8 for ; Thu, 10 Sep 2020 08:19:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zNjoCyV0nHdZ185LY1n+WORtjEv6Oir9KZEn4YIvXXk=; b=PsMn4SigADjeleetrQ54qyxztIeygIwHisTGNfYB9fsbgWAOxq6wlAEnG+MIb/g3ls shSWi6C+8cNb2CWpjN3f0vbBXLLI2RnaVeF8HIWxMK3GKAuKNq1i55WHeKFl6ObWz4EP rftu3NUT+YwusQx0ycXIr+tItCHDLabe2h30Hzts5fjuhp7fK7ZMuQYV9B8sjNZnxoZM GRSCKETtndzVYae6xESije9Jxo8gZ0oa4b1+SvgAkIptw1T85SIlAu/mm5LznlIkhCZU Sy9ViPCBeaAammd+ntr2y9YU1QEL+FyDLW7LOW+USXLt2jLjwSyx+iHPUNkTJPb8mjw0 QRwQ== X-Gm-Message-State: AOAM532TylYgNazcQ5ftU/BE8ToHy3Hyr1atsvB7mmGj9U8/6fLwHL8M nrjlHL0dBVbdIu3sloB+w0Qi+b4YgiZwJA== X-Google-Smtp-Source: ABdhPJyCInZf909bbT9CudJYIHY7jjy28pzSR8RKCwb+NeuCJa5+BocFJ4Q9Nx7+KEx33vuc9oU6uw== X-Received: by 2002:a37:897:: with SMTP id 145mr8622524qki.82.1599751164525; Thu, 10 Sep 2020 08:19:24 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id z37sm7851090qtz.67.2020.09.10.08.19.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Sep 2020 08:19:24 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH 4/4] stdlib: Remove lstat usage from realpath [BZ #24970] Date: Thu, 10 Sep 2020 12:19:15 -0300 Message-Id: <20200910151915.1982465-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> References: <20200910151915.1982465-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The readlink already tells whether the file is a symlink, so there is no need to call lstat to check it. However for '..' it requires an extra readlink check if the previous component can be really accessed, otherwise the next iteration will check a possible valid path and end early. It should performance-wise acceptable and a gain over lstat, afaik symlink should not update any inode information. Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/canonicalize.c | 52 ++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 44a25a9a59..952f4dca41 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -55,6 +55,7 @@ __realpath (const char *name, char *resolved) const char *start, *end, *rpath_limit; const size_t path_max = PATH_MAX; int num_links = 0; + char buf[PATH_MAX]; char extra_buf[PATH_MAX]; if (name == NULL) @@ -104,12 +105,6 @@ __realpath (const char *name, char *resolved) for (end = start; *start; start = end) { -#ifdef _LIBC - struct stat64 st; -#else - struct stat st; -#endif - /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; @@ -118,12 +113,25 @@ __realpath (const char *name, char *resolved) for (end = start; *end && *end != '/'; ++end) /* Nothing. */; - if (end - start == 0) - break; - else if (end - start == 1 && start[0] == '.') + if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { + ssize_t n; + + if (dest[-1] != '/') + *dest++ = '/'; + *dest = '\0'; + + n = __readlink (rpath, buf, path_max - 1); + if (n == -1) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno != EINVAL) + goto error; + } + /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) for (--dest; dest > rpath && dest[-1] != '/'; --dest) @@ -132,6 +140,7 @@ __realpath (const char *name, char *resolved) else { size_t new_size; + ssize_t n; if (dest[-1] != '/') *dest++ = '/'; @@ -166,25 +175,23 @@ __realpath (const char *name, char *resolved) dest = __mempcpy (dest, start, end - start); *dest = '\0'; - if (__lxstat64 (_STAT_VER, rpath, &st) < 0) - goto error; - - if (S_ISLNK (st.st_mode)) + n = __readlink (rpath, buf, path_max - 1); + if (n < 0) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno != EINVAL) + goto error; + } + else { - char buf[PATH_MAX]; size_t len; - ssize_t n; if (++num_links > __eloop_threshold ()) { __set_errno (ELOOP); goto error; } - n = __readlink (rpath, buf, path_max - 1); - if (n < 0) - goto error; - buf[n] = '\0'; - len = strlen (end); /* Check that n + len + 1 doesn't overflow and is <= path_max. */ if (n >= SIZE_MAX - len || n + len >= path_max) @@ -211,11 +218,6 @@ __realpath (const char *name, char *resolved) continue; } } - else if (!S_ISDIR (st.st_mode) && *end != '\0') - { - __set_errno (ENOTDIR); - goto error; - } } } if (dest > rpath + 1 && dest[-1] == '/')