diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 12:15:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 12:15:43 -0400 |
commit | 0f6e0e8448a16d8d22119ce91d8dd24b44865b51 (patch) | |
tree | 7c295c02db035fc6a0b867465911a2bc9dc6b1ef /security/smack/smackfs.c | |
parent | 0d2ecee2bdb2a19d04bc5cefac0f86e790f1aad4 (diff) | |
parent | a002951c97ff8da49938c982a4c236bf2fafdc9f (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (33 commits)
AppArmor: kill unused macros in lsm.c
AppArmor: cleanup generated files correctly
KEYS: Add an iovec version of KEYCTL_INSTANTIATE
KEYS: Add a new keyctl op to reject a key with a specified error code
KEYS: Add a key type op to permit the key description to be vetted
KEYS: Add an RCU payload dereference macro
AppArmor: Cleanup make file to remove cruft and make it easier to read
SELinux: implement the new sb_remount LSM hook
LSM: Pass -o remount options to the LSM
SELinux: Compute SID for the newly created socket
SELinux: Socket retains creator role and MLS attribute
SELinux: Auto-generate security_is_socket_class
TOMOYO: Fix memory leak upon file open.
Revert "selinux: simplify ioctl checking"
selinux: drop unused packet flow permissions
selinux: Fix packet forwarding checks on postrouting
selinux: Fix wrong checks for selinux_policycap_netpeer
selinux: Fix check for xfrm selinux context algorithm
ima: remove unnecessary call to ima_must_measure
IMA: remove IMA imbalance checking
...
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r-- | security/smack/smackfs.c | 370 |
1 files changed, 255 insertions, 115 deletions
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); |