Line data Source code
1 : /* 2 : Unix SMB/Netbios implementation. 3 : 4 : Copyright (C) Ralph Boehme 2019 5 : Copyright (C) Stefan Metzmacher 2019 6 : 7 : This program is free software; you can redistribute it and/or modify 8 : it under the terms of the GNU General Public License as published by 9 : the Free Software Foundation; either version 3 of the License, or 10 : (at your option) any later version. 11 : 12 : This program is distributed in the hope that it will be useful, 13 : but WITHOUT ANY WARRANTY; without even the implied warranty of 14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 : GNU General Public License for more details. 16 : 17 : You should have received a copy of the GNU General Public License 18 : along with this program. If not, see <http://www.gnu.org/licenses/>. 19 : */ 20 : 21 : #include "includes.h" 22 : #include "system/filesys.h" 23 : #include "system/threads.h" 24 : #ifdef HAVE_UNSHARE_CLONE_FS 25 : #include <sched.h> 26 : #endif /* HAVE_UNSHARE_CLONE_FS */ 27 : 28 : static bool _per_thread_cwd_checked; 29 : static bool _per_thread_cwd_supported; 30 : #ifdef HAVE_UNSHARE_CLONE_FS 31 : static __thread bool _per_thread_cwd_disabled; 32 : static __thread bool _per_thread_cwd_activated; 33 : #endif /* HAVE_UNSHARE_CLONE_FS */ 34 : 35 : /* 36 : * This is the first function to be called! 37 : * Typically in the main() function before 38 : * any threads are created. 39 : * 40 : * This can be called multiple times 41 : * as the result is cached the first time. 42 : */ 43 12 : void per_thread_cwd_check(void) 44 : { 45 12 : if (_per_thread_cwd_checked) { 46 0 : return; 47 : } 48 : 49 : #ifdef HAVE_UNSHARE_CLONE_FS 50 : /* 51 : * While unshare(CLONE_FS) is available on 52 : * Linux for ages, unshare() is also 53 : * used to implement containers with various 54 : * per container namespaces. 55 : * 56 : * It's possible that the whole unshare() 57 : * is blocked in order to disallow nested 58 : * containers. 59 : * 60 : * That's why we sadly need a runtime check 61 : * for this. 62 : */ 63 : { 64 0 : int res; 65 : 66 12 : res = unshare(CLONE_FS); 67 12 : if (res == 0) { 68 12 : _per_thread_cwd_supported = true; 69 : } 70 : } 71 : 72 : /* 73 : * We're in the main thread, so we should disallow 74 : * per_thread_cwd_activate() here. 75 : */ 76 12 : _per_thread_cwd_disabled = true; 77 : #endif /* HAVE_UNSHARE_CLONE_FS */ 78 : 79 12 : _per_thread_cwd_checked = true; 80 : } 81 : 82 : /* 83 : * In order to use per_thread_cwd_supported() 84 : * per_thread_cwd_check() needs to be called first! 85 : * Otherwise an assert will be triggered! 86 : */ 87 10111 : bool per_thread_cwd_supported(void) 88 : { 89 10111 : SMB_ASSERT(_per_thread_cwd_checked); 90 10111 : return _per_thread_cwd_supported; 91 : } 92 : 93 : /* 94 : * In order to use per_thread_cwd_disable() 95 : * should be called after any fork() in order 96 : * to mark the main thread of the process, 97 : * which should disallow per_thread_cwd_activate(). 98 : * 99 : * This can be called without calling 100 : * per_thread_cwd_check() first. 101 : * 102 : * And it can't be called after calling 103 : * per_thread_cwd_activate()! 104 : * Otherwise an assert will be triggered! 105 : * 106 : * This can be called multiple times 107 : * as the result is cached the first time. 108 : */ 109 31807 : void per_thread_cwd_disable(void) 110 : { 111 : #ifdef HAVE_UNSHARE_CLONE_FS 112 31807 : SMB_ASSERT(!_per_thread_cwd_activated); 113 31807 : if (_per_thread_cwd_disabled) { 114 30723 : return; 115 : } 116 242 : _per_thread_cwd_disabled = true; 117 : #endif /* HAVE_UNSHARE_CLONE_FS */ 118 : } 119 : 120 : /* 121 : * In order to use per_thread_cwd_activate() 122 : * per_thread_cwd_supported() needs to be checked first! 123 : * Otherwise an assert will be triggered! 124 : * 125 : * This MUST only be called within helper threads! 126 : * 127 : * That means it can't be called after calling 128 : * per_thread_cwd_disable()! 129 : * Otherwise an assert will be triggered! 130 : * 131 : * This can be called multiple times 132 : * as the result is cached the first time. 133 : */ 134 10077 : void per_thread_cwd_activate(void) 135 : { 136 10077 : SMB_ASSERT(_per_thread_cwd_checked); 137 10077 : SMB_ASSERT(_per_thread_cwd_supported); 138 : 139 : #ifdef HAVE_UNSHARE_CLONE_FS 140 10077 : if (_per_thread_cwd_activated) { 141 10058 : return; 142 : } 143 : 144 19 : SMB_ASSERT(!_per_thread_cwd_disabled); 145 : 146 : { 147 0 : int ret; 148 19 : ret = unshare(CLONE_FS); 149 19 : SMB_ASSERT(ret == 0); 150 : } 151 : 152 19 : _per_thread_cwd_activated = true; 153 : #else /* not HAVE_UNSHARE_CLONE_FS */ 154 : smb_panic(__location__); 155 : #endif /* not HAVE_UNSHARE_CLONE_FS */ 156 : }