View | Details | Raw Unified | Return to bug 195128 | Differences between
and this patch

Collapse All | Expand All

(-)lib/libc/gen/getcap.c (+25 lines)
Lines 32-51 Link Here
32
32
33
#if defined(LIBC_SCCS) && !defined(lint)
33
#if defined(LIBC_SCCS) && !defined(lint)
34
static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 3/25/94";
34
static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 3/25/94";
35
#endif /* LIBC_SCCS and not lint */
35
#endif /* LIBC_SCCS and not lint */
36
#include <sys/cdefs.h>
36
#include <sys/cdefs.h>
37
__FBSDID("$FreeBSD$");
37
__FBSDID("$FreeBSD$");
38
38
39
#include "namespace.h"
39
#include "namespace.h"
40
#include <sys/types.h>
40
#include <sys/types.h>
41
41
42
#include <assert.h>
42
#include <ctype.h>
43
#include <ctype.h>
43
#include <errno.h>
44
#include <errno.h>
44
#include <fcntl.h>
45
#include <fcntl.h>
45
#include <limits.h>
46
#include <limits.h>
46
#include <stdio.h>
47
#include <stdio.h>
47
#include <stdlib.h>
48
#include <stdlib.h>
48
#include <string.h>
49
#include <string.h>
49
#include <unistd.h>
50
#include <unistd.h>
50
#include "un-namespace.h"
51
#include "un-namespace.h"
51
52
Lines 57-81 __FBSDID("$FreeBSD$"); Link Here
57
#define	MAX_RECURSION	32		/* maximum getent recursion */
58
#define	MAX_RECURSION	32		/* maximum getent recursion */
58
#define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */
59
#define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */
59
60
60
#define RECOK	(char)0
61
#define RECOK	(char)0
61
#define TCERR	(char)1
62
#define TCERR	(char)1
62
#define	SHADOW	(char)2
63
#define	SHADOW	(char)2
63
64
64
static size_t	 topreclen;	/* toprec length */
65
static size_t	 topreclen;	/* toprec length */
65
static char	*toprec;	/* Additional record specified by cgetset() */
66
static char	*toprec;	/* Additional record specified by cgetset() */
66
static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
67
static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
68
static void	**allocs;	/* Array of allocations to free in cgetclose */
69
static int	nallocs;	/* Number of allocs */
67
70
68
static int	cdbget(DB *, char **, const char *);
71
static int	cdbget(DB *, char **, const char *);
69
static int 	getent(char **, u_int *, char **, int, const char *, int, char *);
72
static int 	getent(char **, u_int *, char **, int, const char *, int, char *);
70
static int	nfcmp(char *, char *);
73
static int	nfcmp(char *, char *);
71
74
75
static void
76
cgetregisteralloc(void *alloc)
77
{
78
	nallocs++;
79
	allocs = realloc(allocs, nallocs * sizeof(allocs[0]));
80
	assert(allocs != NULL);
81
	allocs[nallocs - 1] = alloc;
82
}
83
72
/*
84
/*
73
 * Cgetset() allows the addition of a user specified buffer to be added
85
 * Cgetset() allows the addition of a user specified buffer to be added
74
 * to the database array, in effect "pushing" the buffer on top of the
86
 * to the database array, in effect "pushing" the buffer on top of the
75
 * virtual database. 0 is returned on success, -1 on failure.
87
 * virtual database. 0 is returned on success, -1 on failure.
76
 */
88
 */
77
int
89
int
78
cgetset(const char *ent)
90
cgetset(const char *ent)
79
{
91
{
80
	if (ent == NULL) {
92
	if (ent == NULL) {
81
		if (toprec)
93
		if (toprec)
Lines 517-536 tc_exp: { Link Here
517
	if (myfd)
529
	if (myfd)
518
		(void)_close(fd);
530
		(void)_close(fd);
519
	*len = rp - record - 1;	/* don't count NUL */
531
	*len = rp - record - 1;	/* don't count NUL */
520
	if (r_end > rp)
532
	if (r_end > rp)
521
		if ((record =
533
		if ((record =
522
		     reallocf(record, (size_t)(rp - record))) == NULL) {
534
		     reallocf(record, (size_t)(rp - record))) == NULL) {
523
			errno = ENOMEM;
535
			errno = ENOMEM;
524
			return (-2);
536
			return (-2);
525
		}
537
		}
526
538
539
	cgetregisteralloc(record);
527
	*cap = record;
540
	*cap = record;
528
	if (tc_not_resolved)
541
	if (tc_not_resolved)
529
		return (1);
542
		return (1);
530
	return (0);
543
	return (0);
531
}
544
}
532
545
533
static int
546
static int
534
cdbget(DB *capdbp, char **bp, const char *name)
547
cdbget(DB *capdbp, char **bp, const char *name)
535
{
548
{
536
	DBT key, data;
549
	DBT key, data;
Lines 627-646 static char **dbp; Link Here
627
640
628
int
641
int
629
cgetclose(void)
642
cgetclose(void)
630
{
643
{
631
	if (pfp != NULL) {
644
	if (pfp != NULL) {
632
		(void)fclose(pfp);
645
		(void)fclose(pfp);
633
		pfp = NULL;
646
		pfp = NULL;
634
	}
647
	}
635
	dbp = NULL;
648
	dbp = NULL;
636
	gottoprec = 0;
649
	gottoprec = 0;
650
	if (toprec != NULL) {
651
		free(toprec);
652
		toprec = NULL;
653
	}
654
	if (allocs != NULL) {
655
		while (nallocs-- > 0)
656
			free(allocs[nallocs]);
657
		free(allocs);
658
		allocs = NULL;
659
	}
637
	slash = 0;
660
	slash = 0;
638
	return(0);
661
	return(0);
639
}
662
}
640
663
641
/*
664
/*
642
 * Cgetnext() gets either the first or next entry in the logical database
665
 * Cgetnext() gets either the first or next entry in the logical database
643
 * specified by db_array.  It returns 0 upon completion of the database, 1
666
 * specified by db_array.  It returns 0 upon completion of the database, 1
644
 * upon returning an entry with more remaining, and -1 if an error occurs.
667
 * upon returning an entry with more remaining, and -1 if an error occurs.
645
 */
668
 */
646
int
669
int
Lines 886-905 cgetstr(char *buf, const char *cap, char Link Here
886
	*mp++ = '\0';	/* loop invariant let's us do this */
909
	*mp++ = '\0';	/* loop invariant let's us do this */
887
	m_room--;
910
	m_room--;
888
	len = mp - mem - 1;
911
	len = mp - mem - 1;
889
912
890
	/*
913
	/*
891
	 * Give back any extra memory and return value and success.
914
	 * Give back any extra memory and return value and success.
892
	 */
915
	 */
893
	if (m_room != 0)
916
	if (m_room != 0)
894
		if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL)
917
		if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL)
895
			return (-2);
918
			return (-2);
919
	cgetregisteralloc(mem);
896
	*str = mem;
920
	*str = mem;
897
	return (len);
921
	return (len);
898
}
922
}
899
923
900
/*
924
/*
901
 * Cgetustr retrieves the value of the string capability cap from the
925
 * Cgetustr retrieves the value of the string capability cap from the
902
 * capability record pointed to by buf.  The difference between cgetustr()
926
 * capability record pointed to by buf.  The difference between cgetustr()
903
 * and cgetstr() is that cgetustr does not decode escapes but rather treats
927
 * and cgetstr() is that cgetustr does not decode escapes but rather treats
904
 * all characters literally.  A pointer to a  NUL terminated malloc'd
928
 * all characters literally.  A pointer to a  NUL terminated malloc'd
905
 * copy of the string is returned in the char pointed to by str.  The
929
 * copy of the string is returned in the char pointed to by str.  The
Lines 958-977 cgetustr(char *buf, const char *cap, cha Link Here
958
	*mp++ = '\0';	/* loop invariant let's us do this */
982
	*mp++ = '\0';	/* loop invariant let's us do this */
959
	m_room--;
983
	m_room--;
960
	len = mp - mem - 1;
984
	len = mp - mem - 1;
961
985
962
	/*
986
	/*
963
	 * Give back any extra memory and return value and success.
987
	 * Give back any extra memory and return value and success.
964
	 */
988
	 */
965
	if (m_room != 0)
989
	if (m_room != 0)
966
		if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL)
990
		if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL)
967
			return (-2);
991
			return (-2);
992
	cgetregisteralloc(mem);
968
	*str = mem;
993
	*str = mem;
969
	return (len);
994
	return (len);
970
}
995
}
971
996
972
/*
997
/*
973
 * Cgetnum retrieves the value of the numeric capability cap from the
998
 * Cgetnum retrieves the value of the numeric capability cap from the
974
 * capability record pointed to by buf.  The numeric value is returned in
999
 * capability record pointed to by buf.  The numeric value is returned in
975
 * the long pointed to by num.  0 is returned on success, -1 if the requested
1000
 * the long pointed to by num.  0 is returned on success, -1 if the requested
976
 * numeric capability couldn't be found.
1001
 * numeric capability couldn't be found.
977
 */
1002
 */
(-)lib/libc/tests/gen/Makefile (+1 lines)
Lines 1-18 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
.include <bsd.own.mk>
3
.include <bsd.own.mk>
4
4
5
TESTSDIR=	${TESTSBASE}/lib/libc/gen
5
TESTSDIR=	${TESTSBASE}/lib/libc/gen
6
6
7
ATF_TESTS_C=		arc4random_test
7
ATF_TESTS_C=		arc4random_test
8
ATF_TESTS_C+=		fpclassify2_test
8
ATF_TESTS_C+=		fpclassify2_test
9
ATF_TESTS_C+=		getcap_test
9
10
10
# TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep
11
# TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep
11
# TODO: t_siginfo (fixes require further inspection)
12
# TODO: t_siginfo (fixes require further inspection)
12
# TODO: t_sethostname_test (consistently screws up the hostname)
13
# TODO: t_sethostname_test (consistently screws up the hostname)
13
14
14
NETBSD_ATF_TESTS_C=	alarm_test
15
NETBSD_ATF_TESTS_C=	alarm_test
15
NETBSD_ATF_TESTS_C+=	assert_test
16
NETBSD_ATF_TESTS_C+=	assert_test
16
NETBSD_ATF_TESTS_C+=	basedirname_test
17
NETBSD_ATF_TESTS_C+=	basedirname_test
17
NETBSD_ATF_TESTS_C+=	dir_test
18
NETBSD_ATF_TESTS_C+=	dir_test
18
NETBSD_ATF_TESTS_C+=	floatunditf_test
19
NETBSD_ATF_TESTS_C+=	floatunditf_test
(-)lib/libc/tests/gen/getcap_test.c (+115 lines)
Line 0 Link Here
1
/*-
2
 * Copyright (c) 2014 EMC / Isilon Storage Division
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
 * POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
/*
28
 * Checks for memory leaks in cgetstr() (Bug 195128)
29
 *
30
 * Requirements:
31
 *   /etc/login.conf with default capability with valid path record
32
 *   jemalloc
33
 */
34
#include <atf-c.h>
35
36
#include <assert.h>
37
#include <err.h>
38
#include <fcntl.h>
39
#include <login_cap.h>
40
#include <malloc_np.h>
41
#include <stdio.h>
42
#include <stdint.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <unistd.h>
46
47
ATF_TC(cgetstr_leak);
48
ATF_TC_HEAD(cgetstr_leak, tc)
49
{
50
51
	atf_tc_set_md_var(tc, "descr",
52
	    "Check cgetstr(3) for memory leakage (Bug 195128)");
53
}
54
55
void
56
malgetuint64(char *name, uint64_t *val)
57
{
58
	size_t len;
59
60
	len = sizeof(*val);
61
        if (mallctl(name, val, &len, NULL, 0) == -1)
62
                err(2, "mallctl failed");
63
	if (len != sizeof(*val))
64
		err(2, "bad size from mallctl");
65
}
66
67
int64_t
68
getalloc(void)
69
{
70
	uint64_t allocated, deallocated;
71
72
	malgetuint64("thread.allocated", &allocated);
73
	malgetuint64("thread.deallocated", &deallocated);
74
75
	return ((int64_t)(allocated - deallocated));
76
}
77
78
ATF_TC_BODY(cgetstr_leak, tc)
79
{
80
	char *buf, *str, *dbarray[] = { _PATH_LOGIN_CONF };
81
	int errcode, i;
82
	int64_t allocated, start, delta;
83
84
	start = getalloc();
85
86
	i = cgetent(&buf, dbarray, "default");
87
	if (i == -1)
88
		atf_tc_skip("Unable to find default class in " _PATH_LOGIN_CONF);
89
	if (i == -2)
90
		atf_tc_skip("Error reading login.conf");
91
92
	allocated = getalloc();
93
	for (i = 0; i < 1000; i++) {
94
		if ((errcode = cgetstr(buf, "path", &str)) < 0)
95
			atf_tc_skip("cgetstr failed with %d", errcode);
96
	}
97
	allocated = getalloc();
98
	free(buf);
99
	cgetclose();
100
101
	allocated = getalloc();
102
	delta = allocated - start;
103
	if (delta > 0)
104
		atf_tc_fail("Failure: leaked %jd bytes", delta);
105
	else
106
		(void)printf("OK: leaked %jd bytes\n", delta);
107
}
108
109
ATF_TP_ADD_TCS(tp)
110
{
111
112
	ATF_TP_ADD_TC(tp, cgetstr_leak);
113
114
	return atf_no_error();
115
}

Return to bug 195128