Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

smack: limit privilege by label

There have been a number of requests to make the Smack LSM
enforce MAC even in the face of privilege, either capability
based or superuser based. This is not universally desired,
however, so it seems desirable to make it optional. Further,
at least one legacy OS implemented a scheme whereby only
processes running with one particular label could be exempt
from MAC. This patch supports these three cases.

If /smack/onlycap is empty (unset or null-string) privilege
is enforced in the normal way.

If /smack/onlycap contains a label only processes running with
that label may be MAC exempt.

If the label in /smack/onlycap is the star label ("*") the
semantics of the star label combine with the privilege
restrictions to prevent any violations of MAC, even in the
presence of privilege.

Again, this will be independent of the privilege scheme.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: James Morris <jmorris@namei.org>

authored by

Casey Schaufler and committed by
James Morris
15446235 cf9481e2

+102 -1
+1
security/smack/smack.h
··· 178 178 extern int smack_cipso_direct; 179 179 extern int smack_net_nltype; 180 180 extern char *smack_net_ambient; 181 + extern char *smack_onlycap; 181 182 182 183 extern struct smack_known *smack_known; 183 184 extern struct smack_known smack_known_floor;
+9 -1
security/smack/smack_access.c
··· 157 157 * 158 158 * This function checks the current subject label/object label pair 159 159 * in the access rule list and returns 0 if the access is permitted, 160 - * non zero otherwise. It allows that current my have the capability 160 + * non zero otherwise. It allows that current may have the capability 161 161 * to override the rules. 162 162 */ 163 163 int smk_curacc(char *obj_label, u32 mode) ··· 167 167 rc = smk_access(current->security, obj_label, mode); 168 168 if (rc == 0) 169 169 return 0; 170 + 171 + /* 172 + * Return if a specific label has been designated as the 173 + * only one that gets privilege and current does not 174 + * have that label. 175 + */ 176 + if (smack_onlycap != NULL && smack_onlycap != current->security) 177 + return rc; 170 178 171 179 if (capable(CAP_MAC_OVERRIDE)) 172 180 return 0;
+92
security/smack/smackfs.c
··· 39 39 SMK_DIRECT = 6, /* CIPSO level indicating direct label */ 40 40 SMK_AMBIENT = 7, /* internet ambient label */ 41 41 SMK_NLTYPE = 8, /* label scheme to use by default */ 42 + SMK_ONLYCAP = 9, /* the only "capable" label */ 42 43 }; 43 44 44 45 /* ··· 68 67 * It can be reset via smackfs/direct 69 68 */ 70 69 int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; 70 + 71 + /* 72 + * Unless a process is running with this label even 73 + * having CAP_MAC_OVERRIDE isn't enough to grant 74 + * privilege to violate MAC policy. If no label is 75 + * designated (the NULL case) capabilities apply to 76 + * everyone. It is expected that the hat (^) label 77 + * will be used if any label is used. 78 + */ 79 + char *smack_onlycap; 71 80 72 81 static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; 73 82 struct smk_list_entry *smack_list; ··· 798 787 .write = smk_write_ambient, 799 788 }; 800 789 790 + /** 791 + * smk_read_onlycap - read() for /smack/onlycap 792 + * @filp: file pointer, not actually used 793 + * @buf: where to put the result 794 + * @cn: maximum to send along 795 + * @ppos: where to start 796 + * 797 + * Returns number of bytes read or error code, as appropriate 798 + */ 799 + static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, 800 + size_t cn, loff_t *ppos) 801 + { 802 + char *smack = ""; 803 + ssize_t rc = -EINVAL; 804 + int asize; 805 + 806 + if (*ppos != 0) 807 + return 0; 808 + 809 + if (smack_onlycap != NULL) 810 + smack = smack_onlycap; 811 + 812 + asize = strlen(smack) + 1; 813 + 814 + if (cn >= asize) 815 + rc = simple_read_from_buffer(buf, cn, ppos, smack, asize); 816 + 817 + return rc; 818 + } 819 + 820 + /** 821 + * smk_write_onlycap - write() for /smack/onlycap 822 + * @filp: file pointer, not actually used 823 + * @buf: where to get the data from 824 + * @count: bytes sent 825 + * @ppos: where to start 826 + * 827 + * Returns number of bytes written or error code, as appropriate 828 + */ 829 + static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, 830 + size_t count, loff_t *ppos) 831 + { 832 + char in[SMK_LABELLEN]; 833 + char *sp = current->security; 834 + 835 + if (!capable(CAP_MAC_ADMIN)) 836 + return -EPERM; 837 + 838 + /* 839 + * This can be done using smk_access() but is done 840 + * explicitly for clarity. The smk_access() implementation 841 + * would use smk_access(smack_onlycap, MAY_WRITE) 842 + */ 843 + if (smack_onlycap != NULL && smack_onlycap != sp) 844 + return -EPERM; 845 + 846 + if (count >= SMK_LABELLEN) 847 + return -EINVAL; 848 + 849 + if (copy_from_user(in, buf, count) != 0) 850 + return -EFAULT; 851 + 852 + /* 853 + * Should the null string be passed in unset the onlycap value. 854 + * This seems like something to be careful with as usually 855 + * smk_import only expects to return NULL for errors. It 856 + * is usually the case that a nullstring or "\n" would be 857 + * bad to pass to smk_import but in fact this is useful here. 858 + */ 859 + smack_onlycap = smk_import(in, count); 860 + 861 + return count; 862 + } 863 + 864 + static const struct file_operations smk_onlycap_ops = { 865 + .read = smk_read_onlycap, 866 + .write = smk_write_onlycap, 867 + }; 868 + 801 869 struct option_names { 802 870 int o_number; 803 871 char *o_name; ··· 1009 919 {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, 1010 920 [SMK_NLTYPE] = 1011 921 {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, 922 + [SMK_ONLYCAP] = 923 + {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, 1012 924 /* last one */ {""} 1013 925 }; 1014 926