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 44 : void per_thread_cwd_check(void)
44 : {
45 44 : 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 neested
58 : * containers.
59 : *
60 : * That's why we sadly need a runtime check
61 : * for this.
62 : */
63 : {
64 : int res;
65 :
66 44 : res = unshare(CLONE_FS);
67 44 : if (res == 0) {
68 44 : _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 44 : _per_thread_cwd_disabled = true;
77 : #endif /* HAVE_UNSHARE_CLONE_FS */
78 :
79 44 : _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 0 : bool per_thread_cwd_supported(void)
88 : {
89 0 : SMB_ASSERT(_per_thread_cwd_checked);
90 0 : 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 5436 : void per_thread_cwd_disable(void)
110 : {
111 : #ifdef HAVE_UNSHARE_CLONE_FS
112 5436 : SMB_ASSERT(!_per_thread_cwd_activated);
113 5436 : if (_per_thread_cwd_disabled) {
114 5316 : return;
115 : }
116 120 : _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 0 : void per_thread_cwd_activate(void)
135 : {
136 0 : SMB_ASSERT(_per_thread_cwd_checked);
137 0 : SMB_ASSERT(_per_thread_cwd_supported);
138 :
139 : #ifdef HAVE_UNSHARE_CLONE_FS
140 0 : if (_per_thread_cwd_activated) {
141 0 : return;
142 : }
143 :
144 0 : SMB_ASSERT(!_per_thread_cwd_disabled);
145 :
146 : {
147 : int ret;
148 0 : ret = unshare(CLONE_FS);
149 0 : SMB_ASSERT(ret == 0);
150 : }
151 :
152 0 : _per_thread_cwd_activated = true;
153 : #else /* not HAVE_UNSHARE_CLONE_FS */
154 : smb_panic(__location__);
155 : #endif /* not HAVE_UNSHARE_CLONE_FS */
156 : }
|