diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2014-09-04 14:40:59 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2014-09-04 14:43:34 +0000 |
commit | cd34a7d66f7efb60335bca5e0e87c0571a4d7a48 (patch) | |
tree | d373842465efbb2a0cf801cc8f0955884aa04d60 /main | |
parent | 3ef2e14c40e74821e39e2d6049976da5b7516f49 (diff) | |
download | aports-cd34a7d66f7efb60335bca5e0e87c0571a4d7a48.tar.bz2 aports-cd34a7d66f7efb60335bca5e0e87c0571a4d7a48.tar.xz |
main/freeradius: fix segfault in rlm_unix
rlm_unix can segfault if you require group name lookup (eg user needs
to be in a given system group) and 2 users are authenticating at the
same time.
Upstream has choosed to fix it differently and has added backport for
v3.0.x, but has not cherry-picked it for v2.x.x branch.
We use my proposed fix for v2.x.
upstream bug is https://github.com/FreeRADIUS/freeradius-server/issues/767
Diffstat (limited to 'main')
-rw-r--r-- | main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch | 288 | ||||
-rw-r--r-- | main/freeradius/APKBUILD | 6 |
2 files changed, 293 insertions, 1 deletions
diff --git a/main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch b/main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch new file mode 100644 index 0000000000..8c6ba176c8 --- /dev/null +++ b/main/freeradius/0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch @@ -0,0 +1,288 @@ +From aa269e0e41e4c4c3213149069d8083b27967a192 Mon Sep 17 00:00:00 2001 +From: Natanael Copa <ncopa@alpinelinux.org> +Date: Mon, 1 Sep 2014 16:38:59 +0200 +Subject: [PATCH] Use threadsafe wrapper for getpwnam/getgrnam + +Even if rlm_unix is marked as RLM_TYPE_THREAD_UNSAFE, it runs in a +separate thread than the main thread. Both main thread and rlm_unix +uses thread unsafe getpwnam/getgrnam which causes segfault when under +stress. + +We create a thread safe wrapper for those that uses TLS. + +ref #767 +--- + src/include/radiusd.h | 5 + + src/main/command.c | 6 +- + src/main/util.c | 144 ++++++++++++++++++++++ + src/modules/rlm_opendirectory/rlm_opendirectory.c | 6 +- + src/modules/rlm_unix/rlm_unix.c | 6 +- + 5 files changed, 158 insertions(+), 9 deletions(-) + +diff --git a/src/include/radiusd.h b/src/include/radiusd.h +index 2bf5173..6936305 100644 +--- a/src/include/radiusd.h ++++ b/src/include/radiusd.h +@@ -39,6 +39,9 @@ typedef struct auth_req REQUEST; + #include <pthread.h> + #endif + ++#include <pwd.h> ++#include <grp.h> ++ + #ifndef NDEBUG + #define REQUEST_MAGIC (0xdeadbeef) + #endif +@@ -506,6 +509,8 @@ int rad_copy_variable(char *dst, const char *from); + int rad_expand_xlat(REQUEST *request, const char *cmd, + int max_argc, const char *argv[], int can_fail, + size_t argv_buflen, char *argv_buf); ++struct passwd *rad_getpwnam(const char *name); ++struct group *rad_getgrnam(const char *name); + + /* client.c */ + RADCLIENT_LIST *clients_init(void); +diff --git a/src/main/command.c b/src/main/command.c +index bce7e9a..4debd2b 100644 +--- a/src/main/command.c ++++ b/src/main/command.c +@@ -1975,8 +1975,8 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this) + #if defined(HAVE_GETPEEREID) || defined (SO_PEERCRED) + if (sock->uid_name) { + struct passwd *pw; +- +- pw = getpwnam(sock->uid_name); ++ ++ pw = rad_getpwnam(sock->uid_name); + if (!pw) { + radlog(L_ERR, "Failed getting uid for %s: %s", + sock->uid_name, strerror(errno)); +@@ -1991,7 +1991,7 @@ static int command_socket_parse(CONF_SECTION *cs, rad_listen_t *this) + if (sock->gid_name) { + struct group *gr; + +- gr = getgrnam(sock->gid_name); ++ gr = rad_getgrnam(sock->gid_name); + if (!gr) { + radlog(L_ERR, "Failed getting gid for %s: %s", + sock->gid_name, strerror(errno)); +diff --git a/src/main/util.c b/src/main/util.c +index aebaff0..9ec96bb 100644 +--- a/src/main/util.c ++++ b/src/main/util.c +@@ -31,6 +31,21 @@ RCSID("$Id$") + + #include <sys/stat.h> + #include <fcntl.h> ++#include <unistd.h> ++#include <pwd.h> ++#include <grp.h> ++ ++struct pwgrnam_buffer { ++ struct passwd pwd; ++ char *pwbuffer; ++ int pwsize; ++ ++ struct group grp; ++ char *grbuffer; ++ int grsize; ++}; ++ ++fr_thread_local_setup(struct pwgrnam_buffer *, fr_pwgrnam_buffer); /* macro */ + + /* + * The signal() function in Solaris 2.5.1 sets SA_NODEFER in +@@ -778,3 +793,132 @@ int rad_expand_xlat(REQUEST *request, const char *cmd, + return argc; + } + ++/* ++ * Explicitly cleanup the memory allocated to the pwgrnam ++ * buffer. ++ */ ++static void _fr_pwgrnam_free(void *arg) ++{ ++ struct pwgrnam_buffer *p = (struct pwgrnam_buffer *)arg; ++ free(p->pwbuffer); ++ free(p->grbuffer); ++ free(p); ++} ++ ++/* ++ * Allocate buffers for our getpwnam/getgrnam wrappers. ++ */ ++static struct pwgrnam_buffer *init_pwgrnam_buffer(void) { ++ struct pwgrnam_buffer *p; ++ int ret; ++ ++ p = fr_thread_local_init(fr_pwgrnam_buffer, _fr_pwgrnam_free); ++ if (p) ++ return p; ++ ++ p = malloc(sizeof(struct pwgrnam_buffer)); ++ if (!p) { ++ fr_perror("Failed allocating pwnam/grnam buffer"); ++ return NULL; ++ } ++ ++#ifdef _SC_GETPW_R_SIZE_MAX ++ p->pwsize = sysconf(_SC_GETPW_R_SIZE_MAX); ++ if (p->pwsize <= 0) ++#endif ++ p->pwsize = 16384; ++ ++#ifdef _SC_GETGR_R_SIZE_MAX ++ p->grsize = sysconf(_SC_GETGR_R_SIZE_MAX); ++ if (p->grsize <= 0) ++#endif ++ p->grsize = 16384; ++ ++ p->pwbuffer = malloc(p->pwsize); ++ if (!p->pwbuffer) { ++ fr_perror("Failed allocating pwnam buffer"); ++ free(p); ++ return NULL; ++ } ++ ++ p->grbuffer = malloc(p->grsize); ++ if (!p->grbuffer) { ++ fr_perror("Failed allocating grnam buffer"); ++ free(p->pwbuffer); ++ free(p); ++ return NULL; ++ } ++ ++ ret = fr_thread_local_set(fr_pwgrnam_buffer, p); ++ if (ret != 0) { ++ fr_perror("Failed setting up TLS for pwnam buffer: %s", fr_syserror(ret)); ++ _fr_pwgrnam_free(p); ++ return NULL; ++ } ++ ++ return p; ++} ++ ++/** Wrapper around getpwnam, search user database for a name ++ * ++ * getpwnam is not threadsafe so provide a thread-safe variant that ++ * uses TLS. ++ * ++ * @param name then username to search for ++ * @return NULL on error or not found, else pointer to thread local struct passwd buffer ++ */ ++struct passwd *rad_getpwnam(const char *name) ++{ ++ struct pwgrnam_buffer *p; ++ struct passwd *result; ++ int ret; ++ ++ p = init_pwgrnam_buffer(); ++ if (!p) ++ return NULL; ++ ++ while ((ret = getpwnam_r(name, &p->pwd, p->pwbuffer, p->pwsize, &result)) == ERANGE) { ++ char *tmp = realloc(p->pwbuffer, p->pwsize * 2); ++ if (!tmp) { ++ fr_perror("Failed reallocating pwnam buffer"); ++ return NULL; ++ } ++ p->pwsize *= 2; ++ p->pwbuffer = tmp; ++ } ++ if (ret < 0 || result == NULL) ++ return NULL; ++ return result; ++} ++ ++/** Wrapper around getgrnam, search group database for a name ++ * ++ * getgrnam is not threadsafe so provide a thread-safe variant that ++ * uses TLS. ++ * ++ * @param name the name to search for ++ * @return NULL on error or not found, else pointer to thread local struct group buffer ++ */ ++struct group *rad_getgrnam(const char *name) ++{ ++ struct pwgrnam_buffer *p; ++ struct group *result; ++ int ret; ++ ++ p = init_pwgrnam_buffer(); ++ if (!p) ++ return NULL; ++ ++ while ((ret = getgrnam_r(name, &p->grp, p->grbuffer, p->grsize, &result)) == ERANGE) { ++ char *tmp = realloc(p->grbuffer, p->grsize * 2); ++ if (!tmp) { ++ fr_perror("Failed reallocating pwnam buffer"); ++ return NULL; ++ } ++ p->grsize *= 2; ++ p->grbuffer = tmp; ++ } ++ if (ret < 0 || result == NULL) ++ return NULL; ++ return result; ++} +diff --git a/src/modules/rlm_opendirectory/rlm_opendirectory.c b/src/modules/rlm_opendirectory/rlm_opendirectory.c +index a160b81..0cacadf 100644 +--- a/src/modules/rlm_opendirectory/rlm_opendirectory.c ++++ b/src/modules/rlm_opendirectory/rlm_opendirectory.c +@@ -352,7 +352,7 @@ static int od_authorize(UNUSED void *instance, REQUEST *request) + + /* resolve SACL */ + uuid_clear(guid_sacl); +- groupdata = getgrnam(kRadiusSACLName); ++ groupdata = rad_getgrnam(kRadiusSACLName); + if (groupdata != NULL) { + err = mbr_gid_to_uuid(groupdata->gr_gid, guid_sacl); + if (err != 0) { +@@ -377,7 +377,7 @@ static int od_authorize(UNUSED void *instance, REQUEST *request) + */ + if (uuid_parse(rad_client->community, guid_nasgroup) != 0) { + /* attempt to resolve the name */ +- groupdata = getgrnam(rad_client->community); ++ groupdata = rad_getgrnam(rad_client->community); + if (groupdata == NULL) { + radlog(L_AUTH, "rlm_opendirectory: The group \"%s\" does not exist on this system.", rad_client->community); + return RLM_MODULE_FAIL; +@@ -418,7 +418,7 @@ static int od_authorize(UNUSED void *instance, REQUEST *request) + name = (char *)request->username->vp_strvalue; + rad_assert(name != NULL); + +- userdata = getpwnam(name); ++ userdata = rad_getpwnam(name); + if (userdata != NULL) { + err = mbr_uid_to_uuid(userdata->pw_uid, uuid); + if (err != 0) +diff --git a/src/modules/rlm_unix/rlm_unix.c b/src/modules/rlm_unix/rlm_unix.c +index 9caab7a..661e3d7 100644 +--- a/src/modules/rlm_unix/rlm_unix.c ++++ b/src/modules/rlm_unix/rlm_unix.c +@@ -93,11 +93,11 @@ static int groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, + return -1; + } + +- pwd = getpwnam(req->username->vp_strvalue); ++ pwd = rad_getpwnam(req->username->vp_strvalue); + if (pwd == NULL) + return -1; + +- grp = getgrnam(check->vp_strvalue); ++ grp = rad_getgrnam(check->vp_strvalue); + if (grp == NULL) + return -1; + +@@ -211,7 +211,7 @@ static int unix_getpw(UNUSED void *instance, REQUEST *request, + return RLM_MODULE_USERLOCK; + } + #else /* OSFC2 */ +- if ((pwd = getpwnam(name)) == NULL) { ++ if ((pwd = rad_getpwnam(name)) == NULL) { + return RLM_MODULE_NOTFOUND; + } + encrypted_pass = pwd->pw_passwd; +-- +2.1.0 + diff --git a/main/freeradius/APKBUILD b/main/freeradius/APKBUILD index ad0c65a30c..dcb1c75713 100644 --- a/main/freeradius/APKBUILD +++ b/main/freeradius/APKBUILD @@ -2,7 +2,7 @@ # Maintainer: Leonardo Arena <rnalrd@alpinelinux.org> pkgname=freeradius pkgver=2.2.5 -pkgrel=1 +pkgrel=2 pkgdesc="RADIUS (Remote Authentication Dial-In User Service) server" url="http://freeradius.org/" arch="all" @@ -20,6 +20,7 @@ subpackages="$pkgname-doc $pkgname-dev $pkgname-dbg $pkgname-ldap $pkgname-lib $pkgname-unixodbc $pkgname-pam $pkgname-webif $pkgname-webif-doc" source="ftp://ftp.freeradius.org/pub/freeradius/$pkgname-server-$pkgver.tar.gz freeradius-fix-openssl-version-check.patch + 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch freeradius.confd freeradius.initd " @@ -244,13 +245,16 @@ webif() { md5sums="da77eb23b4c5e2f9fc55119025a91b61 freeradius-server-2.2.5.tar.gz fde9be89b76ed262db1198dfbeb237c6 freeradius-fix-openssl-version-check.patch +f28735060b63d88875783817bcd95586 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch fc6693f3df5a0694610110287a28568a freeradius.confd b3eefdfc466d80c241cd1bb11face405 freeradius.initd" sha256sums="8c4c2a0b600a8d85d2235589a5e80d4fefd1f52317e9daf8193731566fa9d012 freeradius-server-2.2.5.tar.gz c0f15867924ae73511cd009cb3c53cbd7eda298ff708a54f02d1900da5ebfc06 freeradius-fix-openssl-version-check.patch +115ae559fc5c8a638c5ebb510cb58478df66ceeb61a6768584e592e4a1fbc9d4 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch 2d5b3e1af1299373182f2c8021bdf45c29db5d82b0a077b965a16ded32cb6292 freeradius.confd 719bbe4a44df60e76f68d327f7ee70d4dfd6a95e51f9cb01f850cd4ed153f9de freeradius.initd" sha512sums="511599b4f4f5906441d0cda61946341f2226b9aae69b6f68b03a19898b6385499a8221933c191232d50f736cab93f0f6f271e4defe4552e7738cb21e2415f053 freeradius-server-2.2.5.tar.gz 77ec50125b38e05ee784b4cf724a31074844ea9c935c0d28aa51bd71e3e8a5399ba5194958f65f8c7f6c501b67ea6560da3869917f661178afbe602062a6fdc6 freeradius-fix-openssl-version-check.patch +4fb99b6a0f22cb844382139d448e24cc1b698452e30c1b0f06674a6fbd21463bcece2f2f4121618f9c7c57c8eb882eee35511b4dcea6e2a0904e27e5f2a6a679 0001-Use-threadsafe-wrapper-for-getpwnam-getgrnam.patch e248159c0a44f722e405c51c8015d9ad672e42ad0d38ca28f8a051ff911aa4d3e630b9bd4543e9d610940bc4ae50c022594e219ce341b36abe85c572acad418b freeradius.confd 57f12f06ef9112817204dec4ab2591bcd4baf3c8a033afadb2376e115911f76045c70b7a2c80b294a83dac4e05b1ff22335a3bcc9af1c0760682622ab2cdbd31 freeradius.initd" |