diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/smack/smack.h | 9 | ||||
-rw-r--r-- | security/smack/smack_access.c | 52 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 269 | ||||
-rw-r--r-- | security/smack/smackfs.c | 370 |
4 files changed, 522 insertions, 178 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index 129c4eb8ffb1..e365d455ceb6 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -52,13 +52,16 @@ struct socket_smack { | |||
52 | struct inode_smack { | 52 | struct inode_smack { |
53 | char *smk_inode; /* label of the fso */ | 53 | char *smk_inode; /* label of the fso */ |
54 | char *smk_task; /* label of the task */ | 54 | char *smk_task; /* label of the task */ |
55 | char *smk_mmap; /* label of the mmap domain */ | ||
55 | struct mutex smk_lock; /* initialization lock */ | 56 | struct mutex smk_lock; /* initialization lock */ |
56 | int smk_flags; /* smack inode flags */ | 57 | int smk_flags; /* smack inode flags */ |
57 | }; | 58 | }; |
58 | 59 | ||
59 | struct task_smack { | 60 | struct task_smack { |
60 | char *smk_task; /* label used for access control */ | 61 | char *smk_task; /* label for access control */ |
61 | char *smk_forked; /* label when forked */ | 62 | char *smk_forked; /* label when forked */ |
63 | struct list_head smk_rules; /* per task access rules */ | ||
64 | struct mutex smk_rules_lock; /* lock for the rules */ | ||
62 | }; | 65 | }; |
63 | 66 | ||
64 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ | 67 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ |
@@ -202,7 +205,7 @@ struct inode_smack *new_inode_smack(char *); | |||
202 | /* | 205 | /* |
203 | * These functions are in smack_access.c | 206 | * These functions are in smack_access.c |
204 | */ | 207 | */ |
205 | int smk_access_entry(char *, char *); | 208 | int smk_access_entry(char *, char *, struct list_head *); |
206 | int smk_access(char *, char *, int, struct smk_audit_info *); | 209 | int smk_access(char *, char *, int, struct smk_audit_info *); |
207 | int smk_curacc(char *, u32, struct smk_audit_info *); | 210 | int smk_curacc(char *, u32, struct smk_audit_info *); |
208 | int smack_to_cipso(const char *, struct smack_cipso *); | 211 | int smack_to_cipso(const char *, struct smack_cipso *); |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 7ba8478f599e..86453db4333d 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -70,10 +70,11 @@ int log_policy = SMACK_AUDIT_DENIED; | |||
70 | * smk_access_entry - look up matching access rule | 70 | * smk_access_entry - look up matching access rule |
71 | * @subject_label: a pointer to the subject's Smack label | 71 | * @subject_label: a pointer to the subject's Smack label |
72 | * @object_label: a pointer to the object's Smack label | 72 | * @object_label: a pointer to the object's Smack label |
73 | * @rule_list: the list of rules to search | ||
73 | * | 74 | * |
74 | * This function looks up the subject/object pair in the | 75 | * This function looks up the subject/object pair in the |
75 | * access rule list and returns pointer to the matching rule if found, | 76 | * access rule list and returns the access mode. If no |
76 | * NULL otherwise. | 77 | * entry is found returns -ENOENT. |
77 | * | 78 | * |
78 | * NOTE: | 79 | * NOTE: |
79 | * Even though Smack labels are usually shared on smack_list | 80 | * Even though Smack labels are usually shared on smack_list |
@@ -85,13 +86,13 @@ int log_policy = SMACK_AUDIT_DENIED; | |||
85 | * will be on the list, so checking the pointers may be a worthwhile | 86 | * will be on the list, so checking the pointers may be a worthwhile |
86 | * optimization. | 87 | * optimization. |
87 | */ | 88 | */ |
88 | int smk_access_entry(char *subject_label, char *object_label) | 89 | int smk_access_entry(char *subject_label, char *object_label, |
90 | struct list_head *rule_list) | ||
89 | { | 91 | { |
90 | u32 may = MAY_NOT; | 92 | int may = -ENOENT; |
91 | struct smack_rule *srp; | 93 | struct smack_rule *srp; |
92 | 94 | ||
93 | rcu_read_lock(); | 95 | list_for_each_entry_rcu(srp, rule_list, list) { |
94 | list_for_each_entry_rcu(srp, &smack_rule_list, list) { | ||
95 | if (srp->smk_subject == subject_label || | 96 | if (srp->smk_subject == subject_label || |
96 | strcmp(srp->smk_subject, subject_label) == 0) { | 97 | strcmp(srp->smk_subject, subject_label) == 0) { |
97 | if (srp->smk_object == object_label || | 98 | if (srp->smk_object == object_label || |
@@ -101,7 +102,6 @@ int smk_access_entry(char *subject_label, char *object_label) | |||
101 | } | 102 | } |
102 | } | 103 | } |
103 | } | 104 | } |
104 | rcu_read_unlock(); | ||
105 | 105 | ||
106 | return may; | 106 | return may; |
107 | } | 107 | } |
@@ -129,7 +129,7 @@ int smk_access_entry(char *subject_label, char *object_label) | |||
129 | int smk_access(char *subject_label, char *object_label, int request, | 129 | int smk_access(char *subject_label, char *object_label, int request, |
130 | struct smk_audit_info *a) | 130 | struct smk_audit_info *a) |
131 | { | 131 | { |
132 | u32 may = MAY_NOT; | 132 | int may = MAY_NOT; |
133 | int rc = 0; | 133 | int rc = 0; |
134 | 134 | ||
135 | /* | 135 | /* |
@@ -181,13 +181,14 @@ int smk_access(char *subject_label, char *object_label, int request, | |||
181 | * Beyond here an explicit relationship is required. | 181 | * Beyond here an explicit relationship is required. |
182 | * If the requested access is contained in the available | 182 | * If the requested access is contained in the available |
183 | * access (e.g. read is included in readwrite) it's | 183 | * access (e.g. read is included in readwrite) it's |
184 | * good. | 184 | * good. A negative response from smk_access_entry() |
185 | */ | 185 | * indicates there is no entry for this pair. |
186 | may = smk_access_entry(subject_label, object_label); | ||
187 | /* | ||
188 | * This is a bit map operation. | ||
189 | */ | 186 | */ |
190 | if ((request & may) == request) | 187 | rcu_read_lock(); |
188 | may = smk_access_entry(subject_label, object_label, &smack_rule_list); | ||
189 | rcu_read_unlock(); | ||
190 | |||
191 | if (may > 0 && (request & may) == request) | ||
191 | goto out_audit; | 192 | goto out_audit; |
192 | 193 | ||
193 | rc = -EACCES; | 194 | rc = -EACCES; |
@@ -212,12 +213,27 @@ out_audit: | |||
212 | */ | 213 | */ |
213 | int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) | 214 | int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) |
214 | { | 215 | { |
216 | struct task_smack *tsp = current_security(); | ||
217 | char *sp = smk_of_task(tsp); | ||
218 | int may; | ||
215 | int rc; | 219 | int rc; |
216 | char *sp = smk_of_current(); | ||
217 | 220 | ||
221 | /* | ||
222 | * Check the global rule list | ||
223 | */ | ||
218 | rc = smk_access(sp, obj_label, mode, NULL); | 224 | rc = smk_access(sp, obj_label, mode, NULL); |
219 | if (rc == 0) | 225 | if (rc == 0) { |
220 | goto out_audit; | 226 | /* |
227 | * If there is an entry in the task's rule list | ||
228 | * it can further restrict access. | ||
229 | */ | ||
230 | may = smk_access_entry(sp, obj_label, &tsp->smk_rules); | ||
231 | if (may < 0) | ||
232 | goto out_audit; | ||
233 | if ((mode & may) == mode) | ||
234 | goto out_audit; | ||
235 | rc = -EACCES; | ||
236 | } | ||
221 | 237 | ||
222 | /* | 238 | /* |
223 | * Return if a specific label has been designated as the | 239 | * Return if a specific label has been designated as the |
@@ -228,7 +244,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) | |||
228 | goto out_audit; | 244 | goto out_audit; |
229 | 245 | ||
230 | if (capable(CAP_MAC_OVERRIDE)) | 246 | if (capable(CAP_MAC_OVERRIDE)) |
231 | return 0; | 247 | rc = 0; |
232 | 248 | ||
233 | out_audit: | 249 | out_audit: |
234 | #ifdef CONFIG_AUDIT | 250 | #ifdef CONFIG_AUDIT |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 533bf3255d7f..123a499ded37 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -84,6 +84,56 @@ struct inode_smack *new_inode_smack(char *smack) | |||
84 | return isp; | 84 | return isp; |
85 | } | 85 | } |
86 | 86 | ||
87 | /** | ||
88 | * new_task_smack - allocate a task security blob | ||
89 | * @smack: a pointer to the Smack label to use in the blob | ||
90 | * | ||
91 | * Returns the new blob or NULL if there's no memory available | ||
92 | */ | ||
93 | static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp) | ||
94 | { | ||
95 | struct task_smack *tsp; | ||
96 | |||
97 | tsp = kzalloc(sizeof(struct task_smack), gfp); | ||
98 | if (tsp == NULL) | ||
99 | return NULL; | ||
100 | |||
101 | tsp->smk_task = task; | ||
102 | tsp->smk_forked = forked; | ||
103 | INIT_LIST_HEAD(&tsp->smk_rules); | ||
104 | mutex_init(&tsp->smk_rules_lock); | ||
105 | |||
106 | return tsp; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * smk_copy_rules - copy a rule set | ||
111 | * @nhead - new rules header pointer | ||
112 | * @ohead - old rules header pointer | ||
113 | * | ||
114 | * Returns 0 on success, -ENOMEM on error | ||
115 | */ | ||
116 | static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, | ||
117 | gfp_t gfp) | ||
118 | { | ||
119 | struct smack_rule *nrp; | ||
120 | struct smack_rule *orp; | ||
121 | int rc = 0; | ||
122 | |||
123 | INIT_LIST_HEAD(nhead); | ||
124 | |||
125 | list_for_each_entry_rcu(orp, ohead, list) { | ||
126 | nrp = kzalloc(sizeof(struct smack_rule), gfp); | ||
127 | if (nrp == NULL) { | ||
128 | rc = -ENOMEM; | ||
129 | break; | ||
130 | } | ||
131 | *nrp = *orp; | ||
132 | list_add_rcu(&nrp->list, nhead); | ||
133 | } | ||
134 | return rc; | ||
135 | } | ||
136 | |||
87 | /* | 137 | /* |
88 | * LSM hooks. | 138 | * LSM hooks. |
89 | * We he, that is fun! | 139 | * We he, that is fun! |
@@ -102,23 +152,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) | |||
102 | { | 152 | { |
103 | int rc; | 153 | int rc; |
104 | struct smk_audit_info ad; | 154 | struct smk_audit_info ad; |
105 | char *sp, *tsp; | 155 | char *tsp; |
106 | 156 | ||
107 | rc = cap_ptrace_access_check(ctp, mode); | 157 | rc = cap_ptrace_access_check(ctp, mode); |
108 | if (rc != 0) | 158 | if (rc != 0) |
109 | return rc; | 159 | return rc; |
110 | 160 | ||
111 | sp = smk_of_current(); | ||
112 | tsp = smk_of_task(task_security(ctp)); | 161 | tsp = smk_of_task(task_security(ctp)); |
113 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | 162 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); |
114 | smk_ad_setfield_u_tsk(&ad, ctp); | 163 | smk_ad_setfield_u_tsk(&ad, ctp); |
115 | 164 | ||
116 | /* we won't log here, because rc can be overriden */ | 165 | rc = smk_curacc(tsp, MAY_READWRITE, &ad); |
117 | rc = smk_access(sp, tsp, MAY_READWRITE, NULL); | ||
118 | if (rc != 0 && capable(CAP_MAC_OVERRIDE)) | ||
119 | rc = 0; | ||
120 | |||
121 | smack_log(sp, tsp, MAY_READWRITE, rc, &ad); | ||
122 | return rc; | 166 | return rc; |
123 | } | 167 | } |
124 | 168 | ||
@@ -134,23 +178,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
134 | { | 178 | { |
135 | int rc; | 179 | int rc; |
136 | struct smk_audit_info ad; | 180 | struct smk_audit_info ad; |
137 | char *sp, *tsp; | 181 | char *tsp; |
138 | 182 | ||
139 | rc = cap_ptrace_traceme(ptp); | 183 | rc = cap_ptrace_traceme(ptp); |
140 | if (rc != 0) | 184 | if (rc != 0) |
141 | return rc; | 185 | return rc; |
142 | 186 | ||
187 | tsp = smk_of_task(task_security(ptp)); | ||
143 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | 188 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); |
144 | smk_ad_setfield_u_tsk(&ad, ptp); | 189 | smk_ad_setfield_u_tsk(&ad, ptp); |
145 | 190 | ||
146 | sp = smk_of_current(); | 191 | rc = smk_curacc(tsp, MAY_READWRITE, &ad); |
147 | tsp = smk_of_task(task_security(ptp)); | ||
148 | /* we won't log here, because rc can be overriden */ | ||
149 | rc = smk_access(tsp, sp, MAY_READWRITE, NULL); | ||
150 | if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) | ||
151 | rc = 0; | ||
152 | |||
153 | smack_log(tsp, sp, MAY_READWRITE, rc, &ad); | ||
154 | return rc; | 192 | return rc; |
155 | } | 193 | } |
156 | 194 | ||
@@ -474,7 +512,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
474 | { | 512 | { |
475 | char *isp = smk_of_inode(inode); | 513 | char *isp = smk_of_inode(inode); |
476 | char *dsp = smk_of_inode(dir); | 514 | char *dsp = smk_of_inode(dir); |
477 | u32 may; | 515 | int may; |
478 | 516 | ||
479 | if (name) { | 517 | if (name) { |
480 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); | 518 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); |
@@ -483,14 +521,17 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
483 | } | 521 | } |
484 | 522 | ||
485 | if (value) { | 523 | if (value) { |
486 | may = smk_access_entry(smk_of_current(), dsp); | 524 | rcu_read_lock(); |
525 | may = smk_access_entry(smk_of_current(), dsp, &smack_rule_list); | ||
526 | rcu_read_unlock(); | ||
487 | 527 | ||
488 | /* | 528 | /* |
489 | * If the access rule allows transmutation and | 529 | * If the access rule allows transmutation and |
490 | * the directory requests transmutation then | 530 | * the directory requests transmutation then |
491 | * by all means transmute. | 531 | * by all means transmute. |
492 | */ | 532 | */ |
493 | if (((may & MAY_TRANSMUTE) != 0) && smk_inode_transmutable(dir)) | 533 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && |
534 | smk_inode_transmutable(dir)) | ||
494 | isp = dsp; | 535 | isp = dsp; |
495 | 536 | ||
496 | *value = kstrdup(isp, GFP_KERNEL); | 537 | *value = kstrdup(isp, GFP_KERNEL); |
@@ -716,7 +757,8 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
716 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || | 757 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || |
717 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || | 758 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || |
718 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || | 759 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || |
719 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { | 760 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || |
761 | strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | ||
720 | if (!capable(CAP_MAC_ADMIN)) | 762 | if (!capable(CAP_MAC_ADMIN)) |
721 | rc = -EPERM; | 763 | rc = -EPERM; |
722 | /* | 764 | /* |
@@ -773,6 +815,12 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
773 | isp->smk_task = nsp; | 815 | isp->smk_task = nsp; |
774 | else | 816 | else |
775 | isp->smk_task = smack_known_invalid.smk_known; | 817 | isp->smk_task = smack_known_invalid.smk_known; |
818 | } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | ||
819 | nsp = smk_import(value, size); | ||
820 | if (nsp != NULL) | ||
821 | isp->smk_mmap = nsp; | ||
822 | else | ||
823 | isp->smk_mmap = smack_known_invalid.smk_known; | ||
776 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) | 824 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) |
777 | isp->smk_flags |= SMK_INODE_TRANSMUTE; | 825 | isp->smk_flags |= SMK_INODE_TRANSMUTE; |
778 | 826 | ||
@@ -815,7 +863,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
815 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || | 863 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || |
816 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || | 864 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || |
817 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || | 865 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || |
818 | strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 866 | strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || |
867 | strcmp(name, XATTR_NAME_SMACKMMAP)) { | ||
819 | if (!capable(CAP_MAC_ADMIN)) | 868 | if (!capable(CAP_MAC_ADMIN)) |
820 | rc = -EPERM; | 869 | rc = -EPERM; |
821 | } else | 870 | } else |
@@ -829,6 +878,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
829 | if (rc == 0) { | 878 | if (rc == 0) { |
830 | isp = dentry->d_inode->i_security; | 879 | isp = dentry->d_inode->i_security; |
831 | isp->smk_task = NULL; | 880 | isp->smk_task = NULL; |
881 | isp->smk_mmap = NULL; | ||
832 | } | 882 | } |
833 | 883 | ||
834 | return rc; | 884 | return rc; |
@@ -1060,6 +1110,113 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, | |||
1060 | } | 1110 | } |
1061 | 1111 | ||
1062 | /** | 1112 | /** |
1113 | * smk_mmap_list_check - the mmap check | ||
1114 | * @sub: subject label | ||
1115 | * @obj: object label | ||
1116 | * @access: access mode | ||
1117 | * @local: the task specific rule list | ||
1118 | * | ||
1119 | * Returns 0 if acces is permitted, -EACCES otherwise | ||
1120 | */ | ||
1121 | static int smk_mmap_list_check(char *sub, char *obj, int access, | ||
1122 | struct list_head *local) | ||
1123 | { | ||
1124 | int may; | ||
1125 | |||
1126 | /* | ||
1127 | * If there is not a global rule that | ||
1128 | * allows access say no. | ||
1129 | */ | ||
1130 | may = smk_access_entry(sub, obj, &smack_rule_list); | ||
1131 | if (may == -ENOENT || (may & access) != access) | ||
1132 | return -EACCES; | ||
1133 | /* | ||
1134 | * If there is a task local rule that | ||
1135 | * denies access say no. | ||
1136 | */ | ||
1137 | may = smk_access_entry(sub, obj, local); | ||
1138 | if (may != -ENOENT && (may & access) != access) | ||
1139 | return -EACCES; | ||
1140 | |||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | /** | ||
1145 | * smack_file_mmap : | ||
1146 | * Check permissions for a mmap operation. The @file may be NULL, e.g. | ||
1147 | * if mapping anonymous memory. | ||
1148 | * @file contains the file structure for file to map (may be NULL). | ||
1149 | * @reqprot contains the protection requested by the application. | ||
1150 | * @prot contains the protection that will be applied by the kernel. | ||
1151 | * @flags contains the operational flags. | ||
1152 | * Return 0 if permission is granted. | ||
1153 | */ | ||
1154 | static int smack_file_mmap(struct file *file, | ||
1155 | unsigned long reqprot, unsigned long prot, | ||
1156 | unsigned long flags, unsigned long addr, | ||
1157 | unsigned long addr_only) | ||
1158 | { | ||
1159 | struct smack_rule *srp; | ||
1160 | struct task_smack *tsp; | ||
1161 | char *sp; | ||
1162 | char *msmack; | ||
1163 | struct inode_smack *isp; | ||
1164 | struct dentry *dp; | ||
1165 | int rc; | ||
1166 | |||
1167 | /* do DAC check on address space usage */ | ||
1168 | rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); | ||
1169 | if (rc || addr_only) | ||
1170 | return rc; | ||
1171 | |||
1172 | if (file == NULL || file->f_dentry == NULL) | ||
1173 | return 0; | ||
1174 | |||
1175 | dp = file->f_dentry; | ||
1176 | |||
1177 | if (dp->d_inode == NULL) | ||
1178 | return 0; | ||
1179 | |||
1180 | isp = dp->d_inode->i_security; | ||
1181 | if (isp->smk_mmap == NULL) | ||
1182 | return 0; | ||
1183 | msmack = isp->smk_mmap; | ||
1184 | |||
1185 | tsp = current_security(); | ||
1186 | sp = smk_of_current(); | ||
1187 | rc = 0; | ||
1188 | |||
1189 | rcu_read_lock(); | ||
1190 | /* | ||
1191 | * For each Smack rule associated with the subject | ||
1192 | * label verify that the SMACK64MMAP also has access | ||
1193 | * to that rule's object label. | ||
1194 | * | ||
1195 | * Because neither of the labels comes | ||
1196 | * from the networking code it is sufficient | ||
1197 | * to compare pointers. | ||
1198 | */ | ||
1199 | list_for_each_entry_rcu(srp, &smack_rule_list, list) { | ||
1200 | if (srp->smk_subject != sp) | ||
1201 | continue; | ||
1202 | /* | ||
1203 | * Matching labels always allows access. | ||
1204 | */ | ||
1205 | if (msmack == srp->smk_object) | ||
1206 | continue; | ||
1207 | |||
1208 | rc = smk_mmap_list_check(msmack, srp->smk_object, | ||
1209 | srp->smk_access, &tsp->smk_rules); | ||
1210 | if (rc != 0) | ||
1211 | break; | ||
1212 | } | ||
1213 | |||
1214 | rcu_read_unlock(); | ||
1215 | |||
1216 | return rc; | ||
1217 | } | ||
1218 | |||
1219 | /** | ||
1063 | * smack_file_set_fowner - set the file security blob value | 1220 | * smack_file_set_fowner - set the file security blob value |
1064 | * @file: object in question | 1221 | * @file: object in question |
1065 | * | 1222 | * |
@@ -1095,6 +1252,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, | |||
1095 | * struct fown_struct is never outside the context of a struct file | 1252 | * struct fown_struct is never outside the context of a struct file |
1096 | */ | 1253 | */ |
1097 | file = container_of(fown, struct file, f_owner); | 1254 | file = container_of(fown, struct file, f_owner); |
1255 | |||
1098 | /* we don't log here as rc can be overriden */ | 1256 | /* we don't log here as rc can be overriden */ |
1099 | rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); | 1257 | rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); |
1100 | if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) | 1258 | if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) |
@@ -1145,9 +1303,14 @@ static int smack_file_receive(struct file *file) | |||
1145 | */ | 1303 | */ |
1146 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | 1304 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) |
1147 | { | 1305 | { |
1148 | cred->security = kzalloc(sizeof(struct task_smack), gfp); | 1306 | struct task_smack *tsp; |
1149 | if (cred->security == NULL) | 1307 | |
1308 | tsp = new_task_smack(NULL, NULL, gfp); | ||
1309 | if (tsp == NULL) | ||
1150 | return -ENOMEM; | 1310 | return -ENOMEM; |
1311 | |||
1312 | cred->security = tsp; | ||
1313 | |||
1151 | return 0; | 1314 | return 0; |
1152 | } | 1315 | } |
1153 | 1316 | ||
@@ -1156,13 +1319,24 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | |||
1156 | * smack_cred_free - "free" task-level security credentials | 1319 | * smack_cred_free - "free" task-level security credentials |
1157 | * @cred: the credentials in question | 1320 | * @cred: the credentials in question |
1158 | * | 1321 | * |
1159 | * Smack isn't using copies of blobs. Everyone | ||
1160 | * points to an immutable list. The blobs never go away. | ||
1161 | * There is no leak here. | ||
1162 | */ | 1322 | */ |
1163 | static void smack_cred_free(struct cred *cred) | 1323 | static void smack_cred_free(struct cred *cred) |
1164 | { | 1324 | { |
1165 | kfree(cred->security); | 1325 | struct task_smack *tsp = cred->security; |
1326 | struct smack_rule *rp; | ||
1327 | struct list_head *l; | ||
1328 | struct list_head *n; | ||
1329 | |||
1330 | if (tsp == NULL) | ||
1331 | return; | ||
1332 | cred->security = NULL; | ||
1333 | |||
1334 | list_for_each_safe(l, n, &tsp->smk_rules) { | ||
1335 | rp = list_entry(l, struct smack_rule, list); | ||
1336 | list_del(&rp->list); | ||
1337 | kfree(rp); | ||
1338 | } | ||
1339 | kfree(tsp); | ||
1166 | } | 1340 | } |
1167 | 1341 | ||
1168 | /** | 1342 | /** |
@@ -1178,13 +1352,16 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, | |||
1178 | { | 1352 | { |
1179 | struct task_smack *old_tsp = old->security; | 1353 | struct task_smack *old_tsp = old->security; |
1180 | struct task_smack *new_tsp; | 1354 | struct task_smack *new_tsp; |
1355 | int rc; | ||
1181 | 1356 | ||
1182 | new_tsp = kzalloc(sizeof(struct task_smack), gfp); | 1357 | new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp); |
1183 | if (new_tsp == NULL) | 1358 | if (new_tsp == NULL) |
1184 | return -ENOMEM; | 1359 | return -ENOMEM; |
1185 | 1360 | ||
1186 | new_tsp->smk_task = old_tsp->smk_task; | 1361 | rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); |
1187 | new_tsp->smk_forked = old_tsp->smk_task; | 1362 | if (rc != 0) |
1363 | return rc; | ||
1364 | |||
1188 | new->security = new_tsp; | 1365 | new->security = new_tsp; |
1189 | return 0; | 1366 | return 0; |
1190 | } | 1367 | } |
@@ -1203,6 +1380,11 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) | |||
1203 | 1380 | ||
1204 | new_tsp->smk_task = old_tsp->smk_task; | 1381 | new_tsp->smk_task = old_tsp->smk_task; |
1205 | new_tsp->smk_forked = old_tsp->smk_task; | 1382 | new_tsp->smk_forked = old_tsp->smk_task; |
1383 | mutex_init(&new_tsp->smk_rules_lock); | ||
1384 | INIT_LIST_HEAD(&new_tsp->smk_rules); | ||
1385 | |||
1386 | |||
1387 | /* cbs copy rule list */ | ||
1206 | } | 1388 | } |
1207 | 1389 | ||
1208 | /** | 1390 | /** |
@@ -2419,6 +2601,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2419 | } | 2601 | } |
2420 | } | 2602 | } |
2421 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 2603 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); |
2604 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | ||
2422 | 2605 | ||
2423 | dput(dp); | 2606 | dput(dp); |
2424 | break; | 2607 | break; |
@@ -2478,6 +2661,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) | |||
2478 | static int smack_setprocattr(struct task_struct *p, char *name, | 2661 | static int smack_setprocattr(struct task_struct *p, char *name, |
2479 | void *value, size_t size) | 2662 | void *value, size_t size) |
2480 | { | 2663 | { |
2664 | int rc; | ||
2481 | struct task_smack *tsp; | 2665 | struct task_smack *tsp; |
2482 | struct task_smack *oldtsp; | 2666 | struct task_smack *oldtsp; |
2483 | struct cred *new; | 2667 | struct cred *new; |
@@ -2513,13 +2697,16 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2513 | new = prepare_creds(); | 2697 | new = prepare_creds(); |
2514 | if (new == NULL) | 2698 | if (new == NULL) |
2515 | return -ENOMEM; | 2699 | return -ENOMEM; |
2516 | tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL); | 2700 | |
2701 | tsp = new_task_smack(newsmack, oldtsp->smk_forked, GFP_KERNEL); | ||
2517 | if (tsp == NULL) { | 2702 | if (tsp == NULL) { |
2518 | kfree(new); | 2703 | kfree(new); |
2519 | return -ENOMEM; | 2704 | return -ENOMEM; |
2520 | } | 2705 | } |
2521 | tsp->smk_task = newsmack; | 2706 | rc = smk_copy_rules(&tsp->smk_rules, &oldtsp->smk_rules, GFP_KERNEL); |
2522 | tsp->smk_forked = oldtsp->smk_forked; | 2707 | if (rc != 0) |
2708 | return rc; | ||
2709 | |||
2523 | new->security = tsp; | 2710 | new->security = tsp; |
2524 | commit_creds(new); | 2711 | commit_creds(new); |
2525 | return size; | 2712 | return size; |
@@ -3221,6 +3408,7 @@ struct security_operations smack_ops = { | |||
3221 | .file_ioctl = smack_file_ioctl, | 3408 | .file_ioctl = smack_file_ioctl, |
3222 | .file_lock = smack_file_lock, | 3409 | .file_lock = smack_file_lock, |
3223 | .file_fcntl = smack_file_fcntl, | 3410 | .file_fcntl = smack_file_fcntl, |
3411 | .file_mmap = smack_file_mmap, | ||
3224 | .file_set_fowner = smack_file_set_fowner, | 3412 | .file_set_fowner = smack_file_set_fowner, |
3225 | .file_send_sigiotask = smack_file_send_sigiotask, | 3413 | .file_send_sigiotask = smack_file_send_sigiotask, |
3226 | .file_receive = smack_file_receive, | 3414 | .file_receive = smack_file_receive, |
@@ -3334,23 +3522,20 @@ static __init int smack_init(void) | |||
3334 | struct cred *cred; | 3522 | struct cred *cred; |
3335 | struct task_smack *tsp; | 3523 | struct task_smack *tsp; |
3336 | 3524 | ||
3337 | tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL); | 3525 | if (!security_module_enable(&smack_ops)) |
3526 | return 0; | ||
3527 | |||
3528 | tsp = new_task_smack(smack_known_floor.smk_known, | ||
3529 | smack_known_floor.smk_known, GFP_KERNEL); | ||
3338 | if (tsp == NULL) | 3530 | if (tsp == NULL) |
3339 | return -ENOMEM; | 3531 | return -ENOMEM; |
3340 | 3532 | ||
3341 | if (!security_module_enable(&smack_ops)) { | ||
3342 | kfree(tsp); | ||
3343 | return 0; | ||
3344 | } | ||
3345 | |||
3346 | printk(KERN_INFO "Smack: Initializing.\n"); | 3533 | printk(KERN_INFO "Smack: Initializing.\n"); |
3347 | 3534 | ||
3348 | /* | 3535 | /* |
3349 | * Set the security state for the initial task. | 3536 | * Set the security state for the initial task. |
3350 | */ | 3537 | */ |
3351 | cred = (struct cred *) current->cred; | 3538 | cred = (struct cred *) current->cred; |
3352 | tsp->smk_forked = smack_known_floor.smk_known; | ||
3353 | tsp->smk_task = smack_known_floor.smk_known; | ||
3354 | cred->security = tsp; | 3539 | cred->security = tsp; |
3355 | 3540 | ||
3356 | /* initialize the smack_know_list */ | 3541 | /* initialize the smack_know_list */ |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 362d5eda948b..90d1bbaaa6f3 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -43,6 +43,7 @@ enum smk_inos { | |||
43 | SMK_NETLBLADDR = 8, /* single label hosts */ | 43 | SMK_NETLBLADDR = 8, /* single label hosts */ |
44 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 44 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
45 | SMK_LOGGING = 10, /* logging */ | 45 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | ||
46 | }; | 47 | }; |
47 | 48 | ||
48 | /* | 49 | /* |
@@ -135,104 +136,30 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) | |||
135 | #define SMK_NETLBLADDRMIN 9 | 136 | #define SMK_NETLBLADDRMIN 9 |
136 | #define SMK_NETLBLADDRMAX 42 | 137 | #define SMK_NETLBLADDRMAX 42 |
137 | 138 | ||
138 | /* | ||
139 | * Seq_file read operations for /smack/load | ||
140 | */ | ||
141 | |||
142 | static void *load_seq_start(struct seq_file *s, loff_t *pos) | ||
143 | { | ||
144 | if (*pos == SEQ_READ_FINISHED) | ||
145 | return NULL; | ||
146 | if (list_empty(&smack_rule_list)) | ||
147 | return NULL; | ||
148 | return smack_rule_list.next; | ||
149 | } | ||
150 | |||
151 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
152 | { | ||
153 | struct list_head *list = v; | ||
154 | |||
155 | if (list_is_last(list, &smack_rule_list)) { | ||
156 | *pos = SEQ_READ_FINISHED; | ||
157 | return NULL; | ||
158 | } | ||
159 | return list->next; | ||
160 | } | ||
161 | |||
162 | static int load_seq_show(struct seq_file *s, void *v) | ||
163 | { | ||
164 | struct list_head *list = v; | ||
165 | struct smack_rule *srp = | ||
166 | list_entry(list, struct smack_rule, list); | ||
167 | |||
168 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | ||
169 | (char *)srp->smk_object); | ||
170 | |||
171 | seq_putc(s, ' '); | ||
172 | |||
173 | if (srp->smk_access & MAY_READ) | ||
174 | seq_putc(s, 'r'); | ||
175 | if (srp->smk_access & MAY_WRITE) | ||
176 | seq_putc(s, 'w'); | ||
177 | if (srp->smk_access & MAY_EXEC) | ||
178 | seq_putc(s, 'x'); | ||
179 | if (srp->smk_access & MAY_APPEND) | ||
180 | seq_putc(s, 'a'); | ||
181 | if (srp->smk_access & MAY_TRANSMUTE) | ||
182 | seq_putc(s, 't'); | ||
183 | if (srp->smk_access == 0) | ||
184 | seq_putc(s, '-'); | ||
185 | |||
186 | seq_putc(s, '\n'); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static void load_seq_stop(struct seq_file *s, void *v) | ||
192 | { | ||
193 | /* No-op */ | ||
194 | } | ||
195 | |||
196 | static const struct seq_operations load_seq_ops = { | ||
197 | .start = load_seq_start, | ||
198 | .next = load_seq_next, | ||
199 | .show = load_seq_show, | ||
200 | .stop = load_seq_stop, | ||
201 | }; | ||
202 | |||
203 | /** | ||
204 | * smk_open_load - open() for /smack/load | ||
205 | * @inode: inode structure representing file | ||
206 | * @file: "load" file pointer | ||
207 | * | ||
208 | * For reading, use load_seq_* seq_file reading operations. | ||
209 | */ | ||
210 | static int smk_open_load(struct inode *inode, struct file *file) | ||
211 | { | ||
212 | return seq_open(file, &load_seq_ops); | ||
213 | } | ||
214 | |||
215 | /** | 139 | /** |
216 | * smk_set_access - add a rule to the rule list | 140 | * smk_set_access - add a rule to the rule list |
217 | * @srp: the new rule to add | 141 | * @srp: the new rule to add |
142 | * @rule_list: the list of rules | ||
143 | * @rule_lock: the rule list lock | ||
218 | * | 144 | * |
219 | * Looks through the current subject/object/access list for | 145 | * Looks through the current subject/object/access list for |
220 | * the subject/object pair and replaces the access that was | 146 | * the subject/object pair and replaces the access that was |
221 | * there. If the pair isn't found add it with the specified | 147 | * there. If the pair isn't found add it with the specified |
222 | * access. | 148 | * access. |
223 | * | 149 | * |
150 | * Returns 1 if a rule was found to exist already, 0 if it is new | ||
224 | * Returns 0 if nothing goes wrong or -ENOMEM if it fails | 151 | * Returns 0 if nothing goes wrong or -ENOMEM if it fails |
225 | * during the allocation of the new pair to add. | 152 | * during the allocation of the new pair to add. |
226 | */ | 153 | */ |
227 | static int smk_set_access(struct smack_rule *srp) | 154 | static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, |
155 | struct mutex *rule_lock) | ||
228 | { | 156 | { |
229 | struct smack_rule *sp; | 157 | struct smack_rule *sp; |
230 | int ret = 0; | 158 | int found = 0; |
231 | int found; | ||
232 | mutex_lock(&smack_list_lock); | ||
233 | 159 | ||
234 | found = 0; | 160 | mutex_lock(rule_lock); |
235 | list_for_each_entry_rcu(sp, &smack_rule_list, list) { | 161 | |
162 | list_for_each_entry_rcu(sp, rule_list, list) { | ||
236 | if (sp->smk_subject == srp->smk_subject && | 163 | if (sp->smk_subject == srp->smk_subject && |
237 | sp->smk_object == srp->smk_object) { | 164 | sp->smk_object == srp->smk_object) { |
238 | found = 1; | 165 | found = 1; |
@@ -241,19 +168,21 @@ static int smk_set_access(struct smack_rule *srp) | |||
241 | } | 168 | } |
242 | } | 169 | } |
243 | if (found == 0) | 170 | if (found == 0) |
244 | list_add_rcu(&srp->list, &smack_rule_list); | 171 | list_add_rcu(&srp->list, rule_list); |
245 | 172 | ||
246 | mutex_unlock(&smack_list_lock); | 173 | mutex_unlock(rule_lock); |
247 | 174 | ||
248 | return ret; | 175 | return found; |
249 | } | 176 | } |
250 | 177 | ||
251 | /** | 178 | /** |
252 | * smk_write_load - write() for /smack/load | 179 | * smk_write_load_list - write() for any /smack/load |
253 | * @file: file pointer, not actually used | 180 | * @file: file pointer, not actually used |
254 | * @buf: where to get the data from | 181 | * @buf: where to get the data from |
255 | * @count: bytes sent | 182 | * @count: bytes sent |
256 | * @ppos: where to start - must be 0 | 183 | * @ppos: where to start - must be 0 |
184 | * @rule_list: the list of rules to write to | ||
185 | * @rule_lock: lock for the rule list | ||
257 | * | 186 | * |
258 | * Get one smack access rule from above. | 187 | * Get one smack access rule from above. |
259 | * The format is exactly: | 188 | * The format is exactly: |
@@ -263,21 +192,19 @@ static int smk_set_access(struct smack_rule *srp) | |||
263 | * | 192 | * |
264 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | 193 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. |
265 | */ | 194 | */ |
266 | static ssize_t smk_write_load(struct file *file, const char __user *buf, | 195 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, |
267 | size_t count, loff_t *ppos) | 196 | size_t count, loff_t *ppos, |
197 | struct list_head *rule_list, | ||
198 | struct mutex *rule_lock) | ||
268 | { | 199 | { |
269 | struct smack_rule *rule; | 200 | struct smack_rule *rule; |
270 | char *data; | 201 | char *data; |
271 | int rc = -EINVAL; | 202 | int rc = -EINVAL; |
272 | 203 | ||
273 | /* | 204 | /* |
274 | * Must have privilege. | ||
275 | * No partial writes. | 205 | * No partial writes. |
276 | * Enough data must be present. | 206 | * Enough data must be present. |
277 | */ | 207 | */ |
278 | if (!capable(CAP_MAC_ADMIN)) | ||
279 | return -EPERM; | ||
280 | |||
281 | if (*ppos != 0) | 208 | if (*ppos != 0) |
282 | return -EINVAL; | 209 | return -EINVAL; |
283 | /* | 210 | /* |
@@ -372,11 +299,13 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
372 | goto out_free_rule; | 299 | goto out_free_rule; |
373 | } | 300 | } |
374 | 301 | ||
375 | rc = smk_set_access(rule); | 302 | rc = count; |
376 | 303 | /* | |
377 | if (!rc) | 304 | * smk_set_access returns true if there was already a rule |
378 | rc = count; | 305 | * for the subject/object pair, and false if it was new. |
379 | goto out; | 306 | */ |
307 | if (!smk_set_access(rule, rule_list, rule_lock)) | ||
308 | goto out; | ||
380 | 309 | ||
381 | out_free_rule: | 310 | out_free_rule: |
382 | kfree(rule); | 311 | kfree(rule); |
@@ -385,6 +314,108 @@ out: | |||
385 | return rc; | 314 | return rc; |
386 | } | 315 | } |
387 | 316 | ||
317 | |||
318 | /* | ||
319 | * Seq_file read operations for /smack/load | ||
320 | */ | ||
321 | |||
322 | static void *load_seq_start(struct seq_file *s, loff_t *pos) | ||
323 | { | ||
324 | if (*pos == SEQ_READ_FINISHED) | ||
325 | return NULL; | ||
326 | if (list_empty(&smack_rule_list)) | ||
327 | return NULL; | ||
328 | return smack_rule_list.next; | ||
329 | } | ||
330 | |||
331 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
332 | { | ||
333 | struct list_head *list = v; | ||
334 | |||
335 | if (list_is_last(list, &smack_rule_list)) { | ||
336 | *pos = SEQ_READ_FINISHED; | ||
337 | return NULL; | ||
338 | } | ||
339 | return list->next; | ||
340 | } | ||
341 | |||
342 | static int load_seq_show(struct seq_file *s, void *v) | ||
343 | { | ||
344 | struct list_head *list = v; | ||
345 | struct smack_rule *srp = | ||
346 | list_entry(list, struct smack_rule, list); | ||
347 | |||
348 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | ||
349 | (char *)srp->smk_object); | ||
350 | |||
351 | seq_putc(s, ' '); | ||
352 | |||
353 | if (srp->smk_access & MAY_READ) | ||
354 | seq_putc(s, 'r'); | ||
355 | if (srp->smk_access & MAY_WRITE) | ||
356 | seq_putc(s, 'w'); | ||
357 | if (srp->smk_access & MAY_EXEC) | ||
358 | seq_putc(s, 'x'); | ||
359 | if (srp->smk_access & MAY_APPEND) | ||
360 | seq_putc(s, 'a'); | ||
361 | if (srp->smk_access & MAY_TRANSMUTE) | ||
362 | seq_putc(s, 't'); | ||
363 | if (srp->smk_access == 0) | ||
364 | seq_putc(s, '-'); | ||
365 | |||
366 | seq_putc(s, '\n'); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static void load_seq_stop(struct seq_file *s, void *v) | ||
372 | { | ||
373 | /* No-op */ | ||
374 | } | ||
375 | |||
376 | static const struct seq_operations load_seq_ops = { | ||
377 | .start = load_seq_start, | ||
378 | .next = load_seq_next, | ||
379 | .show = load_seq_show, | ||
380 | .stop = load_seq_stop, | ||
381 | }; | ||
382 | |||
383 | /** | ||
384 | * smk_open_load - open() for /smack/load | ||
385 | * @inode: inode structure representing file | ||
386 | * @file: "load" file pointer | ||
387 | * | ||
388 | * For reading, use load_seq_* seq_file reading operations. | ||
389 | */ | ||
390 | static int smk_open_load(struct inode *inode, struct file *file) | ||
391 | { | ||
392 | return seq_open(file, &load_seq_ops); | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * smk_write_load - write() for /smack/load | ||
397 | * @file: file pointer, not actually used | ||
398 | * @buf: where to get the data from | ||
399 | * @count: bytes sent | ||
400 | * @ppos: where to start - must be 0 | ||
401 | * | ||
402 | */ | ||
403 | static ssize_t smk_write_load(struct file *file, const char __user *buf, | ||
404 | size_t count, loff_t *ppos) | ||
405 | { | ||
406 | |||
407 | /* | ||
408 | * Must have privilege. | ||
409 | * No partial writes. | ||
410 | * Enough data must be present. | ||
411 | */ | ||
412 | if (!capable(CAP_MAC_ADMIN)) | ||
413 | return -EPERM; | ||
414 | |||
415 | return smk_write_load_list(file, buf, count, ppos, &smack_rule_list, | ||
416 | &smack_list_lock); | ||
417 | } | ||
418 | |||
388 | static const struct file_operations smk_load_ops = { | 419 | static const struct file_operations smk_load_ops = { |
389 | .open = smk_open_load, | 420 | .open = smk_open_load, |
390 | .read = seq_read, | 421 | .read = seq_read, |
@@ -1288,6 +1319,112 @@ static const struct file_operations smk_logging_ops = { | |||
1288 | .write = smk_write_logging, | 1319 | .write = smk_write_logging, |
1289 | .llseek = default_llseek, | 1320 | .llseek = default_llseek, |
1290 | }; | 1321 | }; |
1322 | |||
1323 | /* | ||
1324 | * Seq_file read operations for /smack/load-self | ||
1325 | */ | ||
1326 | |||
1327 | static void *load_self_seq_start(struct seq_file *s, loff_t *pos) | ||
1328 | { | ||
1329 | struct task_smack *tsp = current_security(); | ||
1330 | |||
1331 | if (*pos == SEQ_READ_FINISHED) | ||
1332 | return NULL; | ||
1333 | if (list_empty(&tsp->smk_rules)) | ||
1334 | return NULL; | ||
1335 | return tsp->smk_rules.next; | ||
1336 | } | ||
1337 | |||
1338 | static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1339 | { | ||
1340 | struct task_smack *tsp = current_security(); | ||
1341 | struct list_head *list = v; | ||
1342 | |||
1343 | if (list_is_last(list, &tsp->smk_rules)) { | ||
1344 | *pos = SEQ_READ_FINISHED; | ||
1345 | return NULL; | ||
1346 | } | ||
1347 | return list->next; | ||
1348 | } | ||
1349 | |||
1350 | static int load_self_seq_show(struct seq_file *s, void *v) | ||
1351 | { | ||
1352 | struct list_head *list = v; | ||
1353 | struct smack_rule *srp = | ||
1354 | list_entry(list, struct smack_rule, list); | ||
1355 | |||
1356 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | ||
1357 | (char *)srp->smk_object); | ||
1358 | |||
1359 | seq_putc(s, ' '); | ||
1360 | |||
1361 | if (srp->smk_access & MAY_READ) | ||
1362 | seq_putc(s, 'r'); | ||
1363 | if (srp->smk_access & MAY_WRITE) | ||
1364 | seq_putc(s, 'w'); | ||
1365 | if (srp->smk_access & MAY_EXEC) | ||
1366 | seq_putc(s, 'x'); | ||
1367 | if (srp->smk_access & MAY_APPEND) | ||
1368 | seq_putc(s, 'a'); | ||
1369 | if (srp->smk_access & MAY_TRANSMUTE) | ||
1370 | seq_putc(s, 't'); | ||
1371 | if (srp->smk_access == 0) | ||
1372 | seq_putc(s, '-'); | ||
1373 | |||
1374 | seq_putc(s, '\n'); | ||
1375 | |||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | static void load_self_seq_stop(struct seq_file *s, void *v) | ||
1380 | { | ||
1381 | /* No-op */ | ||
1382 | } | ||
1383 | |||
1384 | static const struct seq_operations load_self_seq_ops = { | ||
1385 | .start = load_self_seq_start, | ||
1386 | .next = load_self_seq_next, | ||
1387 | .show = load_self_seq_show, | ||
1388 | .stop = load_self_seq_stop, | ||
1389 | }; | ||
1390 | |||
1391 | |||
1392 | /** | ||
1393 | * smk_open_load_self - open() for /smack/load-self | ||
1394 | * @inode: inode structure representing file | ||
1395 | * @file: "load" file pointer | ||
1396 | * | ||
1397 | * For reading, use load_seq_* seq_file reading operations. | ||
1398 | */ | ||
1399 | static int smk_open_load_self(struct inode *inode, struct file *file) | ||
1400 | { | ||
1401 | return seq_open(file, &load_self_seq_ops); | ||
1402 | } | ||
1403 | |||
1404 | /** | ||
1405 | * smk_write_load_self - write() for /smack/load-self | ||
1406 | * @file: file pointer, not actually used | ||
1407 | * @buf: where to get the data from | ||
1408 | * @count: bytes sent | ||
1409 | * @ppos: where to start - must be 0 | ||
1410 | * | ||
1411 | */ | ||
1412 | static ssize_t smk_write_load_self(struct file *file, const char __user *buf, | ||
1413 | size_t count, loff_t *ppos) | ||
1414 | { | ||
1415 | struct task_smack *tsp = current_security(); | ||
1416 | |||
1417 | return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules, | ||
1418 | &tsp->smk_rules_lock); | ||
1419 | } | ||
1420 | |||
1421 | static const struct file_operations smk_load_self_ops = { | ||
1422 | .open = smk_open_load_self, | ||
1423 | .read = seq_read, | ||
1424 | .llseek = seq_lseek, | ||
1425 | .write = smk_write_load_self, | ||
1426 | .release = seq_release, | ||
1427 | }; | ||
1291 | /** | 1428 | /** |
1292 | * smk_fill_super - fill the /smackfs superblock | 1429 | * smk_fill_super - fill the /smackfs superblock |
1293 | * @sb: the empty superblock | 1430 | * @sb: the empty superblock |
@@ -1304,23 +1441,26 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1304 | struct inode *root_inode; | 1441 | struct inode *root_inode; |
1305 | 1442 | ||
1306 | static struct tree_descr smack_files[] = { | 1443 | static struct tree_descr smack_files[] = { |
1307 | [SMK_LOAD] = | 1444 | [SMK_LOAD] = { |
1308 | {"load", &smk_load_ops, S_IRUGO|S_IWUSR}, | 1445 | "load", &smk_load_ops, S_IRUGO|S_IWUSR}, |
1309 | [SMK_CIPSO] = | 1446 | [SMK_CIPSO] = { |
1310 | {"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR}, | 1447 | "cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR}, |
1311 | [SMK_DOI] = | 1448 | [SMK_DOI] = { |
1312 | {"doi", &smk_doi_ops, S_IRUGO|S_IWUSR}, | 1449 | "doi", &smk_doi_ops, S_IRUGO|S_IWUSR}, |
1313 | [SMK_DIRECT] = | 1450 | [SMK_DIRECT] = { |
1314 | {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, | 1451 | "direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, |
1315 | [SMK_AMBIENT] = | 1452 | [SMK_AMBIENT] = { |
1316 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 1453 | "ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
1317 | [SMK_NETLBLADDR] = | 1454 | [SMK_NETLBLADDR] = { |
1318 | {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, | 1455 | "netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, |
1319 | [SMK_ONLYCAP] = | 1456 | [SMK_ONLYCAP] = { |
1320 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | 1457 | "onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, |
1321 | [SMK_LOGGING] = | 1458 | [SMK_LOGGING] = { |
1322 | {"logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, | 1459 | "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, |
1323 | /* last one */ {""} | 1460 | [SMK_LOAD_SELF] = { |
1461 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | ||
1462 | /* last one */ | ||
1463 | {""} | ||
1324 | }; | 1464 | }; |
1325 | 1465 | ||
1326 | rc = simple_fill_super(sb, SMACK_MAGIC, smack_files); | 1466 | rc = simple_fill_super(sb, SMACK_MAGIC, smack_files); |