libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon
Operating on a file descriptor avoids TOCTOU issues and one opened via
O_PATH avoids the requirement of having read access to the file. Since
Linux does not natively support file descriptors opened via O_PATH in
fgetxattr(2) and at least glibc and musl does not emulate O_PATH support
in their implementations, fgetfilecon(3) and fsetfilecon(3) also do not
currently support file descriptors opened with O_PATH.
Inspired by CVE-2013-4392: https://github.com/systemd/systemd/pull/8583
Implementation adapted from: 2825f10b7f
%5E%21/
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
parent
9df28c241a
commit
a782abf226
4 changed files with 53 additions and 6 deletions
|
@ -33,7 +33,9 @@ is identical to
|
|||
.BR getfilecon (),
|
||||
only the open file pointed to by filedes (as returned by
|
||||
.BR open (2))
|
||||
is interrogated in place of path.
|
||||
is interrogated in place of path. Since libselinux 3.4 a file opened via
|
||||
.I O_PATH
|
||||
is supported.
|
||||
|
||||
.BR getfilecon_raw (),
|
||||
.BR lgetfilecon_raw ()
|
||||
|
|
|
@ -29,7 +29,9 @@ link itself has it's context set, not the file that it refers to.
|
|||
is identical to setfilecon, only the open file pointed to by filedes (as
|
||||
returned by
|
||||
.BR open (2))
|
||||
has it's context set in place of path.
|
||||
has it's context set in place of path. Since libselinux 3.4 a file opened via
|
||||
.I O_PATH
|
||||
is supported.
|
||||
|
||||
.BR setfilecon_raw (),
|
||||
.BR lsetfilecon_raw (),
|
||||
|
|
|
@ -3,10 +3,32 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/xattr.h>
|
||||
#include "selinux_internal.h"
|
||||
#include "policy.h"
|
||||
|
||||
static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
|
||||
char buf[40];
|
||||
int fd_flag, saved_errno = errno;
|
||||
ssize_t ret;
|
||||
|
||||
ret = fgetxattr(fd, name, value, size);
|
||||
if (ret != -1 || errno != EBADF)
|
||||
return ret;
|
||||
|
||||
/* Emulate O_PATH support */
|
||||
fd_flag = fcntl(fd, F_GETFL);
|
||||
if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
return getxattr(buf, name, value, size);
|
||||
}
|
||||
|
||||
int fgetfilecon_raw(int fd, char ** context)
|
||||
{
|
||||
char *buf;
|
||||
|
@ -19,11 +41,11 @@ int fgetfilecon_raw(int fd, char ** context)
|
|||
return -1;
|
||||
memset(buf, 0, size);
|
||||
|
||||
ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
|
||||
ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
|
||||
if (ret < 0 && errno == ERANGE) {
|
||||
char *newbuf;
|
||||
|
||||
size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0);
|
||||
size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
|
||||
if (size < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -34,7 +56,7 @@ int fgetfilecon_raw(int fd, char ** context)
|
|||
|
||||
buf = newbuf;
|
||||
memset(buf, 0, size);
|
||||
ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
|
||||
ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
|
||||
}
|
||||
out:
|
||||
if (ret == 0) {
|
||||
|
|
|
@ -3,13 +3,34 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/xattr.h>
|
||||
#include "selinux_internal.h"
|
||||
#include "policy.h"
|
||||
|
||||
static int fsetxattr_wrapper(int fd, const char* name, const void* value, size_t size, int flags) {
|
||||
char buf[40];
|
||||
int rc, fd_flag, saved_errno = errno;
|
||||
|
||||
rc = fsetxattr(fd, name, value, size, flags);
|
||||
if (rc == 0 || errno != EBADF)
|
||||
return rc;
|
||||
|
||||
/* Emulate O_PATH support */
|
||||
fd_flag = fcntl(fd, F_GETFL);
|
||||
if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
return setxattr(buf, name, value, size, flags);
|
||||
}
|
||||
|
||||
int fsetfilecon_raw(int fd, const char * context)
|
||||
{
|
||||
int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
|
||||
int rc = fsetxattr_wrapper(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
|
||||
0);
|
||||
if (rc < 0 && errno == ENOTSUP) {
|
||||
char * ccontext = NULL;
|
||||
|
|
Loading…
Reference in a new issue