16cd6a6acSopenharmony_ci#include <unistd.h> 26cd6a6acSopenharmony_ci#include <sys/types.h> 36cd6a6acSopenharmony_ci#include <fcntl.h> 46cd6a6acSopenharmony_ci#include <stdlib.h> 56cd6a6acSopenharmony_ci#include <stdio.h> 66cd6a6acSopenharmony_ci#include <errno.h> 76cd6a6acSopenharmony_ci#include <string.h> 86cd6a6acSopenharmony_ci#include <limits.h> 96cd6a6acSopenharmony_ci#include "selinux_internal.h" 106cd6a6acSopenharmony_ci#include "policy.h" 116cd6a6acSopenharmony_ci#include "mapping.h" 126cd6a6acSopenharmony_ci 136cd6a6acSopenharmony_ciint security_compute_av_flags_raw(const char * scon, 146cd6a6acSopenharmony_ci const char * tcon, 156cd6a6acSopenharmony_ci security_class_t tclass, 166cd6a6acSopenharmony_ci access_vector_t requested, 176cd6a6acSopenharmony_ci struct av_decision *avd) 186cd6a6acSopenharmony_ci{ 196cd6a6acSopenharmony_ci char path[PATH_MAX]; 206cd6a6acSopenharmony_ci char *buf; 216cd6a6acSopenharmony_ci size_t len; 226cd6a6acSopenharmony_ci int fd, ret; 236cd6a6acSopenharmony_ci security_class_t kclass; 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci if (!selinux_mnt) { 266cd6a6acSopenharmony_ci errno = ENOENT; 276cd6a6acSopenharmony_ci return -1; 286cd6a6acSopenharmony_ci } 296cd6a6acSopenharmony_ci 306cd6a6acSopenharmony_ci snprintf(path, sizeof path, "%s/access", selinux_mnt); 316cd6a6acSopenharmony_ci fd = open(path, O_RDWR | O_CLOEXEC); 326cd6a6acSopenharmony_ci if (fd < 0) 336cd6a6acSopenharmony_ci return -1; 346cd6a6acSopenharmony_ci 356cd6a6acSopenharmony_ci len = selinux_page_size; 366cd6a6acSopenharmony_ci buf = malloc(len); 376cd6a6acSopenharmony_ci if (!buf) { 386cd6a6acSopenharmony_ci ret = -1; 396cd6a6acSopenharmony_ci goto out; 406cd6a6acSopenharmony_ci } 416cd6a6acSopenharmony_ci 426cd6a6acSopenharmony_ci kclass = unmap_class(tclass); 436cd6a6acSopenharmony_ci 446cd6a6acSopenharmony_ci ret = snprintf(buf, len, "%s %s %hu %x", scon, tcon, 456cd6a6acSopenharmony_ci kclass, unmap_perm(tclass, requested)); 466cd6a6acSopenharmony_ci if (ret < 0 || (size_t)ret >= len) { 476cd6a6acSopenharmony_ci errno = EOVERFLOW; 486cd6a6acSopenharmony_ci ret = -1; 496cd6a6acSopenharmony_ci goto out2; 506cd6a6acSopenharmony_ci } 516cd6a6acSopenharmony_ci 526cd6a6acSopenharmony_ci ret = write(fd, buf, strlen(buf)); 536cd6a6acSopenharmony_ci if (ret < 0) 546cd6a6acSopenharmony_ci goto out2; 556cd6a6acSopenharmony_ci 566cd6a6acSopenharmony_ci memset(buf, 0, len); 576cd6a6acSopenharmony_ci ret = read(fd, buf, len - 1); 586cd6a6acSopenharmony_ci if (ret < 0) 596cd6a6acSopenharmony_ci goto out2; 606cd6a6acSopenharmony_ci 616cd6a6acSopenharmony_ci ret = sscanf(buf, "%x %x %x %x %u %x", 626cd6a6acSopenharmony_ci &avd->allowed, &avd->decided, 636cd6a6acSopenharmony_ci &avd->auditallow, &avd->auditdeny, 646cd6a6acSopenharmony_ci &avd->seqno, &avd->flags); 656cd6a6acSopenharmony_ci if (ret < 5) { 666cd6a6acSopenharmony_ci ret = -1; 676cd6a6acSopenharmony_ci goto out2; 686cd6a6acSopenharmony_ci } else if (ret < 6) 696cd6a6acSopenharmony_ci avd->flags = 0; 706cd6a6acSopenharmony_ci 716cd6a6acSopenharmony_ci /* 726cd6a6acSopenharmony_ci * If the tclass could not be mapped to a kernel class at all, the 736cd6a6acSopenharmony_ci * kernel will have already set avd according to the 746cd6a6acSopenharmony_ci * handle_unknown flag and we do not need to do anything further. 756cd6a6acSopenharmony_ci * Otherwise, we must map the permissions within the returned 766cd6a6acSopenharmony_ci * avd to the userspace permission values. 776cd6a6acSopenharmony_ci */ 786cd6a6acSopenharmony_ci if (kclass != 0) 796cd6a6acSopenharmony_ci map_decision(tclass, avd); 806cd6a6acSopenharmony_ci 816cd6a6acSopenharmony_ci ret = 0; 826cd6a6acSopenharmony_ci out2: 836cd6a6acSopenharmony_ci free(buf); 846cd6a6acSopenharmony_ci out: 856cd6a6acSopenharmony_ci close(fd); 866cd6a6acSopenharmony_ci return ret; 876cd6a6acSopenharmony_ci} 886cd6a6acSopenharmony_ci 896cd6a6acSopenharmony_ci 906cd6a6acSopenharmony_ciint security_compute_av_raw(const char * scon, 916cd6a6acSopenharmony_ci const char * tcon, 926cd6a6acSopenharmony_ci security_class_t tclass, 936cd6a6acSopenharmony_ci access_vector_t requested, 946cd6a6acSopenharmony_ci struct av_decision *avd) 956cd6a6acSopenharmony_ci{ 966cd6a6acSopenharmony_ci struct av_decision lavd; 976cd6a6acSopenharmony_ci int ret; 986cd6a6acSopenharmony_ci 996cd6a6acSopenharmony_ci ret = security_compute_av_flags_raw(scon, tcon, tclass, 1006cd6a6acSopenharmony_ci requested, &lavd); 1016cd6a6acSopenharmony_ci if (ret == 0) { 1026cd6a6acSopenharmony_ci avd->allowed = lavd.allowed; 1036cd6a6acSopenharmony_ci avd->decided = lavd.decided; 1046cd6a6acSopenharmony_ci avd->auditallow = lavd.auditallow; 1056cd6a6acSopenharmony_ci avd->auditdeny = lavd.auditdeny; 1066cd6a6acSopenharmony_ci avd->seqno = lavd.seqno; 1076cd6a6acSopenharmony_ci /* NOTE: 1086cd6a6acSopenharmony_ci * We should not return avd->flags via the interface 1096cd6a6acSopenharmony_ci * due to the binary compatibility. 1106cd6a6acSopenharmony_ci */ 1116cd6a6acSopenharmony_ci } 1126cd6a6acSopenharmony_ci return ret; 1136cd6a6acSopenharmony_ci} 1146cd6a6acSopenharmony_ci 1156cd6a6acSopenharmony_ci 1166cd6a6acSopenharmony_ciint security_compute_av_flags(const char * scon, 1176cd6a6acSopenharmony_ci const char * tcon, 1186cd6a6acSopenharmony_ci security_class_t tclass, 1196cd6a6acSopenharmony_ci access_vector_t requested, 1206cd6a6acSopenharmony_ci struct av_decision *avd) 1216cd6a6acSopenharmony_ci{ 1226cd6a6acSopenharmony_ci char * rscon; 1236cd6a6acSopenharmony_ci char * rtcon; 1246cd6a6acSopenharmony_ci int ret; 1256cd6a6acSopenharmony_ci 1266cd6a6acSopenharmony_ci if (selinux_trans_to_raw_context(scon, &rscon)) 1276cd6a6acSopenharmony_ci return -1; 1286cd6a6acSopenharmony_ci if (selinux_trans_to_raw_context(tcon, &rtcon)) { 1296cd6a6acSopenharmony_ci freecon(rscon); 1306cd6a6acSopenharmony_ci return -1; 1316cd6a6acSopenharmony_ci } 1326cd6a6acSopenharmony_ci ret = security_compute_av_flags_raw(rscon, rtcon, tclass, 1336cd6a6acSopenharmony_ci requested, avd); 1346cd6a6acSopenharmony_ci 1356cd6a6acSopenharmony_ci freecon(rscon); 1366cd6a6acSopenharmony_ci freecon(rtcon); 1376cd6a6acSopenharmony_ci 1386cd6a6acSopenharmony_ci return ret; 1396cd6a6acSopenharmony_ci} 1406cd6a6acSopenharmony_ci 1416cd6a6acSopenharmony_ci 1426cd6a6acSopenharmony_ciint security_compute_av(const char * scon, 1436cd6a6acSopenharmony_ci const char * tcon, 1446cd6a6acSopenharmony_ci security_class_t tclass, 1456cd6a6acSopenharmony_ci access_vector_t requested, struct av_decision *avd) 1466cd6a6acSopenharmony_ci{ 1476cd6a6acSopenharmony_ci struct av_decision lavd; 1486cd6a6acSopenharmony_ci int ret; 1496cd6a6acSopenharmony_ci 1506cd6a6acSopenharmony_ci ret = security_compute_av_flags(scon, tcon, tclass, 1516cd6a6acSopenharmony_ci requested, &lavd); 1526cd6a6acSopenharmony_ci if (ret == 0) 1536cd6a6acSopenharmony_ci { 1546cd6a6acSopenharmony_ci avd->allowed = lavd.allowed; 1556cd6a6acSopenharmony_ci avd->decided = lavd.decided; 1566cd6a6acSopenharmony_ci avd->auditallow = lavd.auditallow; 1576cd6a6acSopenharmony_ci avd->auditdeny = lavd.auditdeny; 1586cd6a6acSopenharmony_ci avd->seqno = lavd.seqno; 1596cd6a6acSopenharmony_ci /* NOTE: 1606cd6a6acSopenharmony_ci * We should not return avd->flags via the interface 1616cd6a6acSopenharmony_ci * due to the binary compatibility. 1626cd6a6acSopenharmony_ci */ 1636cd6a6acSopenharmony_ci } 1646cd6a6acSopenharmony_ci 1656cd6a6acSopenharmony_ci return ret; 1666cd6a6acSopenharmony_ci} 1676cd6a6acSopenharmony_ci 168