From d1e6ffe20e2ccf6a38cfbe4d1bc3a20b92d37fd1 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Thu, 9 Nov 2017 18:24:48 +0000 Subject: [PATCH] 9052 nss_files exec attr search leaks memory on dlclose Reviewed by: Tim Kordas Reviewed by: Jerry Jelinek Reviewed by: Dan McDonald Reviewed by: Richard Lowe Approved by: Gordon Ross --- usr/src/lib/nsswitch/files/common/files_common.c | 13 ++++++++ usr/src/lib/nsswitch/files/common/files_common.h | 8 +++++ usr/src/lib/nsswitch/files/common/getexecattr.c | 39 ++++++++++++++++-------- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/usr/src/lib/nsswitch/files/common/files_common.c b/usr/src/lib/nsswitch/files/common/files_common.c index 4755aec86b..5892ed1430 100644 --- a/usr/src/lib/nsswitch/files/common/files_common.c +++ b/usr/src/lib/nsswitch/files/common/files_common.c @@ -24,6 +24,7 @@ */ /* * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. */ /* @@ -738,3 +739,15 @@ _nss_files_check_name_aliases(nss_XbyY_args_t *argp, const char *line, } return (0); } + +/* + * A few NSS modules hold onto data for the duration of their module. In this + * case, when that module goes away, we must free that data. This is a place + * that allows for modules to register items to take care of. + */ +#pragma fini(_nss_files_fini) +static void +_nss_files_fini(void) +{ + getexecattr_fini(); +} diff --git a/usr/src/lib/nsswitch/files/common/files_common.h b/usr/src/lib/nsswitch/files/common/files_common.h index 2138d7180e..b08a666eb6 100644 --- a/usr/src/lib/nsswitch/files/common/files_common.h +++ b/usr/src/lib/nsswitch/files/common/files_common.h @@ -23,6 +23,9 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2017, Joyent, INc. + */ /* * Common code and structures used by name-service-switch "files" backends. @@ -140,6 +143,11 @@ extern int validate_group_ids(char *line, int *linelenp, int buflen, extern int validate_passwd_ids(char *line, int *linelenp, int buflen, int extra_chars); +/* + * Destructors used by different bits. + */ +extern void getexecattr_fini(void); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/nsswitch/files/common/getexecattr.c b/usr/src/lib/nsswitch/files/common/getexecattr.c index c0b47ea419..04ecc445bc 100644 --- a/usr/src/lib/nsswitch/files/common/getexecattr.c +++ b/usr/src/lib/nsswitch/files/common/getexecattr.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Joyent, Inc. */ #include @@ -49,6 +50,19 @@ extern int _readbufline(char *, int, char *, int, int *); extern char *_exec_wild_id(char *, const char *); extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *); +/* + * _exec_files_XY_all wants to cache data from the attribute file. + */ +static char *exec_f_buf; +static time_t exec_read_time; + +void +getexecattr_fini(void) +{ + free(exec_f_buf); + exec_f_buf = NULL; +} + /* * check_match: returns 1 if matching entry found, else returns 0. @@ -104,10 +118,8 @@ _exec_files_XY_all(files_backend_ptr_t be, int exec_fd = 0; int f_size = 0; time_t f_time = 0; - static time_t read_time = 0; char *first; char *last; - static char *f_buf = NULL; struct stat f_stat; nss_status_t res = NSS_NOTFOUND; _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); @@ -132,7 +144,7 @@ _exec_files_XY_all(files_backend_ptr_t be, f_size = f_stat.st_size; f_time = f_stat.st_mtime; - while (f_time > read_time || f_buf == NULL) { + while (f_time > exec_read_time || exec_f_buf == NULL) { /* * file has been modified since we last read it * or we never read it or memory allocation @@ -150,32 +162,35 @@ _exec_files_XY_all(files_backend_ptr_t be, return (NSS_UNAVAIL); } exec_fd = fileno(be->f); - if (f_buf != NULL) - free(f_buf); - if ((f_buf = malloc(f_size)) == NULL) { + if (exec_f_buf != NULL) + free(exec_f_buf); + if ((exec_f_buf = malloc(f_size)) == NULL) { (void) _nss_files_endent(be, 0); (void) rw_unlock(&exec_lock); return (NSS_UNAVAIL); } - if (read(exec_fd, f_buf, f_size) < f_size) { - free(f_buf); + if (read(exec_fd, exec_f_buf, f_size) < f_size) { + free(exec_f_buf); + exec_f_buf = NULL; (void) _nss_files_endent(be, 0); (void) rw_unlock(&exec_lock); return (NSS_UNAVAIL); } - read_time = f_time; + exec_read_time = f_time; (void) rw_unlock(&exec_lock); /* * verify that the file did not change after * we read it. */ if (rw_rdlock(&exec_lock) != 0) { - free(f_buf); + free(exec_f_buf); + exec_f_buf = NULL; (void) _nss_files_endent(be, 0); return (NSS_UNAVAIL); } if (stat(be->filename, &f_stat) != 0) { - free(f_buf); + free(exec_f_buf); + exec_f_buf = NULL; (void) _nss_files_endent(be, 0); (void) rw_unlock(&exec_lock); return (NSS_UNAVAIL); @@ -190,7 +205,7 @@ _exec_files_XY_all(files_backend_ptr_t be, int linelen = 0; char *instr = be->buf; - linelen = _readbufline(f_buf, f_size, instr, be->minbuf, + linelen = _readbufline(exec_f_buf, f_size, instr, be->minbuf, &lastlen); if (linelen < 0) { /* End of file */ -- 2.11.4.GIT