2019-01-11 14:47:40 +03:00
/*
Unix SMB / Netbios implementation .
Copyright ( C ) Ralph Boehme 2019
Copyright ( C ) Stefan Metzmacher 2019
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "system/filesys.h"
# include "system/threads.h"
# ifdef HAVE_UNSHARE_CLONE_FS
# include <sched.h>
# endif /* HAVE_UNSHARE_CLONE_FS */
static bool _per_thread_cwd_checked ;
static bool _per_thread_cwd_supported ;
# ifdef HAVE_UNSHARE_CLONE_FS
static __thread bool _per_thread_cwd_disabled ;
static __thread bool _per_thread_cwd_activated ;
# endif /* HAVE_UNSHARE_CLONE_FS */
/*
* This is the first function to be called !
* Typically in the main ( ) function before
* any threads are created .
*
* This can be called multiple times
* as the result is cached the first time .
*/
void per_thread_cwd_check ( void )
{
if ( _per_thread_cwd_checked ) {
return ;
}
# ifdef HAVE_UNSHARE_CLONE_FS
/*
* While unshare ( CLONE_FS ) is available on
* Linux for ages , unshare ( ) is also
* used to implement containers with various
* per container namespaces .
*
* It ' s possible that the whole unshare ( )
2023-07-05 12:16:18 +03:00
* is blocked in order to disallow nested
2019-01-11 14:47:40 +03:00
* containers .
*
* That ' s why we sadly need a runtime check
* for this .
*/
{
int res ;
res = unshare ( CLONE_FS ) ;
if ( res = = 0 ) {
_per_thread_cwd_supported = true ;
}
}
/*
* We ' re in the main thread , so we should disallow
* per_thread_cwd_activate ( ) here .
*/
_per_thread_cwd_disabled = true ;
# endif /* HAVE_UNSHARE_CLONE_FS */
_per_thread_cwd_checked = true ;
}
/*
* In order to use per_thread_cwd_supported ( )
* per_thread_cwd_check ( ) needs to be called first !
* Otherwise an assert will be triggered !
*/
bool per_thread_cwd_supported ( void )
{
SMB_ASSERT ( _per_thread_cwd_checked ) ;
return _per_thread_cwd_supported ;
}
/*
* In order to use per_thread_cwd_disable ( )
* should be called after any fork ( ) in order
* to mark the main thread of the process ,
* which should disallow per_thread_cwd_activate ( ) .
*
* This can be called without calling
* per_thread_cwd_check ( ) first .
*
* And it can ' t be called after calling
* per_thread_cwd_activate ( ) !
* Otherwise an assert will be triggered !
*
* This can be called multiple times
* as the result is cached the first time .
*/
void per_thread_cwd_disable ( void )
{
# ifdef HAVE_UNSHARE_CLONE_FS
SMB_ASSERT ( ! _per_thread_cwd_activated ) ;
if ( _per_thread_cwd_disabled ) {
return ;
}
_per_thread_cwd_disabled = true ;
# endif /* HAVE_UNSHARE_CLONE_FS */
}
/*
* In order to use per_thread_cwd_activate ( )
* per_thread_cwd_supported ( ) needs to be checked first !
* Otherwise an assert will be triggered !
*
* This MUST only be called within helper threads !
*
* That means it can ' t be called after calling
* per_thread_cwd_disable ( ) !
* Otherwise an assert will be triggered !
*
* This can be called multiple times
* as the result is cached the first time .
*/
void per_thread_cwd_activate ( void )
{
SMB_ASSERT ( _per_thread_cwd_checked ) ;
SMB_ASSERT ( _per_thread_cwd_supported ) ;
# ifdef HAVE_UNSHARE_CLONE_FS
if ( _per_thread_cwd_activated ) {
return ;
}
SMB_ASSERT ( ! _per_thread_cwd_disabled ) ;
{
int ret ;
ret = unshare ( CLONE_FS ) ;
SMB_ASSERT ( ret = = 0 ) ;
}
_per_thread_cwd_activated = true ;
# else /* not HAVE_UNSHARE_CLONE_FS */
smb_panic ( __location__ ) ;
# endif /* not HAVE_UNSHARE_CLONE_FS */
}