Commit b7b57551bbda1390959207f79f2038aa7adb72ae
Exists in
master
and in
39 other branches
Merge branch 'master' of git://git.infradead.org/users/eparis/selinux into for-linus
Conflicts: lib/flex_array.c security/selinux/avc.c security/selinux/hooks.c security/selinux/ss/policydb.c security/smack/smack_lsm.c Manually resolve conflicts. Signed-off-by: James Morris <jmorris@namei.org>
Showing 14 changed files Side-by-side Diff
- MAINTAINERS
- include/linux/lsm_audit.h
- lib/flex_array.c
- security/lsm_audit.c
- security/selinux/avc.c
- security/selinux/hooks.c
- security/selinux/include/security.h
- security/selinux/netnode.c
- security/selinux/selinuxfs.c
- security/selinux/ss/policydb.c
- security/selinux/ss/policydb.h
- security/selinux/ss/services.c
- security/smack/smack.h
- security/smack/smack_lsm.c
MAINTAINERS
... | ... | @@ -5592,10 +5592,11 @@ |
5592 | 5592 | M: Eric Paris <eparis@parisplace.org> |
5593 | 5593 | L: selinux@tycho.nsa.gov (subscribers-only, general discussion) |
5594 | 5594 | W: http://selinuxproject.org |
5595 | -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git | |
5595 | +T: git git://git.infradead.org/users/eparis/selinux.git | |
5596 | 5596 | S: Supported |
5597 | 5597 | F: include/linux/selinux* |
5598 | 5598 | F: security/selinux/ |
5599 | +F: scripts/selinux/ | |
5599 | 5600 | |
5600 | 5601 | APPARMOR SECURITY MODULE |
5601 | 5602 | M: John Johansen <john.johansen@canonical.com> |
include/linux/lsm_audit.h
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | /* Auxiliary data to use in generating the audit record. */ |
28 | 28 | struct common_audit_data { |
29 | 29 | char type; |
30 | -#define LSM_AUDIT_DATA_FS 1 | |
30 | +#define LSM_AUDIT_DATA_PATH 1 | |
31 | 31 | #define LSM_AUDIT_DATA_NET 2 |
32 | 32 | #define LSM_AUDIT_DATA_CAP 3 |
33 | 33 | #define LSM_AUDIT_DATA_IPC 4 |
34 | 34 | |
... | ... | @@ -35,12 +35,13 @@ |
35 | 35 | #define LSM_AUDIT_DATA_KEY 6 |
36 | 36 | #define LSM_AUDIT_DATA_NONE 7 |
37 | 37 | #define LSM_AUDIT_DATA_KMOD 8 |
38 | +#define LSM_AUDIT_DATA_INODE 9 | |
39 | +#define LSM_AUDIT_DATA_DENTRY 10 | |
38 | 40 | struct task_struct *tsk; |
39 | 41 | union { |
40 | - struct { | |
41 | - struct path path; | |
42 | - struct inode *inode; | |
43 | - } fs; | |
42 | + struct path path; | |
43 | + struct dentry *dentry; | |
44 | + struct inode *inode; | |
44 | 45 | struct { |
45 | 46 | int netif; |
46 | 47 | struct sock *sk; |
lib/flex_array.c
... | ... | @@ -88,9 +88,12 @@ |
88 | 88 | gfp_t flags) |
89 | 89 | { |
90 | 90 | struct flex_array *ret; |
91 | - int max_size = FLEX_ARRAY_NR_BASE_PTRS * | |
92 | - FLEX_ARRAY_ELEMENTS_PER_PART(element_size); | |
91 | + int max_size = 0; | |
93 | 92 | |
93 | + if (element_size) | |
94 | + max_size = FLEX_ARRAY_NR_BASE_PTRS * | |
95 | + FLEX_ARRAY_ELEMENTS_PER_PART(element_size); | |
96 | + | |
94 | 97 | /* max_size will end up 0 if element_size > PAGE_SIZE */ |
95 | 98 | if (total > max_size) |
96 | 99 | return NULL; |
97 | 100 | |
98 | 101 | |
... | ... | @@ -183,15 +186,18 @@ |
183 | 186 | int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, |
184 | 187 | gfp_t flags) |
185 | 188 | { |
186 | - int part_nr = fa_element_to_part_nr(fa, element_nr); | |
189 | + int part_nr; | |
187 | 190 | struct flex_array_part *part; |
188 | 191 | void *dst; |
189 | 192 | |
190 | 193 | if (element_nr >= fa->total_nr_elements) |
191 | 194 | return -ENOSPC; |
195 | + if (!fa->element_size) | |
196 | + return 0; | |
192 | 197 | if (elements_fit_in_base(fa)) |
193 | 198 | part = (struct flex_array_part *)&fa->parts[0]; |
194 | 199 | else { |
200 | + part_nr = fa_element_to_part_nr(fa, element_nr); | |
195 | 201 | part = __fa_get_part(fa, part_nr, flags); |
196 | 202 | if (!part) |
197 | 203 | return -ENOMEM; |
198 | 204 | |
199 | 205 | |
... | ... | @@ -211,15 +217,18 @@ |
211 | 217 | */ |
212 | 218 | int flex_array_clear(struct flex_array *fa, unsigned int element_nr) |
213 | 219 | { |
214 | - int part_nr = fa_element_to_part_nr(fa, element_nr); | |
220 | + int part_nr; | |
215 | 221 | struct flex_array_part *part; |
216 | 222 | void *dst; |
217 | 223 | |
218 | 224 | if (element_nr >= fa->total_nr_elements) |
219 | 225 | return -ENOSPC; |
226 | + if (!fa->element_size) | |
227 | + return 0; | |
220 | 228 | if (elements_fit_in_base(fa)) |
221 | 229 | part = (struct flex_array_part *)&fa->parts[0]; |
222 | 230 | else { |
231 | + part_nr = fa_element_to_part_nr(fa, element_nr); | |
223 | 232 | part = fa->parts[part_nr]; |
224 | 233 | if (!part) |
225 | 234 | return -EINVAL; |
... | ... | @@ -264,6 +273,8 @@ |
264 | 273 | |
265 | 274 | if (end >= fa->total_nr_elements) |
266 | 275 | return -ENOSPC; |
276 | + if (!fa->element_size) | |
277 | + return 0; | |
267 | 278 | if (elements_fit_in_base(fa)) |
268 | 279 | return 0; |
269 | 280 | start_part = fa_element_to_part_nr(fa, start); |
270 | 281 | |
271 | 282 | |
... | ... | @@ -291,14 +302,17 @@ |
291 | 302 | */ |
292 | 303 | void *flex_array_get(struct flex_array *fa, unsigned int element_nr) |
293 | 304 | { |
294 | - int part_nr = fa_element_to_part_nr(fa, element_nr); | |
305 | + int part_nr; | |
295 | 306 | struct flex_array_part *part; |
296 | 307 | |
308 | + if (!fa->element_size) | |
309 | + return NULL; | |
297 | 310 | if (element_nr >= fa->total_nr_elements) |
298 | 311 | return NULL; |
299 | 312 | if (elements_fit_in_base(fa)) |
300 | 313 | part = (struct flex_array_part *)&fa->parts[0]; |
301 | 314 | else { |
315 | + part_nr = fa_element_to_part_nr(fa, element_nr); | |
302 | 316 | part = fa->parts[part_nr]; |
303 | 317 | if (!part) |
304 | 318 | return NULL; |
... | ... | @@ -353,7 +367,7 @@ |
353 | 367 | int part_nr; |
354 | 368 | int ret = 0; |
355 | 369 | |
356 | - if (!fa->total_nr_elements) | |
370 | + if (!fa->total_nr_elements || !fa->element_size) | |
357 | 371 | return 0; |
358 | 372 | if (elements_fit_in_base(fa)) |
359 | 373 | return ret; |
security/lsm_audit.c
... | ... | @@ -210,7 +210,6 @@ |
210 | 210 | static void dump_common_audit_data(struct audit_buffer *ab, |
211 | 211 | struct common_audit_data *a) |
212 | 212 | { |
213 | - struct inode *inode = NULL; | |
214 | 213 | struct task_struct *tsk = current; |
215 | 214 | |
216 | 215 | if (a->tsk) |
217 | 216 | |
... | ... | @@ -229,33 +228,47 @@ |
229 | 228 | case LSM_AUDIT_DATA_CAP: |
230 | 229 | audit_log_format(ab, " capability=%d ", a->u.cap); |
231 | 230 | break; |
232 | - case LSM_AUDIT_DATA_FS: | |
233 | - if (a->u.fs.path.dentry) { | |
234 | - struct dentry *dentry = a->u.fs.path.dentry; | |
235 | - if (a->u.fs.path.mnt) { | |
236 | - audit_log_d_path(ab, "path=", &a->u.fs.path); | |
237 | - } else { | |
238 | - audit_log_format(ab, " name="); | |
239 | - audit_log_untrustedstring(ab, | |
240 | - dentry->d_name.name); | |
241 | - } | |
242 | - inode = dentry->d_inode; | |
243 | - } else if (a->u.fs.inode) { | |
244 | - struct dentry *dentry; | |
245 | - inode = a->u.fs.inode; | |
246 | - dentry = d_find_alias(inode); | |
247 | - if (dentry) { | |
248 | - audit_log_format(ab, " name="); | |
249 | - audit_log_untrustedstring(ab, | |
250 | - dentry->d_name.name); | |
251 | - dput(dentry); | |
252 | - } | |
253 | - } | |
231 | + case LSM_AUDIT_DATA_PATH: { | |
232 | + struct inode *inode; | |
233 | + | |
234 | + audit_log_d_path(ab, "path=", &a->u.path); | |
235 | + | |
236 | + inode = a->u.path.dentry->d_inode; | |
254 | 237 | if (inode) |
255 | 238 | audit_log_format(ab, " dev=%s ino=%lu", |
256 | 239 | inode->i_sb->s_id, |
257 | 240 | inode->i_ino); |
258 | 241 | break; |
242 | + } | |
243 | + case LSM_AUDIT_DATA_DENTRY: { | |
244 | + struct inode *inode; | |
245 | + | |
246 | + audit_log_format(ab, " name="); | |
247 | + audit_log_untrustedstring(ab, a->u.dentry->d_name.name); | |
248 | + | |
249 | + inode = a->u.dentry->d_inode; | |
250 | + if (inode) | |
251 | + audit_log_format(ab, " dev=%s ino=%lu", | |
252 | + inode->i_sb->s_id, | |
253 | + inode->i_ino); | |
254 | + break; | |
255 | + } | |
256 | + case LSM_AUDIT_DATA_INODE: { | |
257 | + struct dentry *dentry; | |
258 | + struct inode *inode; | |
259 | + | |
260 | + inode = a->u.inode; | |
261 | + dentry = d_find_alias(inode); | |
262 | + if (dentry) { | |
263 | + audit_log_format(ab, " name="); | |
264 | + audit_log_untrustedstring(ab, | |
265 | + dentry->d_name.name); | |
266 | + dput(dentry); | |
267 | + } | |
268 | + audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id, | |
269 | + inode->i_ino); | |
270 | + break; | |
271 | + } | |
259 | 272 | case LSM_AUDIT_DATA_TASK: |
260 | 273 | tsk = a->u.tsk; |
261 | 274 | if (tsk && tsk->pid) { |
security/selinux/avc.c
... | ... | @@ -526,7 +526,7 @@ |
526 | 526 | * during retry. However this is logically just as if the operation |
527 | 527 | * happened a little later. |
528 | 528 | */ |
529 | - if ((a->type == LSM_AUDIT_DATA_FS) && | |
529 | + if ((a->type == LSM_AUDIT_DATA_INODE) && | |
530 | 530 | (flags & IPERM_FLAG_RCU)) |
531 | 531 | return -ECHILD; |
532 | 532 |
security/selinux/hooks.c
... | ... | @@ -990,6 +990,7 @@ |
990 | 990 | continue; |
991 | 991 | default: |
992 | 992 | BUG(); |
993 | + return; | |
993 | 994 | }; |
994 | 995 | /* we need a comma before each option */ |
995 | 996 | seq_putc(m, ','); |
... | ... | @@ -1443,6 +1444,7 @@ |
1443 | 1444 | printk(KERN_ERR |
1444 | 1445 | "SELinux: out of range capability %d\n", cap); |
1445 | 1446 | BUG(); |
1447 | + return -EINVAL; | |
1446 | 1448 | } |
1447 | 1449 | |
1448 | 1450 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); |
... | ... | @@ -1487,8 +1489,8 @@ |
1487 | 1489 | |
1488 | 1490 | if (!adp) { |
1489 | 1491 | adp = &ad; |
1490 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1491 | - ad.u.fs.inode = inode; | |
1492 | + COMMON_AUDIT_DATA_INIT(&ad, INODE); | |
1493 | + ad.u.inode = inode; | |
1492 | 1494 | } |
1493 | 1495 | |
1494 | 1496 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
1495 | 1497 | |
1496 | 1498 | |
... | ... | @@ -1498,19 +1500,32 @@ |
1498 | 1500 | the dentry to help the auditing code to more easily generate the |
1499 | 1501 | pathname if needed. */ |
1500 | 1502 | static inline int dentry_has_perm(const struct cred *cred, |
1501 | - struct vfsmount *mnt, | |
1502 | 1503 | struct dentry *dentry, |
1503 | 1504 | u32 av) |
1504 | 1505 | { |
1505 | 1506 | struct inode *inode = dentry->d_inode; |
1506 | 1507 | struct common_audit_data ad; |
1507 | 1508 | |
1508 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1509 | - ad.u.fs.path.mnt = mnt; | |
1510 | - ad.u.fs.path.dentry = dentry; | |
1509 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
1510 | + ad.u.dentry = dentry; | |
1511 | 1511 | return inode_has_perm(cred, inode, av, &ad, 0); |
1512 | 1512 | } |
1513 | 1513 | |
1514 | +/* Same as inode_has_perm, but pass explicit audit data containing | |
1515 | + the path to help the auditing code to more easily generate the | |
1516 | + pathname if needed. */ | |
1517 | +static inline int path_has_perm(const struct cred *cred, | |
1518 | + struct path *path, | |
1519 | + u32 av) | |
1520 | +{ | |
1521 | + struct inode *inode = path->dentry->d_inode; | |
1522 | + struct common_audit_data ad; | |
1523 | + | |
1524 | + COMMON_AUDIT_DATA_INIT(&ad, PATH); | |
1525 | + ad.u.path = *path; | |
1526 | + return inode_has_perm(cred, inode, av, &ad, 0); | |
1527 | +} | |
1528 | + | |
1514 | 1529 | /* Check whether a task can use an open file descriptor to |
1515 | 1530 | access an inode in a given way. Check access to the |
1516 | 1531 | descriptor itself, and then use dentry_has_perm to |
... | ... | @@ -1529,8 +1544,8 @@ |
1529 | 1544 | u32 sid = cred_sid(cred); |
1530 | 1545 | int rc; |
1531 | 1546 | |
1532 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1533 | - ad.u.fs.path = file->f_path; | |
1547 | + COMMON_AUDIT_DATA_INIT(&ad, PATH); | |
1548 | + ad.u.path = file->f_path; | |
1534 | 1549 | |
1535 | 1550 | if (sid != fsec->sid) { |
1536 | 1551 | rc = avc_has_perm(sid, fsec->sid, |
... | ... | @@ -1568,8 +1583,8 @@ |
1568 | 1583 | sid = tsec->sid; |
1569 | 1584 | newsid = tsec->create_sid; |
1570 | 1585 | |
1571 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1572 | - ad.u.fs.path.dentry = dentry; | |
1586 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
1587 | + ad.u.dentry = dentry; | |
1573 | 1588 | |
1574 | 1589 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
1575 | 1590 | DIR__ADD_NAME | DIR__SEARCH, |
... | ... | @@ -1621,8 +1636,8 @@ |
1621 | 1636 | dsec = dir->i_security; |
1622 | 1637 | isec = dentry->d_inode->i_security; |
1623 | 1638 | |
1624 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1625 | - ad.u.fs.path.dentry = dentry; | |
1639 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
1640 | + ad.u.dentry = dentry; | |
1626 | 1641 | |
1627 | 1642 | av = DIR__SEARCH; |
1628 | 1643 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); |
1629 | 1644 | |
... | ... | @@ -1667,9 +1682,9 @@ |
1667 | 1682 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
1668 | 1683 | new_dsec = new_dir->i_security; |
1669 | 1684 | |
1670 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1685 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
1671 | 1686 | |
1672 | - ad.u.fs.path.dentry = old_dentry; | |
1687 | + ad.u.dentry = old_dentry; | |
1673 | 1688 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
1674 | 1689 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); |
1675 | 1690 | if (rc) |
... | ... | @@ -1685,7 +1700,7 @@ |
1685 | 1700 | return rc; |
1686 | 1701 | } |
1687 | 1702 | |
1688 | - ad.u.fs.path.dentry = new_dentry; | |
1703 | + ad.u.dentry = new_dentry; | |
1689 | 1704 | av = DIR__ADD_NAME | DIR__SEARCH; |
1690 | 1705 | if (new_dentry->d_inode) |
1691 | 1706 | av |= DIR__REMOVE_NAME; |
... | ... | @@ -1895,7 +1910,7 @@ |
1895 | 1910 | { |
1896 | 1911 | const struct cred *cred = current_cred(); |
1897 | 1912 | |
1898 | - return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); | |
1913 | + return dentry_has_perm(cred, dentry, FILE__QUOTAON); | |
1899 | 1914 | } |
1900 | 1915 | |
1901 | 1916 | static int selinux_syslog(int type) |
... | ... | @@ -1992,8 +2007,8 @@ |
1992 | 2007 | return rc; |
1993 | 2008 | } |
1994 | 2009 | |
1995 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
1996 | - ad.u.fs.path = bprm->file->f_path; | |
2010 | + COMMON_AUDIT_DATA_INIT(&ad, PATH); | |
2011 | + ad.u.path = bprm->file->f_path; | |
1997 | 2012 | |
1998 | 2013 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
1999 | 2014 | new_tsec->sid = old_tsec->sid; |
... | ... | @@ -2121,7 +2136,7 @@ |
2121 | 2136 | |
2122 | 2137 | /* Revalidate access to inherited open files. */ |
2123 | 2138 | |
2124 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
2139 | + COMMON_AUDIT_DATA_INIT(&ad, INODE); | |
2125 | 2140 | |
2126 | 2141 | spin_lock(&files->file_lock); |
2127 | 2142 | for (;;) { |
... | ... | @@ -2469,8 +2484,8 @@ |
2469 | 2484 | if (flags & MS_KERNMOUNT) |
2470 | 2485 | return 0; |
2471 | 2486 | |
2472 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
2473 | - ad.u.fs.path.dentry = sb->s_root; | |
2487 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
2488 | + ad.u.dentry = sb->s_root; | |
2474 | 2489 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
2475 | 2490 | } |
2476 | 2491 | |
... | ... | @@ -2479,8 +2494,8 @@ |
2479 | 2494 | const struct cred *cred = current_cred(); |
2480 | 2495 | struct common_audit_data ad; |
2481 | 2496 | |
2482 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
2483 | - ad.u.fs.path.dentry = dentry->d_sb->s_root; | |
2497 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
2498 | + ad.u.dentry = dentry->d_sb->s_root; | |
2484 | 2499 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
2485 | 2500 | } |
2486 | 2501 | |
... | ... | @@ -2496,8 +2511,7 @@ |
2496 | 2511 | return superblock_has_perm(cred, path->mnt->mnt_sb, |
2497 | 2512 | FILESYSTEM__REMOUNT, NULL); |
2498 | 2513 | else |
2499 | - return dentry_has_perm(cred, path->mnt, path->dentry, | |
2500 | - FILE__MOUNTON); | |
2514 | + return path_has_perm(cred, path, FILE__MOUNTON); | |
2501 | 2515 | } |
2502 | 2516 | |
2503 | 2517 | static int selinux_umount(struct vfsmount *mnt, int flags) |
2504 | 2518 | |
... | ... | @@ -2630,14 +2644,14 @@ |
2630 | 2644 | { |
2631 | 2645 | const struct cred *cred = current_cred(); |
2632 | 2646 | |
2633 | - return dentry_has_perm(cred, NULL, dentry, FILE__READ); | |
2647 | + return dentry_has_perm(cred, dentry, FILE__READ); | |
2634 | 2648 | } |
2635 | 2649 | |
2636 | 2650 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) |
2637 | 2651 | { |
2638 | 2652 | const struct cred *cred = current_cred(); |
2639 | 2653 | |
2640 | - return dentry_has_perm(cred, NULL, dentry, FILE__READ); | |
2654 | + return dentry_has_perm(cred, dentry, FILE__READ); | |
2641 | 2655 | } |
2642 | 2656 | |
2643 | 2657 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) |
... | ... | @@ -2654,8 +2668,8 @@ |
2654 | 2668 | if (!mask) |
2655 | 2669 | return 0; |
2656 | 2670 | |
2657 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
2658 | - ad.u.fs.inode = inode; | |
2671 | + COMMON_AUDIT_DATA_INIT(&ad, INODE); | |
2672 | + ad.u.inode = inode; | |
2659 | 2673 | |
2660 | 2674 | if (from_access) |
2661 | 2675 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; |
2662 | 2676 | |
2663 | 2677 | |
2664 | 2678 | |
... | ... | @@ -2680,16 +2694,20 @@ |
2680 | 2694 | |
2681 | 2695 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | |
2682 | 2696 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
2683 | - return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | |
2697 | + return dentry_has_perm(cred, dentry, FILE__SETATTR); | |
2684 | 2698 | |
2685 | - return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); | |
2699 | + return dentry_has_perm(cred, dentry, FILE__WRITE); | |
2686 | 2700 | } |
2687 | 2701 | |
2688 | 2702 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
2689 | 2703 | { |
2690 | 2704 | const struct cred *cred = current_cred(); |
2705 | + struct path path; | |
2691 | 2706 | |
2692 | - return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR); | |
2707 | + path.dentry = dentry; | |
2708 | + path.mnt = mnt; | |
2709 | + | |
2710 | + return path_has_perm(cred, &path, FILE__GETATTR); | |
2693 | 2711 | } |
2694 | 2712 | |
2695 | 2713 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) |
... | ... | @@ -2710,7 +2728,7 @@ |
2710 | 2728 | |
2711 | 2729 | /* Not an attribute we recognize, so just check the |
2712 | 2730 | ordinary setattr permission. */ |
2713 | - return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | |
2731 | + return dentry_has_perm(cred, dentry, FILE__SETATTR); | |
2714 | 2732 | } |
2715 | 2733 | |
2716 | 2734 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
... | ... | @@ -2733,8 +2751,8 @@ |
2733 | 2751 | if (!inode_owner_or_capable(inode)) |
2734 | 2752 | return -EPERM; |
2735 | 2753 | |
2736 | - COMMON_AUDIT_DATA_INIT(&ad, FS); | |
2737 | - ad.u.fs.path.dentry = dentry; | |
2754 | + COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | |
2755 | + ad.u.dentry = dentry; | |
2738 | 2756 | |
2739 | 2757 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
2740 | 2758 | FILE__RELABELFROM, &ad); |
2741 | 2759 | |
... | ... | @@ -2797,14 +2815,14 @@ |
2797 | 2815 | { |
2798 | 2816 | const struct cred *cred = current_cred(); |
2799 | 2817 | |
2800 | - return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); | |
2818 | + return dentry_has_perm(cred, dentry, FILE__GETATTR); | |
2801 | 2819 | } |
2802 | 2820 | |
2803 | 2821 | static int selinux_inode_listxattr(struct dentry *dentry) |
2804 | 2822 | { |
2805 | 2823 | const struct cred *cred = current_cred(); |
2806 | 2824 | |
2807 | - return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR); | |
2825 | + return dentry_has_perm(cred, dentry, FILE__GETATTR); | |
2808 | 2826 | } |
2809 | 2827 | |
2810 | 2828 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
security/selinux/include/security.h
... | ... | @@ -30,13 +30,14 @@ |
30 | 30 | #define POLICYDB_VERSION_PERMISSIVE 23 |
31 | 31 | #define POLICYDB_VERSION_BOUNDARY 24 |
32 | 32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 |
33 | +#define POLICYDB_VERSION_ROLETRANS 26 | |
33 | 34 | |
34 | 35 | /* Range of policy versions we understand*/ |
35 | 36 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
36 | 37 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
37 | 38 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
38 | 39 | #else |
39 | -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS | |
40 | +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS | |
40 | 41 | #endif |
41 | 42 | |
42 | 43 | /* Mask for just the mount related flags */ |
... | ... | @@ -85,7 +86,7 @@ |
85 | 86 | int security_mls_enabled(void); |
86 | 87 | |
87 | 88 | int security_load_policy(void *data, size_t len); |
88 | -int security_read_policy(void **data, ssize_t *len); | |
89 | +int security_read_policy(void **data, size_t *len); | |
89 | 90 | size_t security_policydb_len(void); |
90 | 91 | |
91 | 92 | int security_policycap_supported(unsigned int req_cap); |
... | ... | @@ -111,8 +112,8 @@ |
111 | 112 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, |
112 | 113 | const struct qstr *qstr, u32 *out_sid); |
113 | 114 | |
114 | -int security_transition_sid_user(u32 ssid, u32 tsid, | |
115 | - u16 tclass, u32 *out_sid); | |
115 | +int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, | |
116 | + const char *objname, u32 *out_sid); | |
116 | 117 | |
117 | 118 | int security_member_sid(u32 ssid, u32 tsid, |
118 | 119 | u16 tclass, u32 *out_sid); |
security/selinux/netnode.c
security/selinux/selinuxfs.c
... | ... | @@ -28,6 +28,7 @@ |
28 | 28 | #include <linux/percpu.h> |
29 | 29 | #include <linux/audit.h> |
30 | 30 | #include <linux/uaccess.h> |
31 | +#include <linux/kobject.h> | |
31 | 32 | |
32 | 33 | /* selinuxfs pseudo filesystem for exporting the security policy API. |
33 | 34 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ |
34 | 35 | |
... | ... | @@ -753,11 +754,13 @@ |
753 | 754 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) |
754 | 755 | { |
755 | 756 | char *scon = NULL, *tcon = NULL; |
757 | + char *namebuf = NULL, *objname = NULL; | |
756 | 758 | u32 ssid, tsid, newsid; |
757 | 759 | u16 tclass; |
758 | 760 | ssize_t length; |
759 | 761 | char *newcon = NULL; |
760 | 762 | u32 len; |
763 | + int nargs; | |
761 | 764 | |
762 | 765 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); |
763 | 766 | if (length) |
764 | 767 | |
765 | 768 | |
... | ... | @@ -773,9 +776,17 @@ |
773 | 776 | if (!tcon) |
774 | 777 | goto out; |
775 | 778 | |
779 | + length = -ENOMEM; | |
780 | + namebuf = kzalloc(size + 1, GFP_KERNEL); | |
781 | + if (!namebuf) | |
782 | + goto out; | |
783 | + | |
776 | 784 | length = -EINVAL; |
777 | - if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | |
785 | + nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf); | |
786 | + if (nargs < 3 || nargs > 4) | |
778 | 787 | goto out; |
788 | + if (nargs == 4) | |
789 | + objname = namebuf; | |
779 | 790 | |
780 | 791 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
781 | 792 | if (length) |
... | ... | @@ -785,7 +796,8 @@ |
785 | 796 | if (length) |
786 | 797 | goto out; |
787 | 798 | |
788 | - length = security_transition_sid_user(ssid, tsid, tclass, &newsid); | |
799 | + length = security_transition_sid_user(ssid, tsid, tclass, | |
800 | + objname, &newsid); | |
789 | 801 | if (length) |
790 | 802 | goto out; |
791 | 803 | |
... | ... | @@ -804,6 +816,7 @@ |
804 | 816 | length = len; |
805 | 817 | out: |
806 | 818 | kfree(newcon); |
819 | + kfree(namebuf); | |
807 | 820 | kfree(tcon); |
808 | 821 | kfree(scon); |
809 | 822 | return length; |
... | ... | @@ -1901,6 +1914,7 @@ |
1901 | 1914 | }; |
1902 | 1915 | |
1903 | 1916 | struct vfsmount *selinuxfs_mount; |
1917 | +static struct kobject *selinuxfs_kobj; | |
1904 | 1918 | |
1905 | 1919 | static int __init init_sel_fs(void) |
1906 | 1920 | { |
1907 | 1921 | |
1908 | 1922 | |
... | ... | @@ -1908,9 +1922,16 @@ |
1908 | 1922 | |
1909 | 1923 | if (!selinux_enabled) |
1910 | 1924 | return 0; |
1925 | + | |
1926 | + selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); | |
1927 | + if (!selinuxfs_kobj) | |
1928 | + return -ENOMEM; | |
1929 | + | |
1911 | 1930 | err = register_filesystem(&sel_fs_type); |
1912 | - if (err) | |
1931 | + if (err) { | |
1932 | + kobject_put(selinuxfs_kobj); | |
1913 | 1933 | return err; |
1934 | + } | |
1914 | 1935 | |
1915 | 1936 | selinuxfs_mount = kern_mount(&sel_fs_type); |
1916 | 1937 | if (IS_ERR(selinuxfs_mount)) { |
... | ... | @@ -1927,6 +1948,7 @@ |
1927 | 1948 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
1928 | 1949 | void exit_sel_fs(void) |
1929 | 1950 | { |
1951 | + kobject_put(selinuxfs_kobj); | |
1930 | 1952 | unregister_filesystem(&sel_fs_type); |
1931 | 1953 | } |
1932 | 1954 | #endif |
security/selinux/ss/policydb.c
... | ... | @@ -128,6 +128,11 @@ |
128 | 128 | .sym_num = SYM_NUM, |
129 | 129 | .ocon_num = OCON_NUM, |
130 | 130 | }, |
131 | + { | |
132 | + .version = POLICYDB_VERSION_ROLETRANS, | |
133 | + .sym_num = SYM_NUM, | |
134 | + .ocon_num = OCON_NUM, | |
135 | + }, | |
131 | 136 | }; |
132 | 137 | |
133 | 138 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
... | ... | @@ -179,6 +184,43 @@ |
179 | 184 | return rc; |
180 | 185 | } |
181 | 186 | |
187 | +static u32 filenametr_hash(struct hashtab *h, const void *k) | |
188 | +{ | |
189 | + const struct filename_trans *ft = k; | |
190 | + unsigned long hash; | |
191 | + unsigned int byte_num; | |
192 | + unsigned char focus; | |
193 | + | |
194 | + hash = ft->stype ^ ft->ttype ^ ft->tclass; | |
195 | + | |
196 | + byte_num = 0; | |
197 | + while ((focus = ft->name[byte_num++])) | |
198 | + hash = partial_name_hash(focus, hash); | |
199 | + return hash & (h->size - 1); | |
200 | +} | |
201 | + | |
202 | +static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2) | |
203 | +{ | |
204 | + const struct filename_trans *ft1 = k1; | |
205 | + const struct filename_trans *ft2 = k2; | |
206 | + int v; | |
207 | + | |
208 | + v = ft1->stype - ft2->stype; | |
209 | + if (v) | |
210 | + return v; | |
211 | + | |
212 | + v = ft1->ttype - ft2->ttype; | |
213 | + if (v) | |
214 | + return v; | |
215 | + | |
216 | + v = ft1->tclass - ft2->tclass; | |
217 | + if (v) | |
218 | + return v; | |
219 | + | |
220 | + return strcmp(ft1->name, ft2->name); | |
221 | + | |
222 | +} | |
223 | + | |
182 | 224 | static u32 rangetr_hash(struct hashtab *h, const void *k) |
183 | 225 | { |
184 | 226 | const struct range_trans *key = k; |
185 | 227 | |
186 | 228 | |
... | ... | @@ -231,15 +273,22 @@ |
231 | 273 | if (rc) |
232 | 274 | goto out; |
233 | 275 | |
276 | + p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); | |
277 | + if (!p->filename_trans) | |
278 | + goto out; | |
279 | + | |
234 | 280 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); |
235 | 281 | if (!p->range_tr) |
236 | 282 | goto out; |
237 | 283 | |
284 | + ebitmap_init(&p->filename_trans_ttypes); | |
238 | 285 | ebitmap_init(&p->policycaps); |
239 | 286 | ebitmap_init(&p->permissive_map); |
240 | 287 | |
241 | 288 | return 0; |
242 | 289 | out: |
290 | + hashtab_destroy(p->filename_trans); | |
291 | + hashtab_destroy(p->range_tr); | |
243 | 292 | for (i = 0; i < SYM_NUM; i++) |
244 | 293 | hashtab_destroy(p->symtab[i].table); |
245 | 294 | return rc; |
246 | 295 | |
247 | 296 | |
248 | 297 | |
249 | 298 | |
250 | 299 | |
251 | 300 | |
252 | 301 | |
... | ... | @@ -417,32 +466,26 @@ |
417 | 466 | }; |
418 | 467 | |
419 | 468 | #ifdef DEBUG_HASHES |
420 | -static void symtab_hash_eval(struct symtab *s) | |
469 | +static void hash_eval(struct hashtab *h, const char *hash_name) | |
421 | 470 | { |
422 | - int i; | |
471 | + struct hashtab_info info; | |
423 | 472 | |
424 | - for (i = 0; i < SYM_NUM; i++) { | |
425 | - struct hashtab *h = s[i].table; | |
426 | - struct hashtab_info info; | |
427 | - | |
428 | - hashtab_stat(h, &info); | |
429 | - printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " | |
430 | - "longest chain length %d\n", symtab_name[i], h->nel, | |
431 | - info.slots_used, h->size, info.max_chain_len); | |
432 | - } | |
473 | + hashtab_stat(h, &info); | |
474 | + printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " | |
475 | + "longest chain length %d\n", hash_name, h->nel, | |
476 | + info.slots_used, h->size, info.max_chain_len); | |
433 | 477 | } |
434 | 478 | |
435 | -static void rangetr_hash_eval(struct hashtab *h) | |
479 | +static void symtab_hash_eval(struct symtab *s) | |
436 | 480 | { |
437 | - struct hashtab_info info; | |
481 | + int i; | |
438 | 482 | |
439 | - hashtab_stat(h, &info); | |
440 | - printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | |
441 | - "longest chain length %d\n", h->nel, | |
442 | - info.slots_used, h->size, info.max_chain_len); | |
483 | + for (i = 0; i < SYM_NUM; i++) | |
484 | + hash_eval(s[i].table, symtab_name[i]); | |
443 | 485 | } |
486 | + | |
444 | 487 | #else |
445 | -static inline void rangetr_hash_eval(struct hashtab *h) | |
488 | +static inline void hash_eval(struct hashtab *h, char *hash_name) | |
446 | 489 | { |
447 | 490 | } |
448 | 491 | #endif |
... | ... | @@ -675,6 +718,16 @@ |
675 | 718 | cat_destroy, |
676 | 719 | }; |
677 | 720 | |
721 | +static int filenametr_destroy(void *key, void *datum, void *p) | |
722 | +{ | |
723 | + struct filename_trans *ft = key; | |
724 | + kfree(ft->name); | |
725 | + kfree(key); | |
726 | + kfree(datum); | |
727 | + cond_resched(); | |
728 | + return 0; | |
729 | +} | |
730 | + | |
678 | 731 | static int range_tr_destroy(void *key, void *datum, void *p) |
679 | 732 | { |
680 | 733 | struct mls_range *rt = datum; |
... | ... | @@ -709,7 +762,6 @@ |
709 | 762 | int i; |
710 | 763 | struct role_allow *ra, *lra = NULL; |
711 | 764 | struct role_trans *tr, *ltr = NULL; |
712 | - struct filename_trans *ft, *nft; | |
713 | 765 | |
714 | 766 | for (i = 0; i < SYM_NUM; i++) { |
715 | 767 | cond_resched(); |
... | ... | @@ -773,6 +825,9 @@ |
773 | 825 | } |
774 | 826 | kfree(lra); |
775 | 827 | |
828 | + hashtab_map(p->filename_trans, filenametr_destroy, NULL); | |
829 | + hashtab_destroy(p->filename_trans); | |
830 | + | |
776 | 831 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
777 | 832 | hashtab_destroy(p->range_tr); |
778 | 833 | |
... | ... | @@ -788,14 +843,7 @@ |
788 | 843 | flex_array_free(p->type_attr_map_array); |
789 | 844 | } |
790 | 845 | |
791 | - ft = p->filename_trans; | |
792 | - while (ft) { | |
793 | - nft = ft->next; | |
794 | - kfree(ft->name); | |
795 | - kfree(ft); | |
796 | - ft = nft; | |
797 | - } | |
798 | - | |
846 | + ebitmap_destroy(&p->filename_trans_ttypes); | |
799 | 847 | ebitmap_destroy(&p->policycaps); |
800 | 848 | ebitmap_destroy(&p->permissive_map); |
801 | 849 | |
... | ... | @@ -1795,7 +1843,7 @@ |
1795 | 1843 | rt = NULL; |
1796 | 1844 | r = NULL; |
1797 | 1845 | } |
1798 | - rangetr_hash_eval(p->range_tr); | |
1846 | + hash_eval(p->range_tr, "rangetr"); | |
1799 | 1847 | rc = 0; |
1800 | 1848 | out: |
1801 | 1849 | kfree(rt); |
1802 | 1850 | |
... | ... | @@ -1805,9 +1853,10 @@ |
1805 | 1853 | |
1806 | 1854 | static int filename_trans_read(struct policydb *p, void *fp) |
1807 | 1855 | { |
1808 | - struct filename_trans *ft, *last; | |
1809 | - u32 nel, len; | |
1856 | + struct filename_trans *ft; | |
1857 | + struct filename_trans_datum *otype; | |
1810 | 1858 | char *name; |
1859 | + u32 nel, len; | |
1811 | 1860 | __le32 buf[4]; |
1812 | 1861 | int rc, i; |
1813 | 1862 | |
1814 | 1863 | |
1815 | 1864 | |
1816 | 1865 | |
... | ... | @@ -1816,25 +1865,23 @@ |
1816 | 1865 | |
1817 | 1866 | rc = next_entry(buf, fp, sizeof(u32)); |
1818 | 1867 | if (rc) |
1819 | - goto out; | |
1868 | + return rc; | |
1820 | 1869 | nel = le32_to_cpu(buf[0]); |
1821 | 1870 | |
1822 | - last = p->filename_trans; | |
1823 | - while (last && last->next) | |
1824 | - last = last->next; | |
1825 | - | |
1826 | 1871 | for (i = 0; i < nel; i++) { |
1872 | + ft = NULL; | |
1873 | + otype = NULL; | |
1874 | + name = NULL; | |
1875 | + | |
1827 | 1876 | rc = -ENOMEM; |
1828 | 1877 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); |
1829 | 1878 | if (!ft) |
1830 | 1879 | goto out; |
1831 | 1880 | |
1832 | - /* add it to the tail of the list */ | |
1833 | - if (!last) | |
1834 | - p->filename_trans = ft; | |
1835 | - else | |
1836 | - last->next = ft; | |
1837 | - last = ft; | |
1881 | + rc = -ENOMEM; | |
1882 | + otype = kmalloc(sizeof(*otype), GFP_KERNEL); | |
1883 | + if (!otype) | |
1884 | + goto out; | |
1838 | 1885 | |
1839 | 1886 | /* length of the path component string */ |
1840 | 1887 | rc = next_entry(buf, fp, sizeof(u32)); |
1841 | 1888 | |
1842 | 1889 | |
... | ... | @@ -1862,10 +1909,22 @@ |
1862 | 1909 | ft->stype = le32_to_cpu(buf[0]); |
1863 | 1910 | ft->ttype = le32_to_cpu(buf[1]); |
1864 | 1911 | ft->tclass = le32_to_cpu(buf[2]); |
1865 | - ft->otype = le32_to_cpu(buf[3]); | |
1912 | + | |
1913 | + otype->otype = le32_to_cpu(buf[3]); | |
1914 | + | |
1915 | + rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1); | |
1916 | + if (rc) | |
1917 | + goto out; | |
1918 | + | |
1919 | + hashtab_insert(p->filename_trans, ft, otype); | |
1866 | 1920 | } |
1867 | - rc = 0; | |
1921 | + hash_eval(p->filename_trans, "filenametr"); | |
1922 | + return 0; | |
1868 | 1923 | out: |
1924 | + kfree(ft); | |
1925 | + kfree(name); | |
1926 | + kfree(otype); | |
1927 | + | |
1869 | 1928 | return rc; |
1870 | 1929 | } |
1871 | 1930 | |
... | ... | @@ -2266,6 +2325,11 @@ |
2266 | 2325 | p->symtab[i].nprim = nprim; |
2267 | 2326 | } |
2268 | 2327 | |
2328 | + rc = -EINVAL; | |
2329 | + p->process_class = string_to_security_class(p, "process"); | |
2330 | + if (!p->process_class) | |
2331 | + goto bad; | |
2332 | + | |
2269 | 2333 | rc = avtab_read(&p->te_avtab, fp, p); |
2270 | 2334 | if (rc) |
2271 | 2335 | goto bad; |
2272 | 2336 | |
... | ... | @@ -2298,8 +2362,17 @@ |
2298 | 2362 | tr->role = le32_to_cpu(buf[0]); |
2299 | 2363 | tr->type = le32_to_cpu(buf[1]); |
2300 | 2364 | tr->new_role = le32_to_cpu(buf[2]); |
2365 | + if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { | |
2366 | + rc = next_entry(buf, fp, sizeof(u32)); | |
2367 | + if (rc) | |
2368 | + goto bad; | |
2369 | + tr->tclass = le32_to_cpu(buf[0]); | |
2370 | + } else | |
2371 | + tr->tclass = p->process_class; | |
2372 | + | |
2301 | 2373 | if (!policydb_role_isvalid(p, tr->role) || |
2302 | 2374 | !policydb_type_isvalid(p, tr->type) || |
2375 | + !policydb_class_isvalid(p, tr->tclass) || | |
2303 | 2376 | !policydb_role_isvalid(p, tr->new_role)) |
2304 | 2377 | goto bad; |
2305 | 2378 | ltr = tr; |
... | ... | @@ -2341,11 +2414,6 @@ |
2341 | 2414 | goto bad; |
2342 | 2415 | |
2343 | 2416 | rc = -EINVAL; |
2344 | - p->process_class = string_to_security_class(p, "process"); | |
2345 | - if (!p->process_class) | |
2346 | - goto bad; | |
2347 | - | |
2348 | - rc = -EINVAL; | |
2349 | 2417 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); |
2350 | 2418 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); |
2351 | 2419 | if (!p->process_trans_perms) |
2352 | 2420 | |
... | ... | @@ -2517,8 +2585,9 @@ |
2517 | 2585 | return 0; |
2518 | 2586 | } |
2519 | 2587 | |
2520 | -static int role_trans_write(struct role_trans *r, void *fp) | |
2588 | +static int role_trans_write(struct policydb *p, void *fp) | |
2521 | 2589 | { |
2590 | + struct role_trans *r = p->role_tr; | |
2522 | 2591 | struct role_trans *tr; |
2523 | 2592 | u32 buf[3]; |
2524 | 2593 | size_t nel; |
... | ... | @@ -2538,6 +2607,12 @@ |
2538 | 2607 | rc = put_entry(buf, sizeof(u32), 3, fp); |
2539 | 2608 | if (rc) |
2540 | 2609 | return rc; |
2610 | + if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) { | |
2611 | + buf[0] = cpu_to_le32(tr->tclass); | |
2612 | + rc = put_entry(buf, sizeof(u32), 1, fp); | |
2613 | + if (rc) | |
2614 | + return rc; | |
2615 | + } | |
2541 | 2616 | } |
2542 | 2617 | |
2543 | 2618 | return 0; |
... | ... | @@ -3045,7 +3120,7 @@ |
3045 | 3120 | return 0; |
3046 | 3121 | } |
3047 | 3122 | |
3048 | -static int range_count(void *key, void *data, void *ptr) | |
3123 | +static int hashtab_cnt(void *key, void *data, void *ptr) | |
3049 | 3124 | { |
3050 | 3125 | int *cnt = ptr; |
3051 | 3126 | *cnt = *cnt + 1; |
... | ... | @@ -3093,7 +3168,7 @@ |
3093 | 3168 | |
3094 | 3169 | /* count the number of entries in the hashtab */ |
3095 | 3170 | nel = 0; |
3096 | - rc = hashtab_map(p->range_tr, range_count, &nel); | |
3171 | + rc = hashtab_map(p->range_tr, hashtab_cnt, &nel); | |
3097 | 3172 | if (rc) |
3098 | 3173 | return rc; |
3099 | 3174 | |
3100 | 3175 | |
3101 | 3176 | |
3102 | 3177 | |
3103 | 3178 | |
3104 | 3179 | |
3105 | 3180 | |
3106 | 3181 | |
3107 | 3182 | |
3108 | 3183 | |
... | ... | @@ -3110,43 +3185,60 @@ |
3110 | 3185 | return 0; |
3111 | 3186 | } |
3112 | 3187 | |
3113 | -static int filename_trans_write(struct policydb *p, void *fp) | |
3188 | +static int filename_write_helper(void *key, void *data, void *ptr) | |
3114 | 3189 | { |
3115 | - struct filename_trans *ft; | |
3116 | - u32 len, nel = 0; | |
3117 | 3190 | __le32 buf[4]; |
3191 | + struct filename_trans *ft = key; | |
3192 | + struct filename_trans_datum *otype = data; | |
3193 | + void *fp = ptr; | |
3118 | 3194 | int rc; |
3195 | + u32 len; | |
3119 | 3196 | |
3120 | - for (ft = p->filename_trans; ft; ft = ft->next) | |
3121 | - nel++; | |
3122 | - | |
3123 | - buf[0] = cpu_to_le32(nel); | |
3197 | + len = strlen(ft->name); | |
3198 | + buf[0] = cpu_to_le32(len); | |
3124 | 3199 | rc = put_entry(buf, sizeof(u32), 1, fp); |
3125 | 3200 | if (rc) |
3126 | 3201 | return rc; |
3127 | 3202 | |
3128 | - for (ft = p->filename_trans; ft; ft = ft->next) { | |
3129 | - len = strlen(ft->name); | |
3130 | - buf[0] = cpu_to_le32(len); | |
3131 | - rc = put_entry(buf, sizeof(u32), 1, fp); | |
3132 | - if (rc) | |
3133 | - return rc; | |
3203 | + rc = put_entry(ft->name, sizeof(char), len, fp); | |
3204 | + if (rc) | |
3205 | + return rc; | |
3134 | 3206 | |
3135 | - rc = put_entry(ft->name, sizeof(char), len, fp); | |
3136 | - if (rc) | |
3137 | - return rc; | |
3207 | + buf[0] = ft->stype; | |
3208 | + buf[1] = ft->ttype; | |
3209 | + buf[2] = ft->tclass; | |
3210 | + buf[3] = otype->otype; | |
3138 | 3211 | |
3139 | - buf[0] = ft->stype; | |
3140 | - buf[1] = ft->ttype; | |
3141 | - buf[2] = ft->tclass; | |
3142 | - buf[3] = ft->otype; | |
3212 | + rc = put_entry(buf, sizeof(u32), 4, fp); | |
3213 | + if (rc) | |
3214 | + return rc; | |
3143 | 3215 | |
3144 | - rc = put_entry(buf, sizeof(u32), 4, fp); | |
3145 | - if (rc) | |
3146 | - return rc; | |
3147 | - } | |
3148 | 3216 | return 0; |
3149 | 3217 | } |
3218 | + | |
3219 | +static int filename_trans_write(struct policydb *p, void *fp) | |
3220 | +{ | |
3221 | + u32 nel; | |
3222 | + __le32 buf[1]; | |
3223 | + int rc; | |
3224 | + | |
3225 | + nel = 0; | |
3226 | + rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel); | |
3227 | + if (rc) | |
3228 | + return rc; | |
3229 | + | |
3230 | + buf[0] = cpu_to_le32(nel); | |
3231 | + rc = put_entry(buf, sizeof(u32), 1, fp); | |
3232 | + if (rc) | |
3233 | + return rc; | |
3234 | + | |
3235 | + rc = hashtab_map(p->filename_trans, filename_write_helper, fp); | |
3236 | + if (rc) | |
3237 | + return rc; | |
3238 | + | |
3239 | + return 0; | |
3240 | +} | |
3241 | + | |
3150 | 3242 | /* |
3151 | 3243 | * Write the configuration data in a policy database |
3152 | 3244 | * structure to a policy database binary representation |
... | ... | @@ -3249,7 +3341,7 @@ |
3249 | 3341 | if (rc) |
3250 | 3342 | return rc; |
3251 | 3343 | |
3252 | - rc = role_trans_write(p->role_tr, fp); | |
3344 | + rc = role_trans_write(p, fp); | |
3253 | 3345 | if (rc) |
3254 | 3346 | return rc; |
3255 | 3347 |
security/selinux/ss/policydb.h
... | ... | @@ -72,17 +72,20 @@ |
72 | 72 | |
73 | 73 | struct role_trans { |
74 | 74 | u32 role; /* current role */ |
75 | - u32 type; /* program executable type */ | |
75 | + u32 type; /* program executable type, or new object type */ | |
76 | + u32 tclass; /* process class, or new object class */ | |
76 | 77 | u32 new_role; /* new role */ |
77 | 78 | struct role_trans *next; |
78 | 79 | }; |
79 | 80 | |
80 | 81 | struct filename_trans { |
81 | - struct filename_trans *next; | |
82 | 82 | u32 stype; /* current process */ |
83 | 83 | u32 ttype; /* parent dir context */ |
84 | 84 | u16 tclass; /* class of new object */ |
85 | 85 | const char *name; /* last path component */ |
86 | +}; | |
87 | + | |
88 | +struct filename_trans_datum { | |
86 | 89 | u32 otype; /* expected of new object */ |
87 | 90 | }; |
88 | 91 | |
... | ... | @@ -227,7 +230,10 @@ |
227 | 230 | struct role_trans *role_tr; |
228 | 231 | |
229 | 232 | /* file transitions with the last path component */ |
230 | - struct filename_trans *filename_trans; | |
233 | + /* quickly exclude lookups when parent ttype has no rules */ | |
234 | + struct ebitmap filename_trans_ttypes; | |
235 | + /* actual set of filename_trans rules */ | |
236 | + struct hashtab *filename_trans; | |
231 | 237 | |
232 | 238 | /* bools indexed by (value - 1) */ |
233 | 239 | struct cond_bool_datum **bool_val_to_struct; |
security/selinux/ss/services.c
... | ... | @@ -1359,26 +1359,35 @@ |
1359 | 1359 | } |
1360 | 1360 | |
1361 | 1361 | static void filename_compute_type(struct policydb *p, struct context *newcontext, |
1362 | - u32 scon, u32 tcon, u16 tclass, | |
1363 | - const struct qstr *qstr) | |
1362 | + u32 stype, u32 ttype, u16 tclass, | |
1363 | + const char *objname) | |
1364 | 1364 | { |
1365 | - struct filename_trans *ft; | |
1366 | - for (ft = p->filename_trans; ft; ft = ft->next) { | |
1367 | - if (ft->stype == scon && | |
1368 | - ft->ttype == tcon && | |
1369 | - ft->tclass == tclass && | |
1370 | - !strcmp(ft->name, qstr->name)) { | |
1371 | - newcontext->type = ft->otype; | |
1372 | - return; | |
1373 | - } | |
1374 | - } | |
1365 | + struct filename_trans ft; | |
1366 | + struct filename_trans_datum *otype; | |
1367 | + | |
1368 | + /* | |
1369 | + * Most filename trans rules are going to live in specific directories | |
1370 | + * like /dev or /var/run. This bitmap will quickly skip rule searches | |
1371 | + * if the ttype does not contain any rules. | |
1372 | + */ | |
1373 | + if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) | |
1374 | + return; | |
1375 | + | |
1376 | + ft.stype = stype; | |
1377 | + ft.ttype = ttype; | |
1378 | + ft.tclass = tclass; | |
1379 | + ft.name = objname; | |
1380 | + | |
1381 | + otype = hashtab_search(p->filename_trans, &ft); | |
1382 | + if (otype) | |
1383 | + newcontext->type = otype->otype; | |
1375 | 1384 | } |
1376 | 1385 | |
1377 | 1386 | static int security_compute_sid(u32 ssid, |
1378 | 1387 | u32 tsid, |
1379 | 1388 | u16 orig_tclass, |
1380 | 1389 | u32 specified, |
1381 | - const struct qstr *qstr, | |
1390 | + const char *objname, | |
1382 | 1391 | u32 *out_sid, |
1383 | 1392 | bool kern) |
1384 | 1393 | { |
1385 | 1394 | |
1386 | 1395 | |
... | ... | @@ -1478,23 +1487,21 @@ |
1478 | 1487 | newcontext.type = avdatum->data; |
1479 | 1488 | } |
1480 | 1489 | |
1481 | - /* if we have a qstr this is a file trans check so check those rules */ | |
1482 | - if (qstr) | |
1490 | + /* if we have a objname this is a file trans check so check those rules */ | |
1491 | + if (objname) | |
1483 | 1492 | filename_compute_type(&policydb, &newcontext, scontext->type, |
1484 | - tcontext->type, tclass, qstr); | |
1493 | + tcontext->type, tclass, objname); | |
1485 | 1494 | |
1486 | 1495 | /* Check for class-specific changes. */ |
1487 | - if (tclass == policydb.process_class) { | |
1488 | - if (specified & AVTAB_TRANSITION) { | |
1489 | - /* Look for a role transition rule. */ | |
1490 | - for (roletr = policydb.role_tr; roletr; | |
1491 | - roletr = roletr->next) { | |
1492 | - if (roletr->role == scontext->role && | |
1493 | - roletr->type == tcontext->type) { | |
1494 | - /* Use the role transition rule. */ | |
1495 | - newcontext.role = roletr->new_role; | |
1496 | - break; | |
1497 | - } | |
1496 | + if (specified & AVTAB_TRANSITION) { | |
1497 | + /* Look for a role transition rule. */ | |
1498 | + for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { | |
1499 | + if ((roletr->role == scontext->role) && | |
1500 | + (roletr->type == tcontext->type) && | |
1501 | + (roletr->tclass == tclass)) { | |
1502 | + /* Use the role transition rule. */ | |
1503 | + newcontext.role = roletr->new_role; | |
1504 | + break; | |
1498 | 1505 | } |
1499 | 1506 | } |
1500 | 1507 | } |
1501 | 1508 | |
1502 | 1509 | |
... | ... | @@ -1541,13 +1548,14 @@ |
1541 | 1548 | const struct qstr *qstr, u32 *out_sid) |
1542 | 1549 | { |
1543 | 1550 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, |
1544 | - qstr, out_sid, true); | |
1551 | + qstr ? qstr->name : NULL, out_sid, true); | |
1545 | 1552 | } |
1546 | 1553 | |
1547 | -int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) | |
1554 | +int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, | |
1555 | + const char *objname, u32 *out_sid) | |
1548 | 1556 | { |
1549 | 1557 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, |
1550 | - NULL, out_sid, false); | |
1558 | + objname, out_sid, false); | |
1551 | 1559 | } |
1552 | 1560 | |
1553 | 1561 | /** |
... | ... | @@ -3190,7 +3198,7 @@ |
3190 | 3198 | * @len: length of data in bytes |
3191 | 3199 | * |
3192 | 3200 | */ |
3193 | -int security_read_policy(void **data, ssize_t *len) | |
3201 | +int security_read_policy(void **data, size_t *len) | |
3194 | 3202 | { |
3195 | 3203 | int rc; |
3196 | 3204 | struct policy_file fp; |
security/smack/smack.h
... | ... | @@ -316,22 +316,17 @@ |
316 | 316 | static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, |
317 | 317 | struct dentry *d) |
318 | 318 | { |
319 | - a->a.u.fs.path.dentry = d; | |
319 | + a->a.u.dentry = d; | |
320 | 320 | } |
321 | -static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a, | |
322 | - struct vfsmount *m) | |
323 | -{ | |
324 | - a->a.u.fs.path.mnt = m; | |
325 | -} | |
326 | 321 | static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, |
327 | 322 | struct inode *i) |
328 | 323 | { |
329 | - a->a.u.fs.inode = i; | |
324 | + a->a.u.inode = i; | |
330 | 325 | } |
331 | 326 | static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, |
332 | 327 | struct path p) |
333 | 328 | { |
334 | - a->a.u.fs.path = p; | |
329 | + a->a.u.path = p; | |
335 | 330 | } |
336 | 331 | static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, |
337 | 332 | struct sock *sk) |
security/smack/smack_lsm.c
... | ... | @@ -383,7 +383,7 @@ |
383 | 383 | int rc; |
384 | 384 | struct smk_audit_info ad; |
385 | 385 | |
386 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
386 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
387 | 387 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
388 | 388 | |
389 | 389 | rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); |
... | ... | @@ -407,7 +407,7 @@ |
407 | 407 | struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; |
408 | 408 | struct smk_audit_info ad; |
409 | 409 | |
410 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
410 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | |
411 | 411 | smk_ad_setfield_u_fs_path(&ad, *path); |
412 | 412 | |
413 | 413 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); |
414 | 414 | |
415 | 415 | |
... | ... | @@ -425,11 +425,14 @@ |
425 | 425 | { |
426 | 426 | struct superblock_smack *sbp; |
427 | 427 | struct smk_audit_info ad; |
428 | + struct path path; | |
428 | 429 | |
429 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
430 | - smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root); | |
431 | - smk_ad_setfield_u_fs_path_mnt(&ad, mnt); | |
430 | + path.dentry = mnt->mnt_root; | |
431 | + path.mnt = mnt; | |
432 | 432 | |
433 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | |
434 | + smk_ad_setfield_u_fs_path(&ad, path); | |
435 | + | |
433 | 436 | sbp = mnt->mnt_sb->s_security; |
434 | 437 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); |
435 | 438 | } |
... | ... | @@ -563,7 +566,7 @@ |
563 | 566 | struct smk_audit_info ad; |
564 | 567 | int rc; |
565 | 568 | |
566 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
569 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
567 | 570 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); |
568 | 571 | |
569 | 572 | isp = smk_of_inode(old_dentry->d_inode); |
... | ... | @@ -592,7 +595,7 @@ |
592 | 595 | struct smk_audit_info ad; |
593 | 596 | int rc; |
594 | 597 | |
595 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
598 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
596 | 599 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
597 | 600 | |
598 | 601 | /* |
... | ... | @@ -623,7 +626,7 @@ |
623 | 626 | struct smk_audit_info ad; |
624 | 627 | int rc; |
625 | 628 | |
626 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
629 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
627 | 630 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
628 | 631 | |
629 | 632 | /* |
... | ... | @@ -663,7 +666,7 @@ |
663 | 666 | char *isp; |
664 | 667 | struct smk_audit_info ad; |
665 | 668 | |
666 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
669 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
667 | 670 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); |
668 | 671 | |
669 | 672 | isp = smk_of_inode(old_dentry->d_inode); |
... | ... | @@ -700,7 +703,7 @@ |
700 | 703 | /* May be droppable after audit */ |
701 | 704 | if (flags & IPERM_FLAG_RCU) |
702 | 705 | return -ECHILD; |
703 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
706 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); | |
704 | 707 | smk_ad_setfield_u_fs_inode(&ad, inode); |
705 | 708 | return smk_curacc(smk_of_inode(inode), mask, &ad); |
706 | 709 | } |
... | ... | @@ -720,7 +723,7 @@ |
720 | 723 | */ |
721 | 724 | if (iattr->ia_valid & ATTR_FORCE) |
722 | 725 | return 0; |
723 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
726 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
724 | 727 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
725 | 728 | |
726 | 729 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
727 | 730 | |
... | ... | @@ -736,10 +739,13 @@ |
736 | 739 | static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
737 | 740 | { |
738 | 741 | struct smk_audit_info ad; |
742 | + struct path path; | |
739 | 743 | |
740 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
741 | - smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | |
742 | - smk_ad_setfield_u_fs_path_mnt(&ad, mnt); | |
744 | + path.dentry = dentry; | |
745 | + path.mnt = mnt; | |
746 | + | |
747 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | |
748 | + smk_ad_setfield_u_fs_path(&ad, path); | |
743 | 749 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); |
744 | 750 | } |
745 | 751 | |
... | ... | @@ -784,7 +790,7 @@ |
784 | 790 | } else |
785 | 791 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
786 | 792 | |
787 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
793 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
788 | 794 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
789 | 795 | |
790 | 796 | if (rc == 0) |
... | ... | @@ -845,7 +851,7 @@ |
845 | 851 | { |
846 | 852 | struct smk_audit_info ad; |
847 | 853 | |
848 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
854 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
849 | 855 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
850 | 856 | |
851 | 857 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); |
... | ... | @@ -877,7 +883,7 @@ |
877 | 883 | } else |
878 | 884 | rc = cap_inode_removexattr(dentry, name); |
879 | 885 | |
880 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
886 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | |
881 | 887 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
882 | 888 | if (rc == 0) |
883 | 889 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
... | ... | @@ -1047,7 +1053,7 @@ |
1047 | 1053 | int rc = 0; |
1048 | 1054 | struct smk_audit_info ad; |
1049 | 1055 | |
1050 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
1056 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | |
1051 | 1057 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
1052 | 1058 | |
1053 | 1059 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
... | ... | @@ -1070,8 +1076,8 @@ |
1070 | 1076 | { |
1071 | 1077 | struct smk_audit_info ad; |
1072 | 1078 | |
1073 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
1074 | - smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); | |
1079 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | |
1080 | + smk_ad_setfield_u_fs_path(&ad, file->f_path); | |
1075 | 1081 | return smk_curacc(file->f_security, MAY_WRITE, &ad); |
1076 | 1082 | } |
1077 | 1083 | |
... | ... | @@ -1089,7 +1095,7 @@ |
1089 | 1095 | struct smk_audit_info ad; |
1090 | 1096 | int rc; |
1091 | 1097 | |
1092 | - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | |
1098 | + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | |
1093 | 1099 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
1094 | 1100 | |
1095 | 1101 | switch (cmd) { |