FreeBSD Bugzilla – Attachment 149711 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 & proto-test case
BR_RIPT_BSD10_CGETSTR-b.diff (text/plain), 8.61 KB, created by
Daniel O'Connor
on 2014-11-22 13:56:27 UTC
(
hide
)
Description:
Fix & proto-test case
Filename:
MIME Type:
Creator:
Daniel O'Connor
Created:
2014-11-22 13:56:27 UTC
Size:
8.61 KB
patch
obsolete
>Index: src/lib/libc/gen/getcap.c >=================================================================== >--- src/lib/libc/gen/getcap.c (revision 448004) >+++ src/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,27 @@ static char **dbp; > > int > cgetclose(void) > { > if (pfp != NULL) { > (void)fclose(pfp); > pfp = NULL; > } > dbp = NULL; > gottoprec = 0; >+ free(toprec); >+ if (allocs != NULL) { >+ while (nallocs-- > 0) >+ free(allocs[nallocs - 1]); >+ 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 +906,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 +979,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: src/lib/libc/tests/gen/Makefile >=================================================================== >--- src/lib/libc/tests/gen/Makefile (revision 448004) >+++ src/lib/libc/tests/gen/Makefile (working copy) >@@ -5,20 +5,21 @@ > CFLAGS+= -I${.CURDIR:H} > > TESTSDIR= ${TESTSBASE}/lib/libc/gen > > #ATF_TESTS+= posix_spawn > TESTS_SUBDIRS= posix_spawn > > ATF_TESTS_C= t_alarm > ATF_TESTS_C+= t_assert > ATF_TESTS_C+= t_basedirname >+ATF_TESTS_C+= t_getcap > # XXX: F_MAXFD DNE > #TESTS_C+= t_closefrom > # XXX: missing cpuset* support. > #TESTS_C+= t_cpuset > ATF_TESTS_C+= t_dir > ATF_TESTS_C+= t_fmtcheck > ATF_TESTS_C+= t_fnmatch > ATF_TESTS_C+= t_fpclassify > ATF_TESTS_C+= t_fpsetmask > ATF_TESTS_C+= t_fpsetround >Index: src/lib/libc/tests/gen/t_getcap.c >=================================================================== >--- src/lib/libc/tests/gen/t_getcap.c (revision 0) >+++ src/lib/libc/tests/gen/t_getcap.c (working copy) >@@ -0,0 +1,116 @@ >+/*- >+ * 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. >+ */ >+ >+#include <atf-c.h> >+ >+#include <assert.h> >+#include <dirent.h> >+#include <err.h> >+#include <fcntl.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 >+malallocated(void) { >+ uint64_t allocated, deallocated; >+ >+ malgetuint64("thread.allocated", &allocated); >+ malgetuint64("thread.deallocated", &deallocated); >+ printf("alloc: %jd dealloc: %jd delta: %jd\n", (uintmax_t)allocated, (uintmax_t)deallocated, (uintmax_t)(allocated - deallocated)); >+ return ((int64_t)(allocated - deallocated)); >+} >+ >+ATF_TC_BODY(cgetstr_leak, tc) >+{ >+ char *buf, *str, *dbarray[] = { "/etc/login.conf" }; >+ int errcode, i; >+ int64_t allocated, start; >+ >+ buf = "opt.dss"; >+ str = "primary"; >+ i = 1; >+ if (mallctl(buf, NULL, 0, str, strlen(str) + 1) == -1) >+ err(2, "mallctl failed"); >+ >+ start = malallocated(); >+ printf("Start %jd\n", (uintmax_t)start); >+ >+ i = cgetent(&buf, dbarray, "default"); >+ if (i == -1) >+ atf_tc_skip("Unable to find default class in login.conf"); >+ if (i == -2) >+ atf_tc_skip("Error reading login.conf"); >+ >+ allocated = malallocated(); >+ printf("cgetent %jd\n", (uintmax_t)allocated); >+ for (i = 0; i < 1000; i++) { >+ if ((errcode = cgetstr(buf, "path", &str)) < 0) >+ atf_tc_skip("cgetstr failed with %d", errcode); >+ } >+ allocated = malallocated(); >+ printf("cgetstr %jd\n", (uintmax_t)allocated); >+ free(buf); >+ cgetclose(); >+ >+ allocated = malallocated(); >+ printf("end %jd\n", (uintmax_t)allocated); >+ if (allocated - start > 4096) { >+ atf_tc_fail("Failure: leaked %jd bytes", allocated - start); >+ } else { >+ (void)printf("OK: used %jd bytes\n", allocated - start); >+ } >+} >+ >+ATF_TP_ADD_TCS(tp) >+{ >+ >+ ATF_TP_ADD_TC(tp, cgetstr_leak); >+ >+ return atf_no_error(); >+}
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