16cd6a6acSopenharmony_ci#include <unistd.h>
26cd6a6acSopenharmony_ci#include <fcntl.h>
36cd6a6acSopenharmony_ci#include <string.h>
46cd6a6acSopenharmony_ci#include <stdlib.h>
56cd6a6acSopenharmony_ci#include <errno.h>
66cd6a6acSopenharmony_ci#include <stdio.h>
76cd6a6acSopenharmony_ci#include <sys/xattr.h>
86cd6a6acSopenharmony_ci#include "selinux_internal.h"
96cd6a6acSopenharmony_ci#include "policy.h"
106cd6a6acSopenharmony_ci
116cd6a6acSopenharmony_cistatic ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
126cd6a6acSopenharmony_ci	char buf[40];
136cd6a6acSopenharmony_ci	int fd_flag, saved_errno = errno;
146cd6a6acSopenharmony_ci	ssize_t ret;
156cd6a6acSopenharmony_ci
166cd6a6acSopenharmony_ci	ret = fgetxattr(fd, name, value, size);
176cd6a6acSopenharmony_ci	if (ret != -1 || errno != EBADF)
186cd6a6acSopenharmony_ci		return ret;
196cd6a6acSopenharmony_ci
206cd6a6acSopenharmony_ci	/* Emulate O_PATH support */
216cd6a6acSopenharmony_ci	fd_flag = fcntl(fd, F_GETFL);
226cd6a6acSopenharmony_ci	if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
236cd6a6acSopenharmony_ci		errno = EBADF;
246cd6a6acSopenharmony_ci		return -1;
256cd6a6acSopenharmony_ci	}
266cd6a6acSopenharmony_ci
276cd6a6acSopenharmony_ci	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
286cd6a6acSopenharmony_ci	errno = saved_errno;
296cd6a6acSopenharmony_ci	ret = getxattr(buf, name, value, size);
306cd6a6acSopenharmony_ci	if (ret < 0 && errno == ENOENT)
316cd6a6acSopenharmony_ci		errno = EBADF;
326cd6a6acSopenharmony_ci	return ret;
336cd6a6acSopenharmony_ci}
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ciint fgetfilecon_raw(int fd, char ** context)
366cd6a6acSopenharmony_ci{
376cd6a6acSopenharmony_ci	char *buf;
386cd6a6acSopenharmony_ci	ssize_t size;
396cd6a6acSopenharmony_ci	ssize_t ret;
406cd6a6acSopenharmony_ci
416cd6a6acSopenharmony_ci	size = INITCONTEXTLEN + 1;
426cd6a6acSopenharmony_ci	buf = malloc(size);
436cd6a6acSopenharmony_ci	if (!buf)
446cd6a6acSopenharmony_ci		return -1;
456cd6a6acSopenharmony_ci	memset(buf, 0, size);
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_ci	ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
486cd6a6acSopenharmony_ci	if (ret < 0 && errno == ERANGE) {
496cd6a6acSopenharmony_ci		char *newbuf;
506cd6a6acSopenharmony_ci
516cd6a6acSopenharmony_ci		size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
526cd6a6acSopenharmony_ci		if (size < 0)
536cd6a6acSopenharmony_ci			goto out;
546cd6a6acSopenharmony_ci
556cd6a6acSopenharmony_ci		size++;
566cd6a6acSopenharmony_ci		newbuf = realloc(buf, size);
576cd6a6acSopenharmony_ci		if (!newbuf)
586cd6a6acSopenharmony_ci			goto out;
596cd6a6acSopenharmony_ci
606cd6a6acSopenharmony_ci		buf = newbuf;
616cd6a6acSopenharmony_ci		memset(buf, 0, size);
626cd6a6acSopenharmony_ci		ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
636cd6a6acSopenharmony_ci	}
646cd6a6acSopenharmony_ci      out:
656cd6a6acSopenharmony_ci	if (ret == 0) {
666cd6a6acSopenharmony_ci		/* Re-map empty attribute values to errors. */
676cd6a6acSopenharmony_ci		errno = ENOTSUP;
686cd6a6acSopenharmony_ci		ret = -1;
696cd6a6acSopenharmony_ci	}
706cd6a6acSopenharmony_ci	if (ret < 0)
716cd6a6acSopenharmony_ci		free(buf);
726cd6a6acSopenharmony_ci	else
736cd6a6acSopenharmony_ci		*context = buf;
746cd6a6acSopenharmony_ci	return ret;
756cd6a6acSopenharmony_ci}
766cd6a6acSopenharmony_ci
776cd6a6acSopenharmony_ci
786cd6a6acSopenharmony_ciint fgetfilecon(int fd, char ** context)
796cd6a6acSopenharmony_ci{
806cd6a6acSopenharmony_ci	char * rcontext = NULL;
816cd6a6acSopenharmony_ci	int ret;
826cd6a6acSopenharmony_ci
836cd6a6acSopenharmony_ci	*context = NULL;
846cd6a6acSopenharmony_ci
856cd6a6acSopenharmony_ci	ret = fgetfilecon_raw(fd, &rcontext);
866cd6a6acSopenharmony_ci
876cd6a6acSopenharmony_ci	if (ret > 0) {
886cd6a6acSopenharmony_ci		ret = selinux_raw_to_trans_context(rcontext, context);
896cd6a6acSopenharmony_ci		freecon(rcontext);
906cd6a6acSopenharmony_ci	}
916cd6a6acSopenharmony_ci
926cd6a6acSopenharmony_ci	if (ret >= 0 && *context)
936cd6a6acSopenharmony_ci		return strlen(*context) + 1;
946cd6a6acSopenharmony_ci
956cd6a6acSopenharmony_ci	return ret;
966cd6a6acSopenharmony_ci}
97