Skip to content

Commit c8ba796

Browse files
fishilicojwcart2
authored andcommitted
libselinux: do not return the cached prev_current value when using getpidcon()
libselinux implements a cache mechanism for get*con() functions, such that when a thread calls setcon(...) then getcon(...), the context is directly returned. Unfortunately, getpidcon(pid, &context) uses the same cached variable, so when a program uses setcon("something"), all later calls to getpidcon(pid, ...) returns "something". This is a bug. Here is a program which illustrates this bug: #include <stdio.h> #include <selinux/selinux.h> int main() { char *context = ""; if (getpidcon(1, &context) < 0) { perror("getpidcon(1)"); } printf("getpidcon(1) = %s\n", context); if (getcon(&context) < 0) { perror("getcon()"); } printf("getcon() = %s\n", context); if (setcon(context) < 0) { perror("setcon()"); } if (getpidcon(1, &context) < 0) { perror("getpidcon(1)"); } printf("getpidcon(1) = %s\n", context); return 0; } On an Arch Linux system using unconfined user, this program displays: getpidcon(1) = system_u:system_r:init_t getcon() = unconfined_u:unconfined_r:unconfined_t getpidcon(1) = unconfined_u:unconfined_r:unconfined_t With this commit, this program displays: getpidcon(1) = system_u:system_r:init_t getcon() = unconfined_u:unconfined_r:unconfined_t getpidcon(1) = system_u:system_r:init_t This bug was present in the first commit of https://github.com/SELinuxProject/selinux git history. It was reported in https://lore.kernel.org/selinux/20220121084012.GS7643@suse.com/ and a patch to fix it was sent in https://patchwork.kernel.org/project/selinux/patch/20220127130741.31940-1-jsegitz@suse.de/ without a clear explanation. This patch added pid checks, which made sense but were difficult to read. Instead, it is possible to change the way the functions are called so that they directly know which cache variable to use. Moreover, as the code is not clear at all (I spent too much time trying to understand what the switch did and what the thread-local variable contained), this commit also reworks libselinux/src/procattr.c to: - not use hard-to-understand switch/case constructions on strings (they are replaced by a new argument filled by macros) - remove getpidattr_def macro (it was only used once, for pidcon, and the code is clearer with one less macro) - remove the pid parameter of setprocattrcon() and setprocattrcon_raw() (it is always zero) Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org> Cc: Johannes Segitz <jsegitz@suse.de>
1 parent de28525 commit c8ba796

File tree

1 file changed

+50
-97
lines changed

1 file changed

+50
-97
lines changed

libselinux/src/procattr.c

Lines changed: 50 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111

1212
#define UNSET (char *) -1
1313

14+
/* Cached values so that when a thread calls set*con() then gen*con(), the value
15+
* which was set is directly returned.
16+
*/
1417
static __thread char *prev_current = UNSET;
15-
static __thread char * prev_exec = UNSET;
16-
static __thread char * prev_fscreate = UNSET;
17-
static __thread char * prev_keycreate = UNSET;
18-
static __thread char * prev_sockcreate = UNSET;
18+
static __thread char *prev_exec = UNSET;
19+
static __thread char *prev_fscreate = UNSET;
20+
static __thread char *prev_keycreate = UNSET;
21+
static __thread char *prev_sockcreate = UNSET;
1922

2023
static pthread_once_t once = PTHREAD_ONCE_INIT;
2124
static pthread_key_t destructor_key;
@@ -111,43 +114,18 @@ static int openattr(pid_t pid, const char *attr, int flags)
111114
return fd;
112115
}
113116

114-
static int getprocattrcon_raw(char ** context,
115-
pid_t pid, const char *attr)
117+
static int getprocattrcon_raw(char **context, pid_t pid, const char *attr,
118+
const char *prev_context)
116119
{
117120
char *buf;
118121
size_t size;
119122
int fd;
120123
ssize_t ret;
121124
int errno_hold;
122-
char * prev_context;
123125

124126
__selinux_once(once, init_procattr);
125127
init_thread_destructor();
126128

127-
switch (attr[0]) {
128-
case 'c':
129-
prev_context = prev_current;
130-
break;
131-
case 'e':
132-
prev_context = prev_exec;
133-
break;
134-
case 'f':
135-
prev_context = prev_fscreate;
136-
break;
137-
case 'k':
138-
prev_context = prev_keycreate;
139-
break;
140-
case 's':
141-
prev_context = prev_sockcreate;
142-
break;
143-
case 'p':
144-
prev_context = NULL;
145-
break;
146-
default:
147-
errno = ENOENT;
148-
return -1;
149-
}
150-
151129
if (prev_context && prev_context != UNSET) {
152130
*context = strdup(prev_context);
153131
if (!(*context)) {
@@ -194,13 +172,13 @@ static int getprocattrcon_raw(char ** context,
194172
return ret;
195173
}
196174

197-
static int getprocattrcon(char ** context,
198-
pid_t pid, const char *attr)
175+
static int getprocattrcon(char **context, pid_t pid, const char *attr,
176+
const char *prev_context)
199177
{
200178
int ret;
201179
char * rcontext;
202180

203-
ret = getprocattrcon_raw(&rcontext, pid, attr);
181+
ret = getprocattrcon_raw(&rcontext, pid, attr, prev_context);
204182

205183
if (!ret) {
206184
ret = selinux_raw_to_trans_context(rcontext, context);
@@ -210,45 +188,24 @@ static int getprocattrcon(char ** context,
210188
return ret;
211189
}
212190

213-
static int setprocattrcon_raw(const char * context,
214-
pid_t pid, const char *attr)
191+
static int setprocattrcon_raw(const char *context, const char *attr,
192+
char **prev_context)
215193
{
216194
int fd;
217195
ssize_t ret;
218196
int errno_hold;
219-
char **prev_context, *context2 = NULL;
197+
char *context2 = NULL;
220198

221199
__selinux_once(once, init_procattr);
222200
init_thread_destructor();
223201

224-
switch (attr[0]) {
225-
case 'c':
226-
prev_context = &prev_current;
227-
break;
228-
case 'e':
229-
prev_context = &prev_exec;
230-
break;
231-
case 'f':
232-
prev_context = &prev_fscreate;
233-
break;
234-
case 'k':
235-
prev_context = &prev_keycreate;
236-
break;
237-
case 's':
238-
prev_context = &prev_sockcreate;
239-
break;
240-
default:
241-
errno = ENOENT;
242-
return -1;
243-
}
244-
245202
if (!context && !*prev_context)
246203
return 0;
247204
if (context && *prev_context && *prev_context != UNSET
248205
&& !strcmp(context, *prev_context))
249206
return 0;
250207

251-
fd = openattr(pid, attr, O_RDWR | O_CLOEXEC);
208+
fd = openattr(0, attr, O_RDWR | O_CLOEXEC);
252209
if (fd < 0)
253210
return -1;
254211
if (context) {
@@ -279,71 +236,67 @@ static int setprocattrcon_raw(const char * context,
279236
}
280237
}
281238

282-
static int setprocattrcon(const char * context,
283-
pid_t pid, const char *attr)
239+
static int setprocattrcon(const char *context, const char *attr,
240+
char **prev_context)
284241
{
285242
int ret;
286243
char * rcontext;
287244

288245
if (selinux_trans_to_raw_context(context, &rcontext))
289246
return -1;
290247

291-
ret = setprocattrcon_raw(rcontext, pid, attr);
248+
ret = setprocattrcon_raw(rcontext, attr, prev_context);
292249

293250
freecon(rcontext);
294251

295252
return ret;
296253
}
297254

298-
#define getselfattr_def(fn, attr) \
255+
#define getselfattr_def(fn, attr, prev_context) \
299256
int get##fn##_raw(char **c) \
300257
{ \
301-
return getprocattrcon_raw(c, 0, #attr); \
258+
return getprocattrcon_raw(c, 0, attr, prev_context); \
302259
} \
303260
int get##fn(char **c) \
304261
{ \
305-
return getprocattrcon(c, 0, #attr); \
262+
return getprocattrcon(c, 0, attr, prev_context); \
306263
}
307264

308-
#define setselfattr_def(fn, attr) \
265+
#define setselfattr_def(fn, attr, prev_context) \
309266
int set##fn##_raw(const char * c) \
310267
{ \
311-
return setprocattrcon_raw(c, 0, #attr); \
268+
return setprocattrcon_raw(c, attr, &prev_context); \
312269
} \
313270
int set##fn(const char * c) \
314271
{ \
315-
return setprocattrcon(c, 0, #attr); \
272+
return setprocattrcon(c, attr, &prev_context); \
316273
}
317274

318-
#define all_selfattr_def(fn, attr) \
319-
getselfattr_def(fn, attr) \
320-
setselfattr_def(fn, attr)
275+
#define all_selfattr_def(fn, attr, prev_context) \
276+
getselfattr_def(fn, attr, prev_context) \
277+
setselfattr_def(fn, attr, prev_context)
321278

322-
#define getpidattr_def(fn, attr) \
323-
int get##fn##_raw(pid_t pid, char **c) \
324-
{ \
325-
if (pid <= 0) { \
326-
errno = EINVAL; \
327-
return -1; \
328-
} else { \
329-
return getprocattrcon_raw(c, pid, #attr); \
330-
} \
331-
} \
332-
int get##fn(pid_t pid, char **c) \
333-
{ \
334-
if (pid <= 0) { \
335-
errno = EINVAL; \
336-
return -1; \
337-
} else { \
338-
return getprocattrcon(c, pid, #attr); \
339-
} \
340-
}
279+
all_selfattr_def(con, "current", prev_current)
280+
getselfattr_def(prevcon, "prev", NULL)
281+
all_selfattr_def(execcon, "exec", prev_exec)
282+
all_selfattr_def(fscreatecon, "fscreate", prev_fscreate)
283+
all_selfattr_def(sockcreatecon, "sockcreate", prev_sockcreate)
284+
all_selfattr_def(keycreatecon, "keycreate", prev_keycreate)
341285

342-
all_selfattr_def(con, current)
343-
getpidattr_def(pidcon, current)
344-
getselfattr_def(prevcon, prev)
345-
all_selfattr_def(execcon, exec)
346-
all_selfattr_def(fscreatecon, fscreate)
347-
all_selfattr_def(sockcreatecon, sockcreate)
348-
all_selfattr_def(keycreatecon, keycreate)
286+
int getpidcon_raw(pid_t pid, char **c)
287+
{
288+
if (pid <= 0) {
289+
errno = EINVAL;
290+
return -1;
291+
}
292+
return getprocattrcon_raw(c, pid, "current", NULL);
293+
}
349294

295+
int getpidcon(pid_t pid, char **c)
296+
{
297+
if (pid <= 0) {
298+
errno = EINVAL;
299+
return -1;
300+
}
301+
return getprocattrcon(c, pid, "current", NULL);
302+
}

0 commit comments

Comments
 (0)