553 |
return true; |
return true; |
554 |
} |
} |
555 |
|
|
556 |
|
static int ccs_write_domain_policy2(char *data, struct ccs_domain_info *domain, |
557 |
|
struct ccs_condition *cond, |
558 |
|
const bool is_delete) |
559 |
|
{ |
560 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CAPABILITY)) |
561 |
|
return ccs_write_capability_policy(data, domain, cond, |
562 |
|
is_delete); |
563 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_NETWORK)) |
564 |
|
return ccs_write_network_policy(data, domain, cond, is_delete); |
565 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_SIGNAL)) |
566 |
|
return ccs_write_signal_policy(data, domain, cond, is_delete); |
567 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_ENV)) |
568 |
|
return ccs_write_env_policy(data, domain, cond, is_delete); |
569 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_MOUNT)) |
570 |
|
return ccs_write_mount_policy(data, domain, cond, is_delete); |
571 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_UNMOUNT)) |
572 |
|
return ccs_write_umount_policy(data, domain, cond, is_delete); |
573 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CHROOT)) |
574 |
|
return ccs_write_chroot_policy(data, domain, cond, is_delete); |
575 |
|
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_PIVOT_ROOT)) |
576 |
|
return ccs_write_pivot_root_policy(data, domain, cond, |
577 |
|
is_delete); |
578 |
|
return ccs_write_file_policy(data, domain, cond, is_delete); |
579 |
|
} |
580 |
|
|
581 |
/** |
/** |
582 |
* ccs_write_domain_policy - Write domain policy. |
* ccs_write_domain_policy - Write domain policy. |
583 |
* |
* |
638 |
if (!cond) |
if (!cond) |
639 |
return -EINVAL; |
return -EINVAL; |
640 |
} |
} |
641 |
if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CAPABILITY)) |
error = ccs_write_domain_policy2(data, domain, cond, is_delete); |
|
error = ccs_write_capability_policy(data, domain, cond, |
|
|
is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_NETWORK)) |
|
|
error = ccs_write_network_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_SIGNAL)) |
|
|
error = ccs_write_signal_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_ENV)) |
|
|
error = ccs_write_env_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_MOUNT)) |
|
|
error = ccs_write_mount_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_UNMOUNT)) |
|
|
error = ccs_write_umount_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_CHROOT)) |
|
|
error = ccs_write_chroot_policy(data, domain, cond, is_delete); |
|
|
else if (ccs_str_starts(&data, CCS_KEYWORD_ALLOW_PIVOT_ROOT)) |
|
|
error = ccs_write_pivot_root_policy(data, domain, cond, |
|
|
is_delete); |
|
|
else |
|
|
error = ccs_write_file_policy(data, domain, cond, is_delete); |
|
642 |
if (cond) |
if (cond) |
643 |
ccs_put_condition(cond); |
ccs_put_condition(cond); |
644 |
return error; |
return error; |
861 |
pos = head->read_avail; |
pos = head->read_avail; |
862 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", msg) || |
863 |
!ccs_print_name_union(head, &ptr->name) || |
!ccs_print_name_union(head, &ptr->name) || |
864 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
865 |
goto out; |
head->read_bit = bit; |
866 |
|
head->read_avail = pos; |
867 |
|
return false; |
868 |
|
} |
869 |
} |
} |
870 |
head->read_bit = 0; |
head->read_bit = 0; |
871 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
872 |
} |
} |
873 |
|
|
874 |
/** |
/** |
897 |
!ccs_print_name_union(head, &ptr->name) || |
!ccs_print_name_union(head, &ptr->name) || |
898 |
!ccs_print_number_union(head, &ptr->major) || |
!ccs_print_number_union(head, &ptr->major) || |
899 |
!ccs_print_number_union(head, &ptr->minor) || |
!ccs_print_number_union(head, &ptr->minor) || |
900 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
901 |
goto out; |
head->read_bit = bit; |
902 |
|
head->read_avail = pos; |
903 |
|
return false; |
904 |
|
} |
905 |
} |
} |
906 |
head->read_bit = 0; |
head->read_bit = 0; |
907 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
908 |
} |
} |
909 |
|
|
910 |
/** |
/** |
932 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", msg) || |
933 |
!ccs_print_name_union(head, &ptr->name1) || |
!ccs_print_name_union(head, &ptr->name1) || |
934 |
!ccs_print_name_union(head, &ptr->name2) || |
!ccs_print_name_union(head, &ptr->name2) || |
935 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
936 |
goto out; |
head->read_bit = bit; |
937 |
|
head->read_avail = pos; |
938 |
|
return false; |
939 |
|
} |
940 |
} |
} |
941 |
head->read_bit = 0; |
head->read_bit = 0; |
942 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
943 |
} |
} |
944 |
|
|
945 |
/** |
/** |
967 |
if (!ccs_io_printf(head, "allow_%s", msg) || |
if (!ccs_io_printf(head, "allow_%s", msg) || |
968 |
!ccs_print_name_union(head, &ptr->name) || |
!ccs_print_name_union(head, &ptr->name) || |
969 |
!ccs_print_number_union(head, &ptr->number) || |
!ccs_print_number_union(head, &ptr->number) || |
970 |
!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
971 |
goto out; |
head->read_bit = bit; |
972 |
|
head->read_avail = pos; |
973 |
|
return false; |
974 |
|
} |
975 |
} |
} |
976 |
head->read_bit = 0; |
head->read_bit = 0; |
977 |
return true; |
return true; |
|
out: |
|
|
head->read_bit = bit; |
|
|
head->read_avail = pos; |
|
|
return false; |
|
978 |
} |
} |
979 |
|
|
980 |
/** |
/** |
990 |
struct ccs_env_acl_record *ptr, |
struct ccs_env_acl_record *ptr, |
991 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
992 |
{ |
{ |
993 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
994 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_ENV "%s", ptr->env->name)) |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_ENV "%s", ptr->env->name) || |
995 |
goto out; |
!ccs_print_condition(head, cond)) { |
996 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
997 |
goto out; |
return false; |
998 |
|
} |
999 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1000 |
} |
} |
1001 |
|
|
1002 |
/** |
/** |
1012 |
struct ccs_capability_acl_record *ptr, |
struct ccs_capability_acl_record *ptr, |
1013 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1014 |
{ |
{ |
1015 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1016 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CAPABILITY "%s", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CAPABILITY "%s", |
1017 |
ccs_cap2keyword(ptr->operation))) |
ccs_cap2keyword(ptr->operation)) || |
1018 |
goto out; |
!ccs_print_condition(head, cond)) { |
1019 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1020 |
goto out; |
return false; |
1021 |
|
} |
1022 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1023 |
} |
} |
1024 |
|
|
1025 |
/** |
/** |
1081 |
struct ccs_ip_network_acl_record *ptr, |
struct ccs_ip_network_acl_record *ptr, |
1082 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1083 |
{ |
{ |
1084 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1085 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_NETWORK "%s ", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_NETWORK "%s ", |
1086 |
ccs_net2keyword(ptr->operation_type))) |
ccs_net2keyword(ptr->operation_type))) |
1087 |
goto out; |
goto out; |
1122 |
struct ccs_signal_acl_record *ptr, |
struct ccs_signal_acl_record *ptr, |
1123 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1124 |
{ |
{ |
1125 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1126 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_SIGNAL "%u %s", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_SIGNAL "%u %s", |
1127 |
ptr->sig, ptr->domainname->name)) |
ptr->sig, ptr->domainname->name) || |
1128 |
goto out; |
!ccs_print_condition(head, cond)) { |
1129 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1130 |
goto out; |
return false; |
1131 |
|
} |
1132 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1133 |
} |
} |
1134 |
|
|
1135 |
/** |
/** |
1162 |
struct ccs_mount_acl_record *ptr, |
struct ccs_mount_acl_record *ptr, |
1163 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1164 |
{ |
{ |
1165 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1166 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_MOUNT) || |
1167 |
ptr->dev_name->name, ptr->dir_name->name, |
!ccs_print_name_union(head, &ptr->dev_name) || |
1168 |
ptr->fs_type->name, ptr->flags)) |
!ccs_print_name_union(head, &ptr->dir_name) || |
1169 |
goto out; |
!ccs_print_name_union(head, &ptr->fs_type) || |
1170 |
if (!ccs_print_condition(head, cond)) |
!ccs_print_number_union(head, &ptr->flags) || |
1171 |
goto out; |
!ccs_print_condition(head, cond)) { |
1172 |
|
head->read_avail = pos; |
1173 |
|
return false; |
1174 |
|
} |
1175 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1176 |
} |
} |
1177 |
|
|
1178 |
/** |
/** |
1188 |
struct ccs_umount_acl_record *ptr, |
struct ccs_umount_acl_record *ptr, |
1189 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1190 |
{ |
{ |
1191 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1192 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_UNMOUNT "%s\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_UNMOUNT) || |
1193 |
ptr->dir->name)) |
!ccs_print_name_union(head, &ptr->dir) || |
1194 |
goto out; |
!ccs_print_condition(head, cond)) { |
1195 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1196 |
goto out; |
return false; |
1197 |
|
} |
1198 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1199 |
} |
} |
1200 |
|
|
1201 |
/** |
/** |
1211 |
struct ccs_chroot_acl_record *ptr, |
struct ccs_chroot_acl_record *ptr, |
1212 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1213 |
{ |
{ |
1214 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1215 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CHROOT "%s\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_CHROOT) || |
1216 |
ptr->dir->name)) |
!ccs_print_name_union(head, &ptr->dir) || |
1217 |
goto out; |
!ccs_print_condition(head, cond)) { |
1218 |
if (!ccs_print_condition(head, cond)) |
head->read_avail = pos; |
1219 |
goto out; |
return false; |
1220 |
|
} |
1221 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1222 |
} |
} |
1223 |
|
|
1224 |
/** |
/** |
1234 |
struct ccs_pivot_root_acl_record *ptr, |
struct ccs_pivot_root_acl_record *ptr, |
1235 |
const struct ccs_condition *cond) |
const struct ccs_condition *cond) |
1236 |
{ |
{ |
1237 |
int pos = head->read_avail; |
const int pos = head->read_avail; |
1238 |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_PIVOT_ROOT "%s %s\n", |
if (!ccs_io_printf(head, CCS_KEYWORD_ALLOW_PIVOT_ROOT) || |
1239 |
ptr->new_root->name, ptr->old_root->name)) |
!ccs_print_name_union(head, &ptr->new_root) || |
1240 |
goto out; |
!ccs_print_name_union(head, &ptr->old_root) || |
1241 |
if (!ccs_print_condition(head, cond)) |
!ccs_print_condition(head, cond)) { |
1242 |
goto out; |
head->read_avail = pos; |
1243 |
|
return false; |
1244 |
|
} |
1245 |
return true; |
return true; |
|
out: |
|
|
head->read_avail = pos; |
|
|
return false; |
|
1246 |
} |
} |
1247 |
|
|
1248 |
/** |
/** |
1681 |
return 0; |
return 0; |
1682 |
} |
} |
1683 |
|
|
1684 |
|
/** |
1685 |
|
* ccs_get_argv0 - Get argv[0]. |
1686 |
|
* |
1687 |
|
* @ee: Pointer to "struct ccs_execve_entry". |
1688 |
|
* |
1689 |
|
* Returns true on success, false otherwise. |
1690 |
|
*/ |
1691 |
|
static bool ccs_get_argv0(struct ccs_execve_entry *ee) |
1692 |
|
{ |
1693 |
|
struct linux_binprm *bprm = ee->bprm; |
1694 |
|
char *arg_ptr = ee->tmp; |
1695 |
|
int arg_len = 0; |
1696 |
|
unsigned long pos = bprm->p; |
1697 |
|
int offset = pos % PAGE_SIZE; |
1698 |
|
bool done = false; |
1699 |
|
if (!bprm->argc) |
1700 |
|
goto out; |
1701 |
|
while (1) { |
1702 |
|
if (!ccs_dump_page(bprm, pos, &ee->dump)) |
1703 |
|
goto out; |
1704 |
|
pos += PAGE_SIZE - offset; |
1705 |
|
/* Read. */ |
1706 |
|
while (offset < PAGE_SIZE) { |
1707 |
|
const char *kaddr = ee->dump.data; |
1708 |
|
const unsigned char c = kaddr[offset++]; |
1709 |
|
if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) { |
1710 |
|
if (c == '\\') { |
1711 |
|
arg_ptr[arg_len++] = '\\'; |
1712 |
|
arg_ptr[arg_len++] = '\\'; |
1713 |
|
} else if (c == '/') { |
1714 |
|
arg_len = 0; |
1715 |
|
} else if (c > ' ' && c < 127) { |
1716 |
|
arg_ptr[arg_len++] = c; |
1717 |
|
} else { |
1718 |
|
arg_ptr[arg_len++] = '\\'; |
1719 |
|
arg_ptr[arg_len++] = (c >> 6) + '0'; |
1720 |
|
arg_ptr[arg_len++] |
1721 |
|
= ((c >> 3) & 7) + '0'; |
1722 |
|
arg_ptr[arg_len++] = (c & 7) + '0'; |
1723 |
|
} |
1724 |
|
} else { |
1725 |
|
arg_ptr[arg_len] = '\0'; |
1726 |
|
done = true; |
1727 |
|
break; |
1728 |
|
} |
1729 |
|
} |
1730 |
|
offset = 0; |
1731 |
|
if (done) |
1732 |
|
break; |
1733 |
|
} |
1734 |
|
return true; |
1735 |
|
out: |
1736 |
|
return false; |
1737 |
|
} |
1738 |
|
|
1739 |
|
static struct ccs_condition *ccs_get_execute_condition(struct ccs_execve_entry |
1740 |
|
*ee) |
1741 |
|
{ |
1742 |
|
struct ccs_condition *cond; |
1743 |
|
char *buf; |
1744 |
|
int len = 256; |
1745 |
|
char *realpath = NULL; |
1746 |
|
char *argv0 = NULL; |
1747 |
|
if (ccs_check_flags(NULL, CCS_AUTOLEARN_EXEC_REALPATH)) { |
1748 |
|
struct file *file = ee->bprm->file; |
1749 |
|
realpath = ccs_realpath_from_dentry(file->f_dentry, |
1750 |
|
file->f_vfsmnt); |
1751 |
|
if (realpath) |
1752 |
|
len += strlen(realpath) + 17; |
1753 |
|
} |
1754 |
|
if (ccs_check_flags(NULL, CCS_AUTOLEARN_EXEC_REALPATH)) { |
1755 |
|
if (ccs_get_argv0(ee)) { |
1756 |
|
argv0 = ee->tmp; |
1757 |
|
len += strlen(argv0) + 16; |
1758 |
|
} |
1759 |
|
} |
1760 |
|
buf = kmalloc(len, GFP_KERNEL); |
1761 |
|
if (!buf) |
1762 |
|
return NULL; |
1763 |
|
snprintf(buf, len - 1, "if"); |
1764 |
|
if (current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER) { |
1765 |
|
const int pos = strlen(buf); |
1766 |
|
snprintf(buf + pos, len - pos - 1, |
1767 |
|
" task.type=execute_handler"); |
1768 |
|
} |
1769 |
|
if (realpath) { |
1770 |
|
const int pos = strlen(buf); |
1771 |
|
snprintf(buf + pos, len - pos - 1, " exec.realpath=\"%s\"", |
1772 |
|
realpath); |
1773 |
|
kfree(realpath); |
1774 |
|
} |
1775 |
|
if (argv0) { |
1776 |
|
const int pos = strlen(buf); |
1777 |
|
snprintf(buf + pos, len - pos - 1, " exec.argv[0]=\"%s\"", |
1778 |
|
argv0); |
1779 |
|
} |
1780 |
|
cond = ccs_get_condition(buf); |
1781 |
|
kfree(buf); |
1782 |
|
return cond; |
1783 |
|
} |
1784 |
|
|
1785 |
/* Wait queue for ccs_query_list. */ |
/* Wait queue for ccs_query_list. */ |
1786 |
static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait); |
static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait); |
1787 |
|
|
1813 |
* Returns 0 if the supervisor decided to permit the access request which |
* Returns 0 if the supervisor decided to permit the access request which |
1814 |
* violated the policy in enforcing mode, 1 if the supervisor decided to |
* violated the policy in enforcing mode, 1 if the supervisor decided to |
1815 |
* retry the access request which violated the policy in enforcing mode, |
* retry the access request which violated the policy in enforcing mode, |
1816 |
* -EPERM otherwise. |
* 0 if it is not in enforcing mode, -EPERM otherwise. |
1817 |
*/ |
*/ |
1818 |
int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
1819 |
{ |
{ |
1827 |
char *header; |
char *header; |
1828 |
if (!r->domain) |
if (!r->domain) |
1829 |
r->domain = ccs_current_domain(); |
r->domain = ccs_current_domain(); |
1830 |
|
switch (r->mode) { |
1831 |
|
char *buffer; |
1832 |
|
struct ccs_condition *cond; |
1833 |
|
case 1: |
1834 |
|
if (!ccs_domain_quota_ok(r)) |
1835 |
|
return 0; |
1836 |
|
va_start(args, fmt); |
1837 |
|
len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4; |
1838 |
|
va_end(args); |
1839 |
|
buffer = kmalloc(len, GFP_KERNEL); |
1840 |
|
if (!buffer) |
1841 |
|
return 0; |
1842 |
|
va_start(args, fmt); |
1843 |
|
vsnprintf(buffer, len - 1, fmt, args); |
1844 |
|
va_end(args); |
1845 |
|
ccs_normalize_line(buffer); |
1846 |
|
if (r->ee && !strncmp(buffer, "allow_execute ", 14)) |
1847 |
|
cond = ccs_get_execute_condition(r->ee); |
1848 |
|
else if ((current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)) { |
1849 |
|
char str[] = "if task.type=execute_handler"; |
1850 |
|
cond = ccs_get_condition(str); |
1851 |
|
} else |
1852 |
|
cond = NULL; |
1853 |
|
ccs_write_domain_policy2(buffer, r->domain, cond, false); |
1854 |
|
ccs_put_condition(cond); |
1855 |
|
kfree(buffer); |
1856 |
|
/* fall through */ |
1857 |
|
case 2: |
1858 |
|
return 0; |
1859 |
|
} |
1860 |
if (!atomic_read(&ccs_query_observers)) { |
if (!atomic_read(&ccs_query_observers)) { |
1861 |
int i; |
int i; |
1862 |
if (current->ccs_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) |
if (current->ccs_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) |