FreeBSD Bugzilla – Attachment 149937 Details for
Bug 195128
Memory leaks in lib/libpam/modules due to memory handling with login_getcapstr, et al
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Fix and test case against FreeBSD current
freebsd-head-cgetcap-leak.diff (text/plain), 8.71 KB, created by
Daniel O'Connor
on 2014-11-27 10:52:13 UTC
(
hide
)
Description:
Fix and test case against FreeBSD current
Filename:
MIME Type:
Creator:
Daniel O'Connor
Created:
2014-11-27 10:52:13 UTC
Size:
8.71 KB
patch
obsolete
>Index: lib/libc/gen/getcap.c >=================================================================== >--- lib/libc/gen/getcap.c (revision 274808) >+++ lib/libc/gen/getcap.c (working copy) >@@ -32,20 +32,21 @@ > > #if defined(LIBC_SCCS) && !defined(lint) > static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94"; > #endif /* LIBC_SCCS and not lint */ > #include <sys/cdefs.h> > __FBSDID("$FreeBSD$"); > > #include "namespace.h" > #include <sys/types.h> > >+#include <assert.h> > #include <ctype.h> > #include <errno.h> > #include <fcntl.h> > #include <limits.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <unistd.h> > #include "un-namespace.h" > >@@ -57,25 +58,36 @@ __FBSDID("$FreeBSD$"); > #define MAX_RECURSION 32 /* maximum getent recursion */ > #define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ > > #define RECOK (char)0 > #define TCERR (char)1 > #define SHADOW (char)2 > > static size_t topreclen; /* toprec length */ > static char *toprec; /* Additional record specified by cgetset() */ > static int gottoprec; /* Flag indicating retrieval of toprecord */ >+static void **allocs; /* Array of allocations to free in cgetclose */ >+static int nallocs; /* Number of allocs */ > > static int cdbget(DB *, char **, const char *); > static int getent(char **, u_int *, char **, int, const char *, int, char *); > static int nfcmp(char *, char *); > >+static void >+cgetregisteralloc(void *alloc) >+{ >+ nallocs++; >+ allocs = realloc(allocs, nallocs * sizeof(allocs[0])); >+ assert(allocs != NULL); >+ allocs[nallocs - 1] = alloc; >+} >+ > /* > * Cgetset() allows the addition of a user specified buffer to be added > * to the database array, in effect "pushing" the buffer on top of the > * virtual database. 0 is returned on success, -1 on failure. > */ > int > cgetset(const char *ent) > { > if (ent == NULL) { > if (toprec) >@@ -517,20 +529,21 @@ tc_exp: { > if (myfd) > (void)_close(fd); > *len = rp - record - 1; /* don't count NUL */ > if (r_end > rp) > if ((record = > reallocf(record, (size_t)(rp - record))) == NULL) { > errno = ENOMEM; > return (-2); > } > >+ cgetregisteralloc(record); > *cap = record; > if (tc_not_resolved) > return (1); > return (0); > } > > static int > cdbget(DB *capdbp, char **bp, const char *name) > { > DBT key, data; >@@ -627,20 +640,30 @@ static char **dbp; > > int > cgetclose(void) > { > if (pfp != NULL) { > (void)fclose(pfp); > pfp = NULL; > } > dbp = NULL; > gottoprec = 0; >+ if (toprec != NULL) { >+ free(toprec); >+ toprec = NULL; >+ } >+ if (allocs != NULL) { >+ while (nallocs-- > 0) >+ free(allocs[nallocs]); >+ free(allocs); >+ allocs = NULL; >+ } > slash = 0; > return(0); > } > > /* > * Cgetnext() gets either the first or next entry in the logical database > * specified by db_array. It returns 0 upon completion of the database, 1 > * upon returning an entry with more remaining, and -1 if an error occurs. > */ > int >@@ -886,20 +909,21 @@ cgetstr(char *buf, const char *cap, char > *mp++ = '\0'; /* loop invariant let's us do this */ > m_room--; > len = mp - mem - 1; > > /* > * Give back any extra memory and return value and success. > */ > if (m_room != 0) > if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) > return (-2); >+ cgetregisteralloc(mem); > *str = mem; > return (len); > } > > /* > * Cgetustr retrieves the value of the string capability cap from the > * capability record pointed to by buf. The difference between cgetustr() > * and cgetstr() is that cgetustr does not decode escapes but rather treats > * all characters literally. A pointer to a NUL terminated malloc'd > * copy of the string is returned in the char pointed to by str. The >@@ -958,20 +982,21 @@ cgetustr(char *buf, const char *cap, cha > *mp++ = '\0'; /* loop invariant let's us do this */ > m_room--; > len = mp - mem - 1; > > /* > * Give back any extra memory and return value and success. > */ > if (m_room != 0) > if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) > return (-2); >+ cgetregisteralloc(mem); > *str = mem; > return (len); > } > > /* > * Cgetnum retrieves the value of the numeric capability cap from the > * capability record pointed to by buf. The numeric value is returned in > * the long pointed to by num. 0 is returned on success, -1 if the requested > * numeric capability couldn't be found. > */ >Index: lib/libc/tests/gen/Makefile >=================================================================== >--- lib/libc/tests/gen/Makefile (revision 274808) >+++ lib/libc/tests/gen/Makefile (working copy) >@@ -1,18 +1,19 @@ > # $FreeBSD$ > > .include <bsd.own.mk> > > TESTSDIR= ${TESTSBASE}/lib/libc/gen > > ATF_TESTS_C= arc4random_test > ATF_TESTS_C+= fpclassify2_test >+ATF_TESTS_C+= getcap_test > > # TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep > # TODO: t_siginfo (fixes require further inspection) > # TODO: t_sethostname_test (consistently screws up the hostname) > > NETBSD_ATF_TESTS_C= alarm_test > NETBSD_ATF_TESTS_C+= assert_test > NETBSD_ATF_TESTS_C+= basedirname_test > NETBSD_ATF_TESTS_C+= dir_test > NETBSD_ATF_TESTS_C+= floatunditf_test >Index: lib/libc/tests/gen/getcap_test.c >=================================================================== >--- lib/libc/tests/gen/getcap_test.c (revision 0) >+++ lib/libc/tests/gen/getcap_test.c (working copy) >@@ -0,0 +1,115 @@ >+/*- >+ * Copyright (c) 2014 EMC / Isilon Storage Division >+ * All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS >+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED >+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >+ * POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+/* >+ * Checks for memory leaks in cgetstr() (Bug 195128) >+ * >+ * Requirements: >+ * /etc/login.conf with default capability with valid path record >+ * jemalloc >+ */ >+#include <atf-c.h> >+ >+#include <assert.h> >+#include <err.h> >+#include <fcntl.h> >+#include <login_cap.h> >+#include <malloc_np.h> >+#include <stdio.h> >+#include <stdint.h> >+#include <stdlib.h> >+#include <string.h> >+#include <unistd.h> >+ >+ATF_TC(cgetstr_leak); >+ATF_TC_HEAD(cgetstr_leak, tc) >+{ >+ >+ atf_tc_set_md_var(tc, "descr", >+ "Check cgetstr(3) for memory leakage (Bug 195128)"); >+} >+ >+void >+malgetuint64(char *name, uint64_t *val) >+{ >+ size_t len; >+ >+ len = sizeof(*val); >+ if (mallctl(name, val, &len, NULL, 0) == -1) >+ err(2, "mallctl failed"); >+ if (len != sizeof(*val)) >+ err(2, "bad size from mallctl"); >+} >+ >+int64_t >+getalloc(void) >+{ >+ uint64_t allocated, deallocated; >+ >+ malgetuint64("thread.allocated", &allocated); >+ malgetuint64("thread.deallocated", &deallocated); >+ >+ return ((int64_t)(allocated - deallocated)); >+} >+ >+ATF_TC_BODY(cgetstr_leak, tc) >+{ >+ char *buf, *str, *dbarray[] = { _PATH_LOGIN_CONF }; >+ int errcode, i; >+ int64_t allocated, start, delta; >+ >+ start = getalloc(); >+ >+ i = cgetent(&buf, dbarray, "default"); >+ if (i == -1) >+ atf_tc_skip("Unable to find default class in " _PATH_LOGIN_CONF); >+ if (i == -2) >+ atf_tc_skip("Error reading login.conf"); >+ >+ allocated = getalloc(); >+ for (i = 0; i < 1000; i++) { >+ if ((errcode = cgetstr(buf, "path", &str)) < 0) >+ atf_tc_skip("cgetstr failed with %d", errcode); >+ } >+ allocated = getalloc(); >+ free(buf); >+ cgetclose(); >+ >+ allocated = getalloc(); >+ delta = allocated - start; >+ if (delta > 0) >+ atf_tc_fail("Failure: leaked %jd bytes", delta); >+ else >+ (void)printf("OK: leaked %jd bytes\n", delta); >+} >+ >+ATF_TP_ADD_TCS(tp) >+{ >+ >+ ATF_TP_ADD_TC(tp, cgetstr_leak); >+ >+ return atf_no_error(); >+} > >Property changes on: lib/libc/tests/gen/getcap_test.c >___________________________________________________________________ >Added: svn:eol-style >## -0,0 +1 ## >+native >\ No newline at end of property >Added: svn:mime-type >## -0,0 +1 ## >+text/plain >\ No newline at end of property >Added: svn:keywords >## -0,0 +1 ## >+FreeBSD=%H >\ No newline at end of property
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 195128
:
149711
| 149937