From 1be958e68279a95633d948fe901c951c0f323f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Schieli?= Date: Sat, 18 Mar 2017 11:32:01 +0100 Subject: [PATCH 1/5] Helper functions needed to secure the promiscuous mode. The jack_group2gid() function does a thread-safe lookup of a unix gid from a unix group name. The jack_promiscuous_perms() function adjusts the permissions of a shared resource (socket, semaphore, shm segment, ...) referenced by a fd and/or a path so it can be used by any member of the provided unix group. By using those functions it will be possible to enable a secure promiscuous mode. 'Secure' meaning here that one is not forced to launch every clients with a (way) too permissive 0000 umask. --- common/promiscuous.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ common/promiscuous.h | 39 ++++++++++++++++++ common/wscript | 3 ++ 3 files changed, 137 insertions(+) create mode 100644 common/promiscuous.c create mode 100644 common/promiscuous.h diff --git a/common/promiscuous.c b/common/promiscuous.c new file mode 100644 index 00000000..aa6850c1 --- /dev/null +++ b/common/promiscuous.c @@ -0,0 +1,95 @@ +/* + Copyright (C) 2014-2017 Cédric Schieli + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#endif +#include "JackError.h" +#endif + + +int +jack_group2gid(const char* group) +{ +#ifdef WIN32 + return -1; +#else + size_t buflen; + char *buf; + int ret; + struct group grp; + struct group *result; + + if (!group || !*group) + return -1; + + ret = strtol(group, &buf, 10); + if (!*buf) + return ret; + +/* MacOSX only defines _SC_GETGR_R_SIZE_MAX starting from 10.4 */ +#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 + buflen = 4096; +#else + buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (buflen == -1) + buflen = 4096; +#endif + buf = (char*)malloc(buflen); + + while (buf && ((ret = getgrnam_r(group, &grp, buf, buflen, &result)) == ERANGE)) { + buflen *= 2; + buf = (char*)realloc(buf, buflen); + } + if (!buf) + return -1; + free(buf); + if (ret || !result) + return -1; + return grp.gr_gid; +#endif +} + +#ifndef WIN32 +int +jack_promiscuous_perms(int fd, const char* path, gid_t gid) +{ + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + if (gid >= 0) { + if (((fd < 0) ? chown(path, -1, gid) : fchown(fd, -1, gid)) < 0) { + jack_log("Cannot chgrp %s: %s. Falling back to permissive perms.", path, strerror(errno)); + } else { + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + } + } + if (((fd < 0) ? chmod(path, mode) : fchmod(fd, mode)) < 0) { + jack_log("Cannot chmod %s: %s. Falling back to default (umask) perms.", path, strerror(errno)); + return -1; + } + return 0; +} +#endif diff --git a/common/promiscuous.h b/common/promiscuous.h new file mode 100644 index 00000000..437fc03c --- /dev/null +++ b/common/promiscuous.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2014-2017 Cédric Schieli + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#ifndef __jack_gid_h__ +#define __jack_gid_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +int jack_group2gid (const char *group); /*!< Lookup gid for a UNIX group in a thread-safe way */ +#ifndef WIN32 +int jack_promiscuous_perms (int fd, const char *path, gid_t gid); /*!< Set promiscuous permissions on object referenced by fd and/or path */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __jack_gid_h__ */ + + diff --git a/common/wscript b/common/wscript index 860cbace..cbdaacc2 100644 --- a/common/wscript +++ b/common/wscript @@ -82,6 +82,7 @@ def build(bld): common_libsources += [ 'JackDebugClient.cpp', 'timestamps.c', + 'promiscuous.c', '../posix/JackPosixThread.cpp', '../posix/JackPosixProcessSync.cpp', '../posix/JackPosixMutex.cpp', @@ -97,6 +98,7 @@ def build(bld): common_libsources += [ 'JackDebugClient.cpp', 'timestamps.c', + 'promiscuous.c', '../posix/JackPosixThread.cpp', '../posix/JackFifo.cpp', '../posix/JackPosixProcessSync.cpp', @@ -111,6 +113,7 @@ def build(bld): common_libsources += [ 'JackDebugClient.cpp', 'timestamps.c', + 'promiscuous.c', '../posix/JackPosixProcessSync.cpp', '../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', From 325b8ff80f8275376f6cca26bb636ce6bbd6b60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Schieli?= Date: Sat, 18 Mar 2017 11:32:36 +0100 Subject: [PATCH 2/5] Secure promiscuous mode for shared memory segments Adjusts the permissions of shared memory segments when promiscuous mode is enabled. --- common/shm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/shm.c b/common/shm.c index 75075743..067ef3fe 100644 --- a/common/shm.c +++ b/common/shm.c @@ -52,6 +52,7 @@ #include #include #include +#include "promiscuous.h" #endif @@ -837,6 +838,7 @@ jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) int shm_fd; int rc = -1; char name[SHM_NAME_MAX+1]; + const char* promiscuous; if (jack_shm_lock_registry () < 0) { jack_error ("jack_shm_lock_registry fails..."); @@ -877,6 +879,10 @@ jack_shmalloc (const char *shm_name, jack_shmsize_t size, jack_shm_info_t* si) goto unlock; } + promiscuous = getenv("JACK_PROMISCUOUS_SERVER"); + if ((promiscuous != NULL) && (jack_promiscuous_perms(shm_fd, name, jack_group2gid(promiscuous)) < 0)) + goto unlock; + close (shm_fd); registry->size = size; strncpy (registry->id, name, sizeof (registry->id)); From bb7faafd1c8a9189881895269291d36e6a0e5193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Schieli?= Date: Sat, 18 Mar 2017 11:33:06 +0100 Subject: [PATCH 3/5] Secure promiscuous mode for unix sockets Adjusts the permissions of unix sockets when promiscuous mode is enabled. --- posix/JackSocket.cpp | 28 +++++++++++++++++++++++----- posix/JackSocket.h | 10 ++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/posix/JackSocket.cpp b/posix/JackSocket.cpp index e8b528d9..73f1fc44 100644 --- a/posix/JackSocket.cpp +++ b/posix/JackSocket.cpp @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackConstants.h" #include "JackTools.h" #include "JackError.h" +#include "promiscuous.h" #include #include #include @@ -29,18 +30,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. namespace Jack { -static void BuildName(const char* client_name, char* res, const char* dir, int which, int size) +static void BuildName(const char* client_name, char* res, const char* dir, int which, int size, bool promiscuous) { char ext_client_name[SYNC_MAX_NAME_SIZE + 1]; JackTools::RewriteName(client_name, ext_client_name); - if (getenv("JACK_PROMISCUOUS_SERVER")) { + if (promiscuous) { snprintf(res, size, "%s/jack_%s_%d", dir, ext_client_name, which); } else { snprintf(res, size, "%s/jack_%s_%d_%d", dir, ext_client_name, JackTools::GetUID(), which); } } -JackClientSocket::JackClientSocket(int socket): JackClientRequestInterface(), fSocket(socket),fTimeOut(0) +JackClientSocket::JackClientSocket(): JackClientRequestInterface(), fSocket(-1), fTimeOut(0) +{ + const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER"); + fPromiscuous = (promiscuous != NULL); + fPromiscuousGid = jack_group2gid(promiscuous); +} + +JackClientSocket::JackClientSocket(int socket): JackClientRequestInterface(), fSocket(socket),fTimeOut(0), fPromiscuous(false), fPromiscuousGid(-1) {} #if defined(__sun__) || defined(sun) @@ -123,7 +131,7 @@ int JackClientSocket::Connect(const char* dir, const char* name, int which) // A } addr.sun_family = AF_UNIX; - BuildName(name, addr.sun_path, dir, which, sizeof(addr.sun_path)); + BuildName(name, addr.sun_path, dir, which, sizeof(addr.sun_path), fPromiscuous); jack_log("JackClientSocket::Connect : addr.sun_path %s", addr.sun_path); if (connect(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { @@ -247,6 +255,13 @@ int JackClientSocket::Write(void* data, int len) } } +JackServerSocket::JackServerSocket(): fSocket( -1) +{ + const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER"); + fPromiscuous = (promiscuous != NULL); + fPromiscuousGid = jack_group2gid(promiscuous); +} + int JackServerSocket::Bind(const char* dir, const char* name, int which) // A revoir : utilisation de "which" { struct sockaddr_un addr; @@ -258,7 +273,7 @@ int JackServerSocket::Bind(const char* dir, const char* name, int which) // A re addr.sun_family = AF_UNIX; // Socket name has to be kept in fName to be "unlinked". - BuildName(name, fName, dir, which, sizeof(addr.sun_path)); + BuildName(name, fName, dir, which, sizeof(addr.sun_path), fPromiscuous); strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1); jack_log("JackServerSocket::Bind : addr.sun_path %s", addr.sun_path); @@ -274,6 +289,9 @@ int JackServerSocket::Bind(const char* dir, const char* name, int which) // A re goto error; } + if (fPromiscuous && (jack_promiscuous_perms(-1, fName, fPromiscuousGid) < 0)) + goto error; + return 0; error: diff --git a/posix/JackSocket.h b/posix/JackSocket.h index 8568025b..5f0501a1 100644 --- a/posix/JackSocket.h +++ b/posix/JackSocket.h @@ -45,11 +45,12 @@ class JackClientSocket : public detail::JackClientRequestInterface int fSocket; int fTimeOut; + bool fPromiscuous; + int fPromiscuousGid; public: - JackClientSocket():JackClientRequestInterface(), fSocket(-1), fTimeOut(0) - {} + JackClientSocket(); JackClientSocket(int socket); int Connect(const char* dir, const char* name, int which); @@ -80,11 +81,12 @@ class JackServerSocket int fSocket; char fName[SOCKET_MAX_NAME_SIZE]; + bool fPromiscuous; + int fPromiscuousGid; public: - JackServerSocket(): fSocket( -1) - {} + JackServerSocket(); ~JackServerSocket() {} From 5d89eba8c7d2010100e372a286ff24fb0aadba6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Schieli?= Date: Sat, 18 Mar 2017 11:33:49 +0100 Subject: [PATCH 4/5] Secure promiscuous mode for linux futexes Adjusts the permissions of linux futexes when promiscuous mode is enabled. --- linux/JackLinuxFutex.cpp | 17 ++++++++++++++++- linux/JackLinuxFutex.h | 5 +++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/linux/JackLinuxFutex.cpp b/linux/JackLinuxFutex.cpp index 6e897bc8..b724f191 100644 --- a/linux/JackLinuxFutex.cpp +++ b/linux/JackLinuxFutex.cpp @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackTools.h" #include "JackConstants.h" #include "JackError.h" +#include "promiscuous.h" #include #include #include @@ -31,11 +32,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. namespace Jack { +JackLinuxFutex::JackLinuxFutex() : JackSynchro(), fSharedMem(-1), fFutex(NULL), fPrivate(false) +{ + const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER"); + fPromiscuous = (promiscuous != NULL); + fPromiscuousGid = jack_group2gid(promiscuous); +} + void JackLinuxFutex::BuildName(const char* client_name, const char* server_name, char* res, int size) { char ext_client_name[SYNC_MAX_NAME_SIZE + 1]; JackTools::RewriteName(client_name, ext_client_name); - if (getenv("JACK_PROMISCUOUS_SERVER")) { + if (fPromiscuous) { snprintf(res, size, "jack_sem.%s_%s", server_name, ext_client_name); } else { snprintf(res, size, "jack_sem.%d_%s_%s", JackTools::GetUID(), server_name, ext_client_name); @@ -132,6 +140,13 @@ bool JackLinuxFutex::Allocate(const char* name, const char* server_name, int val ftruncate(fSharedMem, sizeof(FutexData)); + if (fPromiscuous && (jack_promiscuous_perms(fSharedMem, fName, fPromiscuousGid) < 0)) { + close(fSharedMem); + fSharedMem = -1; + shm_unlink(fName); + return false; + } + if ((fFutex = (FutexData*)mmap(NULL, sizeof(FutexData), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fSharedMem, 0)) == NULL) { jack_error("Allocate: can't check in named futex name = %s err = %s", fName, strerror(errno)); close(fSharedMem); diff --git a/linux/JackLinuxFutex.h b/linux/JackLinuxFutex.h index 5c8a7006..559f1e63 100644 --- a/linux/JackLinuxFutex.h +++ b/linux/JackLinuxFutex.h @@ -53,6 +53,8 @@ class SERVER_EXPORT JackLinuxFutex : public detail::JackSynchro int fSharedMem; FutexData* fFutex; bool fPrivate; + bool fPromiscuous; + int fPromiscuousGid; protected: @@ -60,8 +62,7 @@ class SERVER_EXPORT JackLinuxFutex : public detail::JackSynchro public: - JackLinuxFutex():JackSynchro(), fSharedMem(-1), fFutex(NULL), fPrivate(false) - {} + JackLinuxFutex(); bool Signal(); bool SignalAll(); From d4f925c2eafa050f2cda5b682f077b892d3b3de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Schieli?= Date: Sat, 18 Mar 2017 11:33:30 +0100 Subject: [PATCH 5/5] Secure promiscuous mode for posix semaphores Adjusts the permissions of posix semaphores when promiscuous mode is enabled. Note that changing permissions of semaphores is only supported on linux by using the /dev/shm filesystem. As of now, linux does not use posix semaphores anymore so this code is currently unsed. --- posix/JackPosixSemaphore.cpp | 22 +++++++++++++++++++++- posix/JackPosixSemaphore.h | 7 +++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/posix/JackPosixSemaphore.cpp b/posix/JackPosixSemaphore.cpp index 9e511647..1f4df7a4 100644 --- a/posix/JackPosixSemaphore.cpp +++ b/posix/JackPosixSemaphore.cpp @@ -24,10 +24,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#ifdef __linux__ +#include "promiscuous.h" +#endif namespace Jack { +JackPosixSemaphore::JackPosixSemaphore() : JackSynchro(), fSemaphore(NULL) +{ + const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER"); + fPromiscuous = (promiscuous != NULL); +#ifdef __linux__ + fPromiscuousGid = jack_group2gid(promiscuous); +#endif +} + void JackPosixSemaphore::BuildName(const char* client_name, const char* server_name, char* res, int size) { char ext_client_name[SYNC_MAX_NAME_SIZE + 1]; @@ -35,7 +47,7 @@ void JackPosixSemaphore::BuildName(const char* client_name, const char* server_n #if __APPLE__ // POSIX semaphore names are limited to 32 characters... snprintf(res, 32, "js_%s", ext_client_name); #else - if (getenv("JACK_PROMISCUOUS_SERVER")) { + if (fPromiscuous) { snprintf(res, size, "jack_sem.%s_%s", server_name, ext_client_name); } else { snprintf(res, size, "jack_sem.%d_%s_%s", JackTools::GetUID(), server_name, ext_client_name); @@ -147,6 +159,14 @@ bool JackPosixSemaphore::Allocate(const char* name, const char* server_name, int jack_error("Allocate: can't check in named semaphore name = %s err = %s", fName, strerror(errno)); return false; } else { +#ifdef __linux__ + if (fPromiscuous) { + char sempath[SYNC_MAX_NAME_SIZE+13]; + snprintf(sempath, sizeof(sempath), "/dev/shm/sem.%s", fName); + if (jack_promiscuous_perms(-1, sempath, fPromiscuousGid) < 0) + return false; + } +#endif return true; } } diff --git a/posix/JackPosixSemaphore.h b/posix/JackPosixSemaphore.h index 94f4d60f..bc5e0cea 100644 --- a/posix/JackPosixSemaphore.h +++ b/posix/JackPosixSemaphore.h @@ -39,6 +39,10 @@ class SERVER_EXPORT JackPosixSemaphore : public detail::JackSynchro private: sem_t* fSemaphore; + bool fPromiscuous; +#ifdef __linux__ + int fPromiscuousGid; +#endif protected: @@ -46,8 +50,7 @@ class SERVER_EXPORT JackPosixSemaphore : public detail::JackSynchro public: - JackPosixSemaphore():JackSynchro(), fSemaphore(NULL) - {} + JackPosixSemaphore(); bool Signal(); bool SignalAll();