diff options
-rw-r--r-- | MAINTAINERS | 3 | ||||
-rw-r--r-- | include/linux/lsm_audit.h | 11 | ||||
-rw-r--r-- | lib/flex_array.c | 26 | ||||
-rw-r--r-- | security/lsm_audit.c | 59 | ||||
-rw-r--r-- | security/selinux/avc.c | 2 | ||||
-rw-r--r-- | security/selinux/hooks.c | 92 | ||||
-rw-r--r-- | security/selinux/include/security.h | 9 | ||||
-rw-r--r-- | security/selinux/netnode.c | 1 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 28 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 244 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 12 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 72 | ||||
-rw-r--r-- | security/smack/smack.h | 11 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 48 |
14 files changed, 398 insertions, 220 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 0b415248ae25..2db39d61b3fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5592,10 +5592,11 @@ M: James Morris <jmorris@namei.org> | |||
5592 | M: Eric Paris <eparis@parisplace.org> | 5592 | M: Eric Paris <eparis@parisplace.org> |
5593 | L: selinux@tycho.nsa.gov (subscribers-only, general discussion) | 5593 | L: selinux@tycho.nsa.gov (subscribers-only, general discussion) |
5594 | W: http://selinuxproject.org | 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 | S: Supported | 5596 | S: Supported |
5597 | F: include/linux/selinux* | 5597 | F: include/linux/selinux* |
5598 | F: security/selinux/ | 5598 | F: security/selinux/ |
5599 | F: scripts/selinux/ | ||
5599 | 5600 | ||
5600 | APPARMOR SECURITY MODULE | 5601 | APPARMOR SECURITY MODULE |
5601 | M: John Johansen <john.johansen@canonical.com> | 5602 | M: John Johansen <john.johansen@canonical.com> |
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 112a55033352..88e78dedc2e8 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h | |||
@@ -27,7 +27,7 @@ | |||
27 | /* Auxiliary data to use in generating the audit record. */ | 27 | /* Auxiliary data to use in generating the audit record. */ |
28 | struct common_audit_data { | 28 | struct common_audit_data { |
29 | char type; | 29 | char type; |
30 | #define LSM_AUDIT_DATA_FS 1 | 30 | #define LSM_AUDIT_DATA_PATH 1 |
31 | #define LSM_AUDIT_DATA_NET 2 | 31 | #define LSM_AUDIT_DATA_NET 2 |
32 | #define LSM_AUDIT_DATA_CAP 3 | 32 | #define LSM_AUDIT_DATA_CAP 3 |
33 | #define LSM_AUDIT_DATA_IPC 4 | 33 | #define LSM_AUDIT_DATA_IPC 4 |
@@ -35,12 +35,13 @@ struct common_audit_data { | |||
35 | #define LSM_AUDIT_DATA_KEY 6 | 35 | #define LSM_AUDIT_DATA_KEY 6 |
36 | #define LSM_AUDIT_DATA_NONE 7 | 36 | #define LSM_AUDIT_DATA_NONE 7 |
37 | #define LSM_AUDIT_DATA_KMOD 8 | 37 | #define LSM_AUDIT_DATA_KMOD 8 |
38 | #define LSM_AUDIT_DATA_INODE 9 | ||
39 | #define LSM_AUDIT_DATA_DENTRY 10 | ||
38 | struct task_struct *tsk; | 40 | struct task_struct *tsk; |
39 | union { | 41 | union { |
40 | struct { | 42 | struct path path; |
41 | struct path path; | 43 | struct dentry *dentry; |
42 | struct inode *inode; | 44 | struct inode *inode; |
43 | } fs; | ||
44 | struct { | 45 | struct { |
45 | int netif; | 46 | int netif; |
46 | struct sock *sk; | 47 | struct sock *sk; |
diff --git a/lib/flex_array.c b/lib/flex_array.c index 854b57bd7d9d..cab7621f98aa 100644 --- a/lib/flex_array.c +++ b/lib/flex_array.c | |||
@@ -88,8 +88,11 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total, | |||
88 | gfp_t flags) | 88 | gfp_t flags) |
89 | { | 89 | { |
90 | struct flex_array *ret; | 90 | struct flex_array *ret; |
91 | int max_size = FLEX_ARRAY_NR_BASE_PTRS * | 91 | int max_size = 0; |
92 | FLEX_ARRAY_ELEMENTS_PER_PART(element_size); | 92 | |
93 | if (element_size) | ||
94 | max_size = FLEX_ARRAY_NR_BASE_PTRS * | ||
95 | FLEX_ARRAY_ELEMENTS_PER_PART(element_size); | ||
93 | 96 | ||
94 | /* max_size will end up 0 if element_size > PAGE_SIZE */ | 97 | /* max_size will end up 0 if element_size > PAGE_SIZE */ |
95 | if (total > max_size) | 98 | if (total > max_size) |
@@ -183,15 +186,18 @@ __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags) | |||
183 | int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, | 186 | int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, |
184 | gfp_t flags) | 187 | gfp_t flags) |
185 | { | 188 | { |
186 | int part_nr = fa_element_to_part_nr(fa, element_nr); | 189 | int part_nr; |
187 | struct flex_array_part *part; | 190 | struct flex_array_part *part; |
188 | void *dst; | 191 | void *dst; |
189 | 192 | ||
190 | if (element_nr >= fa->total_nr_elements) | 193 | if (element_nr >= fa->total_nr_elements) |
191 | return -ENOSPC; | 194 | return -ENOSPC; |
195 | if (!fa->element_size) | ||
196 | return 0; | ||
192 | if (elements_fit_in_base(fa)) | 197 | if (elements_fit_in_base(fa)) |
193 | part = (struct flex_array_part *)&fa->parts[0]; | 198 | part = (struct flex_array_part *)&fa->parts[0]; |
194 | else { | 199 | else { |
200 | part_nr = fa_element_to_part_nr(fa, element_nr); | ||
195 | part = __fa_get_part(fa, part_nr, flags); | 201 | part = __fa_get_part(fa, part_nr, flags); |
196 | if (!part) | 202 | if (!part) |
197 | return -ENOMEM; | 203 | return -ENOMEM; |
@@ -211,15 +217,18 @@ EXPORT_SYMBOL(flex_array_put); | |||
211 | */ | 217 | */ |
212 | int flex_array_clear(struct flex_array *fa, unsigned int element_nr) | 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 | struct flex_array_part *part; | 221 | struct flex_array_part *part; |
216 | void *dst; | 222 | void *dst; |
217 | 223 | ||
218 | if (element_nr >= fa->total_nr_elements) | 224 | if (element_nr >= fa->total_nr_elements) |
219 | return -ENOSPC; | 225 | return -ENOSPC; |
226 | if (!fa->element_size) | ||
227 | return 0; | ||
220 | if (elements_fit_in_base(fa)) | 228 | if (elements_fit_in_base(fa)) |
221 | part = (struct flex_array_part *)&fa->parts[0]; | 229 | part = (struct flex_array_part *)&fa->parts[0]; |
222 | else { | 230 | else { |
231 | part_nr = fa_element_to_part_nr(fa, element_nr); | ||
223 | part = fa->parts[part_nr]; | 232 | part = fa->parts[part_nr]; |
224 | if (!part) | 233 | if (!part) |
225 | return -EINVAL; | 234 | return -EINVAL; |
@@ -264,6 +273,8 @@ int flex_array_prealloc(struct flex_array *fa, unsigned int start, | |||
264 | 273 | ||
265 | if (end >= fa->total_nr_elements) | 274 | if (end >= fa->total_nr_elements) |
266 | return -ENOSPC; | 275 | return -ENOSPC; |
276 | if (!fa->element_size) | ||
277 | return 0; | ||
267 | if (elements_fit_in_base(fa)) | 278 | if (elements_fit_in_base(fa)) |
268 | return 0; | 279 | return 0; |
269 | start_part = fa_element_to_part_nr(fa, start); | 280 | start_part = fa_element_to_part_nr(fa, start); |
@@ -291,14 +302,17 @@ EXPORT_SYMBOL(flex_array_prealloc); | |||
291 | */ | 302 | */ |
292 | void *flex_array_get(struct flex_array *fa, unsigned int element_nr) | 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 | struct flex_array_part *part; | 306 | struct flex_array_part *part; |
296 | 307 | ||
308 | if (!fa->element_size) | ||
309 | return NULL; | ||
297 | if (element_nr >= fa->total_nr_elements) | 310 | if (element_nr >= fa->total_nr_elements) |
298 | return NULL; | 311 | return NULL; |
299 | if (elements_fit_in_base(fa)) | 312 | if (elements_fit_in_base(fa)) |
300 | part = (struct flex_array_part *)&fa->parts[0]; | 313 | part = (struct flex_array_part *)&fa->parts[0]; |
301 | else { | 314 | else { |
315 | part_nr = fa_element_to_part_nr(fa, element_nr); | ||
302 | part = fa->parts[part_nr]; | 316 | part = fa->parts[part_nr]; |
303 | if (!part) | 317 | if (!part) |
304 | return NULL; | 318 | return NULL; |
@@ -353,7 +367,7 @@ int flex_array_shrink(struct flex_array *fa) | |||
353 | int part_nr; | 367 | int part_nr; |
354 | int ret = 0; | 368 | int ret = 0; |
355 | 369 | ||
356 | if (!fa->total_nr_elements) | 370 | if (!fa->total_nr_elements || !fa->element_size) |
357 | return 0; | 371 | return 0; |
358 | if (elements_fit_in_base(fa)) | 372 | if (elements_fit_in_base(fa)) |
359 | return ret; | 373 | return ret; |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 908aa712816a..893af8a2fa1e 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -210,7 +210,6 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | |||
210 | static void dump_common_audit_data(struct audit_buffer *ab, | 210 | static void dump_common_audit_data(struct audit_buffer *ab, |
211 | struct common_audit_data *a) | 211 | struct common_audit_data *a) |
212 | { | 212 | { |
213 | struct inode *inode = NULL; | ||
214 | struct task_struct *tsk = current; | 213 | struct task_struct *tsk = current; |
215 | 214 | ||
216 | if (a->tsk) | 215 | if (a->tsk) |
@@ -229,33 +228,47 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
229 | case LSM_AUDIT_DATA_CAP: | 228 | case LSM_AUDIT_DATA_CAP: |
230 | audit_log_format(ab, " capability=%d ", a->u.cap); | 229 | audit_log_format(ab, " capability=%d ", a->u.cap); |
231 | break; | 230 | break; |
232 | case LSM_AUDIT_DATA_FS: | 231 | case LSM_AUDIT_DATA_PATH: { |
233 | if (a->u.fs.path.dentry) { | 232 | struct inode *inode; |
234 | struct dentry *dentry = a->u.fs.path.dentry; | 233 | |
235 | if (a->u.fs.path.mnt) { | 234 | audit_log_d_path(ab, "path=", &a->u.path); |
236 | audit_log_d_path(ab, "path=", &a->u.fs.path); | 235 | |
237 | } else { | 236 | inode = a->u.path.dentry->d_inode; |
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 | } | ||
254 | if (inode) | 237 | if (inode) |
255 | audit_log_format(ab, " dev=%s ino=%lu", | 238 | audit_log_format(ab, " dev=%s ino=%lu", |
256 | inode->i_sb->s_id, | 239 | inode->i_sb->s_id, |
257 | inode->i_ino); | 240 | inode->i_ino); |
258 | break; | 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 | case LSM_AUDIT_DATA_TASK: | 272 | case LSM_AUDIT_DATA_TASK: |
260 | tsk = a->u.tsk; | 273 | tsk = a->u.tsk; |
261 | if (tsk && tsk->pid) { | 274 | if (tsk && tsk->pid) { |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 3d2715fd35ea..fcb89cb0f223 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -526,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid, | |||
526 | * during retry. However this is logically just as if the operation | 526 | * during retry. However this is logically just as if the operation |
527 | * happened a little later. | 527 | * happened a little later. |
528 | */ | 528 | */ |
529 | if ((a->type == LSM_AUDIT_DATA_FS) && | 529 | if ((a->type == LSM_AUDIT_DATA_INODE) && |
530 | (flags & IPERM_FLAG_RCU)) | 530 | (flags & IPERM_FLAG_RCU)) |
531 | return -ECHILD; | 531 | return -ECHILD; |
532 | 532 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8fb248843009..a0d38459d650 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m, | |||
990 | continue; | 990 | continue; |
991 | default: | 991 | default: |
992 | BUG(); | 992 | BUG(); |
993 | return; | ||
993 | }; | 994 | }; |
994 | /* we need a comma before each option */ | 995 | /* we need a comma before each option */ |
995 | seq_putc(m, ','); | 996 | seq_putc(m, ','); |
@@ -1443,6 +1444,7 @@ static int task_has_capability(struct task_struct *tsk, | |||
1443 | printk(KERN_ERR | 1444 | printk(KERN_ERR |
1444 | "SELinux: out of range capability %d\n", cap); | 1445 | "SELinux: out of range capability %d\n", cap); |
1445 | BUG(); | 1446 | BUG(); |
1447 | return -EINVAL; | ||
1446 | } | 1448 | } |
1447 | 1449 | ||
1448 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); | 1450 | rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); |
@@ -1487,8 +1489,8 @@ static int inode_has_perm(const struct cred *cred, | |||
1487 | 1489 | ||
1488 | if (!adp) { | 1490 | if (!adp) { |
1489 | adp = &ad; | 1491 | adp = &ad; |
1490 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1492 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
1491 | ad.u.fs.inode = inode; | 1493 | ad.u.inode = inode; |
1492 | } | 1494 | } |
1493 | 1495 | ||
1494 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); | 1496 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
@@ -1498,16 +1500,29 @@ static int inode_has_perm(const struct cred *cred, | |||
1498 | the dentry to help the auditing code to more easily generate the | 1500 | the dentry to help the auditing code to more easily generate the |
1499 | pathname if needed. */ | 1501 | pathname if needed. */ |
1500 | static inline int dentry_has_perm(const struct cred *cred, | 1502 | static inline int dentry_has_perm(const struct cred *cred, |
1501 | struct vfsmount *mnt, | ||
1502 | struct dentry *dentry, | 1503 | struct dentry *dentry, |
1503 | u32 av) | 1504 | u32 av) |
1504 | { | 1505 | { |
1505 | struct inode *inode = dentry->d_inode; | 1506 | struct inode *inode = dentry->d_inode; |
1506 | struct common_audit_data ad; | 1507 | struct common_audit_data ad; |
1507 | 1508 | ||
1508 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1509 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1509 | ad.u.fs.path.mnt = mnt; | 1510 | ad.u.dentry = dentry; |
1510 | ad.u.fs.path.dentry = dentry; | 1511 | return inode_has_perm(cred, inode, av, &ad, 0); |
1512 | } | ||
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; | ||
1511 | return inode_has_perm(cred, inode, av, &ad, 0); | 1526 | return inode_has_perm(cred, inode, av, &ad, 0); |
1512 | } | 1527 | } |
1513 | 1528 | ||
@@ -1529,8 +1544,8 @@ static int file_has_perm(const struct cred *cred, | |||
1529 | u32 sid = cred_sid(cred); | 1544 | u32 sid = cred_sid(cred); |
1530 | int rc; | 1545 | int rc; |
1531 | 1546 | ||
1532 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1547 | COMMON_AUDIT_DATA_INIT(&ad, PATH); |
1533 | ad.u.fs.path = file->f_path; | 1548 | ad.u.path = file->f_path; |
1534 | 1549 | ||
1535 | if (sid != fsec->sid) { | 1550 | if (sid != fsec->sid) { |
1536 | rc = avc_has_perm(sid, fsec->sid, | 1551 | rc = avc_has_perm(sid, fsec->sid, |
@@ -1568,8 +1583,8 @@ static int may_create(struct inode *dir, | |||
1568 | sid = tsec->sid; | 1583 | sid = tsec->sid; |
1569 | newsid = tsec->create_sid; | 1584 | newsid = tsec->create_sid; |
1570 | 1585 | ||
1571 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1586 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1572 | ad.u.fs.path.dentry = dentry; | 1587 | ad.u.dentry = dentry; |
1573 | 1588 | ||
1574 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1589 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
1575 | DIR__ADD_NAME | DIR__SEARCH, | 1590 | DIR__ADD_NAME | DIR__SEARCH, |
@@ -1621,8 +1636,8 @@ static int may_link(struct inode *dir, | |||
1621 | dsec = dir->i_security; | 1636 | dsec = dir->i_security; |
1622 | isec = dentry->d_inode->i_security; | 1637 | isec = dentry->d_inode->i_security; |
1623 | 1638 | ||
1624 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 1639 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
1625 | ad.u.fs.path.dentry = dentry; | 1640 | ad.u.dentry = dentry; |
1626 | 1641 | ||
1627 | av = DIR__SEARCH; | 1642 | av = DIR__SEARCH; |
1628 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); | 1643 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); |
@@ -1667,9 +1682,9 @@ static inline int may_rename(struct inode *old_dir, | |||
1667 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1682 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
1668 | new_dsec = new_dir->i_security; | 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 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1688 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
1674 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); | 1689 | DIR__REMOVE_NAME | DIR__SEARCH, &ad); |
1675 | if (rc) | 1690 | if (rc) |
@@ -1685,7 +1700,7 @@ static inline int may_rename(struct inode *old_dir, | |||
1685 | return rc; | 1700 | return rc; |
1686 | } | 1701 | } |
1687 | 1702 | ||
1688 | ad.u.fs.path.dentry = new_dentry; | 1703 | ad.u.dentry = new_dentry; |
1689 | av = DIR__ADD_NAME | DIR__SEARCH; | 1704 | av = DIR__ADD_NAME | DIR__SEARCH; |
1690 | if (new_dentry->d_inode) | 1705 | if (new_dentry->d_inode) |
1691 | av |= DIR__REMOVE_NAME; | 1706 | av |= DIR__REMOVE_NAME; |
@@ -1895,7 +1910,7 @@ static int selinux_quota_on(struct dentry *dentry) | |||
1895 | { | 1910 | { |
1896 | const struct cred *cred = current_cred(); | 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 | static int selinux_syslog(int type) | 1916 | static int selinux_syslog(int type) |
@@ -1992,8 +2007,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
1992 | return rc; | 2007 | return rc; |
1993 | } | 2008 | } |
1994 | 2009 | ||
1995 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2010 | COMMON_AUDIT_DATA_INIT(&ad, PATH); |
1996 | ad.u.fs.path = bprm->file->f_path; | 2011 | ad.u.path = bprm->file->f_path; |
1997 | 2012 | ||
1998 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2013 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
1999 | new_tsec->sid = old_tsec->sid; | 2014 | new_tsec->sid = old_tsec->sid; |
@@ -2121,7 +2136,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2121 | 2136 | ||
2122 | /* Revalidate access to inherited open files. */ | 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 | spin_lock(&files->file_lock); | 2141 | spin_lock(&files->file_lock); |
2127 | for (;;) { | 2142 | for (;;) { |
@@ -2469,8 +2484,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2469 | if (flags & MS_KERNMOUNT) | 2484 | if (flags & MS_KERNMOUNT) |
2470 | return 0; | 2485 | return 0; |
2471 | 2486 | ||
2472 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2487 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2473 | ad.u.fs.path.dentry = sb->s_root; | 2488 | ad.u.dentry = sb->s_root; |
2474 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2489 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
2475 | } | 2490 | } |
2476 | 2491 | ||
@@ -2479,8 +2494,8 @@ static int selinux_sb_statfs(struct dentry *dentry) | |||
2479 | const struct cred *cred = current_cred(); | 2494 | const struct cred *cred = current_cred(); |
2480 | struct common_audit_data ad; | 2495 | struct common_audit_data ad; |
2481 | 2496 | ||
2482 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2497 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2483 | ad.u.fs.path.dentry = dentry->d_sb->s_root; | 2498 | ad.u.dentry = dentry->d_sb->s_root; |
2484 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2499 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
2485 | } | 2500 | } |
2486 | 2501 | ||
@@ -2496,8 +2511,7 @@ static int selinux_mount(char *dev_name, | |||
2496 | return superblock_has_perm(cred, path->mnt->mnt_sb, | 2511 | return superblock_has_perm(cred, path->mnt->mnt_sb, |
2497 | FILESYSTEM__REMOUNT, NULL); | 2512 | FILESYSTEM__REMOUNT, NULL); |
2498 | else | 2513 | else |
2499 | return dentry_has_perm(cred, path->mnt, path->dentry, | 2514 | return path_has_perm(cred, path, FILE__MOUNTON); |
2500 | FILE__MOUNTON); | ||
2501 | } | 2515 | } |
2502 | 2516 | ||
2503 | static int selinux_umount(struct vfsmount *mnt, int flags) | 2517 | static int selinux_umount(struct vfsmount *mnt, int flags) |
@@ -2630,14 +2644,14 @@ static int selinux_inode_readlink(struct dentry *dentry) | |||
2630 | { | 2644 | { |
2631 | const struct cred *cred = current_cred(); | 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 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) | 2650 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) |
2637 | { | 2651 | { |
2638 | const struct cred *cred = current_cred(); | 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 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) | 2657 | static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags) |
@@ -2654,8 +2668,8 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag | |||
2654 | if (!mask) | 2668 | if (!mask) |
2655 | return 0; | 2669 | return 0; |
2656 | 2670 | ||
2657 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2671 | COMMON_AUDIT_DATA_INIT(&ad, INODE); |
2658 | ad.u.fs.inode = inode; | 2672 | ad.u.inode = inode; |
2659 | 2673 | ||
2660 | if (from_access) | 2674 | if (from_access) |
2661 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; | 2675 | ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS; |
@@ -2680,16 +2694,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
2680 | 2694 | ||
2681 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | | 2695 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | |
2682 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) | 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 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 2702 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
2689 | { | 2703 | { |
2690 | const struct cred *cred = current_cred(); | 2704 | const struct cred *cred = current_cred(); |
2705 | struct path path; | ||
2706 | |||
2707 | path.dentry = dentry; | ||
2708 | path.mnt = mnt; | ||
2691 | 2709 | ||
2692 | return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR); | 2710 | return path_has_perm(cred, &path, FILE__GETATTR); |
2693 | } | 2711 | } |
2694 | 2712 | ||
2695 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | 2713 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) |
@@ -2710,7 +2728,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | |||
2710 | 2728 | ||
2711 | /* Not an attribute we recognize, so just check the | 2729 | /* Not an attribute we recognize, so just check the |
2712 | ordinary setattr permission. */ | 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 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | 2734 | static int selinux_inode_setxattr(struct dentry *dentry, const char *name, |
@@ -2733,8 +2751,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2733 | if (!inode_owner_or_capable(inode)) | 2751 | if (!inode_owner_or_capable(inode)) |
2734 | return -EPERM; | 2752 | return -EPERM; |
2735 | 2753 | ||
2736 | COMMON_AUDIT_DATA_INIT(&ad, FS); | 2754 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); |
2737 | ad.u.fs.path.dentry = dentry; | 2755 | ad.u.dentry = dentry; |
2738 | 2756 | ||
2739 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2757 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
2740 | FILE__RELABELFROM, &ad); | 2758 | FILE__RELABELFROM, &ad); |
@@ -2797,14 +2815,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name) | |||
2797 | { | 2815 | { |
2798 | const struct cred *cred = current_cred(); | 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 | static int selinux_inode_listxattr(struct dentry *dentry) | 2821 | static int selinux_inode_listxattr(struct dentry *dentry) |
2804 | { | 2822 | { |
2805 | const struct cred *cred = current_cred(); | 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 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) | 2828 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 348eb00cb668..3ba4feba048a 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -30,13 +30,14 @@ | |||
30 | #define POLICYDB_VERSION_PERMISSIVE 23 | 30 | #define POLICYDB_VERSION_PERMISSIVE 23 |
31 | #define POLICYDB_VERSION_BOUNDARY 24 | 31 | #define POLICYDB_VERSION_BOUNDARY 24 |
32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 | 32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 |
33 | #define POLICYDB_VERSION_ROLETRANS 26 | ||
33 | 34 | ||
34 | /* Range of policy versions we understand*/ | 35 | /* Range of policy versions we understand*/ |
35 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 36 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
36 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 37 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
37 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 38 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
38 | #else | 39 | #else |
39 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_FILENAME_TRANS | 40 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS |
40 | #endif | 41 | #endif |
41 | 42 | ||
42 | /* Mask for just the mount related flags */ | 43 | /* Mask for just the mount related flags */ |
@@ -85,7 +86,7 @@ extern int selinux_policycap_openperm; | |||
85 | int security_mls_enabled(void); | 86 | int security_mls_enabled(void); |
86 | 87 | ||
87 | int security_load_policy(void *data, size_t len); | 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 | size_t security_policydb_len(void); | 90 | size_t security_policydb_len(void); |
90 | 91 | ||
91 | int security_policycap_supported(unsigned int req_cap); | 92 | int security_policycap_supported(unsigned int req_cap); |
@@ -111,8 +112,8 @@ void security_compute_av_user(u32 ssid, u32 tsid, | |||
111 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, | 112 | int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, |
112 | const struct qstr *qstr, u32 *out_sid); | 113 | const struct qstr *qstr, u32 *out_sid); |
113 | 114 | ||
114 | int security_transition_sid_user(u32 ssid, u32 tsid, | 115 | int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, |
115 | u16 tclass, u32 *out_sid); | 116 | const char *objname, u32 *out_sid); |
116 | 117 | ||
117 | int security_member_sid(u32 ssid, u32 tsid, | 118 | int security_member_sid(u32 ssid, u32 tsid, |
118 | u16 tclass, u32 *out_sid); | 119 | u16 tclass, u32 *out_sid); |
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 65ebfe954f85..3618251d0fdb 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family) | |||
141 | break; | 141 | break; |
142 | default: | 142 | default: |
143 | BUG(); | 143 | BUG(); |
144 | return NULL; | ||
144 | } | 145 | } |
145 | 146 | ||
146 | list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list) | 147 | list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list) |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 2d3373b2e256..77d44138864f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/percpu.h> | 28 | #include <linux/percpu.h> |
29 | #include <linux/audit.h> | 29 | #include <linux/audit.h> |
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/kobject.h> | ||
31 | 32 | ||
32 | /* selinuxfs pseudo filesystem for exporting the security policy API. | 33 | /* selinuxfs pseudo filesystem for exporting the security policy API. |
33 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ | 34 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ |
@@ -753,11 +754,13 @@ out: | |||
753 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | 754 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) |
754 | { | 755 | { |
755 | char *scon = NULL, *tcon = NULL; | 756 | char *scon = NULL, *tcon = NULL; |
757 | char *namebuf = NULL, *objname = NULL; | ||
756 | u32 ssid, tsid, newsid; | 758 | u32 ssid, tsid, newsid; |
757 | u16 tclass; | 759 | u16 tclass; |
758 | ssize_t length; | 760 | ssize_t length; |
759 | char *newcon = NULL; | 761 | char *newcon = NULL; |
760 | u32 len; | 762 | u32 len; |
763 | int nargs; | ||
761 | 764 | ||
762 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); | 765 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); |
763 | if (length) | 766 | if (length) |
@@ -773,9 +776,17 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
773 | if (!tcon) | 776 | if (!tcon) |
774 | goto out; | 777 | goto out; |
775 | 778 | ||
779 | length = -ENOMEM; | ||
780 | namebuf = kzalloc(size + 1, GFP_KERNEL); | ||
781 | if (!namebuf) | ||
782 | goto out; | ||
783 | |||
776 | length = -EINVAL; | 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 | goto out; | 787 | goto out; |
788 | if (nargs == 4) | ||
789 | objname = namebuf; | ||
779 | 790 | ||
780 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 791 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
781 | if (length) | 792 | if (length) |
@@ -785,7 +796,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
785 | if (length) | 796 | if (length) |
786 | goto out; | 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 | if (length) | 801 | if (length) |
790 | goto out; | 802 | goto out; |
791 | 803 | ||
@@ -804,6 +816,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
804 | length = len; | 816 | length = len; |
805 | out: | 817 | out: |
806 | kfree(newcon); | 818 | kfree(newcon); |
819 | kfree(namebuf); | ||
807 | kfree(tcon); | 820 | kfree(tcon); |
808 | kfree(scon); | 821 | kfree(scon); |
809 | return length; | 822 | return length; |
@@ -1901,6 +1914,7 @@ static struct file_system_type sel_fs_type = { | |||
1901 | }; | 1914 | }; |
1902 | 1915 | ||
1903 | struct vfsmount *selinuxfs_mount; | 1916 | struct vfsmount *selinuxfs_mount; |
1917 | static struct kobject *selinuxfs_kobj; | ||
1904 | 1918 | ||
1905 | static int __init init_sel_fs(void) | 1919 | static int __init init_sel_fs(void) |
1906 | { | 1920 | { |
@@ -1908,9 +1922,16 @@ static int __init init_sel_fs(void) | |||
1908 | 1922 | ||
1909 | if (!selinux_enabled) | 1923 | if (!selinux_enabled) |
1910 | return 0; | 1924 | return 0; |
1925 | |||
1926 | selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); | ||
1927 | if (!selinuxfs_kobj) | ||
1928 | return -ENOMEM; | ||
1929 | |||
1911 | err = register_filesystem(&sel_fs_type); | 1930 | err = register_filesystem(&sel_fs_type); |
1912 | if (err) | 1931 | if (err) { |
1932 | kobject_put(selinuxfs_kobj); | ||
1913 | return err; | 1933 | return err; |
1934 | } | ||
1914 | 1935 | ||
1915 | selinuxfs_mount = kern_mount(&sel_fs_type); | 1936 | selinuxfs_mount = kern_mount(&sel_fs_type); |
1916 | if (IS_ERR(selinuxfs_mount)) { | 1937 | if (IS_ERR(selinuxfs_mount)) { |
@@ -1927,6 +1948,7 @@ __initcall(init_sel_fs); | |||
1927 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 1948 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
1928 | void exit_sel_fs(void) | 1949 | void exit_sel_fs(void) |
1929 | { | 1950 | { |
1951 | kobject_put(selinuxfs_kobj); | ||
1930 | unregister_filesystem(&sel_fs_type); | 1952 | unregister_filesystem(&sel_fs_type); |
1931 | } | 1953 | } |
1932 | #endif | 1954 | #endif |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 7102457661d6..102e9ec1b77a 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
128 | .sym_num = SYM_NUM, | 128 | .sym_num = SYM_NUM, |
129 | .ocon_num = OCON_NUM, | 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 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 138 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -179,6 +184,43 @@ out: | |||
179 | return rc; | 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 | static u32 rangetr_hash(struct hashtab *h, const void *k) | 224 | static u32 rangetr_hash(struct hashtab *h, const void *k) |
183 | { | 225 | { |
184 | const struct range_trans *key = k; | 226 | const struct range_trans *key = k; |
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p) | |||
231 | if (rc) | 273 | if (rc) |
232 | goto out; | 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 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | 280 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); |
235 | if (!p->range_tr) | 281 | if (!p->range_tr) |
236 | goto out; | 282 | goto out; |
237 | 283 | ||
284 | ebitmap_init(&p->filename_trans_ttypes); | ||
238 | ebitmap_init(&p->policycaps); | 285 | ebitmap_init(&p->policycaps); |
239 | ebitmap_init(&p->permissive_map); | 286 | ebitmap_init(&p->permissive_map); |
240 | 287 | ||
241 | return 0; | 288 | return 0; |
242 | out: | 289 | out: |
290 | hashtab_destroy(p->filename_trans); | ||
291 | hashtab_destroy(p->range_tr); | ||
243 | for (i = 0; i < SYM_NUM; i++) | 292 | for (i = 0; i < SYM_NUM; i++) |
244 | hashtab_destroy(p->symtab[i].table); | 293 | hashtab_destroy(p->symtab[i].table); |
245 | return rc; | 294 | return rc; |
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
417 | }; | 466 | }; |
418 | 467 | ||
419 | #ifdef DEBUG_HASHES | 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 | |||
424 | for (i = 0; i < SYM_NUM; i++) { | ||
425 | struct hashtab *h = s[i].table; | ||
426 | struct hashtab_info info; | ||
427 | 472 | ||
428 | hashtab_stat(h, &info); | 473 | hashtab_stat(h, &info); |
429 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " | 474 | printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, " |
430 | "longest chain length %d\n", symtab_name[i], h->nel, | 475 | "longest chain length %d\n", hash_name, h->nel, |
431 | info.slots_used, h->size, info.max_chain_len); | 476 | info.slots_used, h->size, info.max_chain_len); |
432 | } | ||
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); | 483 | for (i = 0; i < SYM_NUM; i++) |
440 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | 484 | hash_eval(s[i].table, symtab_name[i]); |
441 | "longest chain length %d\n", h->nel, | ||
442 | info.slots_used, h->size, info.max_chain_len); | ||
443 | } | 485 | } |
486 | |||
444 | #else | 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 | #endif | 491 | #endif |
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
675 | cat_destroy, | 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 | static int range_tr_destroy(void *key, void *datum, void *p) | 731 | static int range_tr_destroy(void *key, void *datum, void *p) |
679 | { | 732 | { |
680 | struct mls_range *rt = datum; | 733 | struct mls_range *rt = datum; |
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p) | |||
709 | int i; | 762 | int i; |
710 | struct role_allow *ra, *lra = NULL; | 763 | struct role_allow *ra, *lra = NULL; |
711 | struct role_trans *tr, *ltr = NULL; | 764 | struct role_trans *tr, *ltr = NULL; |
712 | struct filename_trans *ft, *nft; | ||
713 | 765 | ||
714 | for (i = 0; i < SYM_NUM; i++) { | 766 | for (i = 0; i < SYM_NUM; i++) { |
715 | cond_resched(); | 767 | cond_resched(); |
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p) | |||
773 | } | 825 | } |
774 | kfree(lra); | 826 | kfree(lra); |
775 | 827 | ||
828 | hashtab_map(p->filename_trans, filenametr_destroy, NULL); | ||
829 | hashtab_destroy(p->filename_trans); | ||
830 | |||
776 | hashtab_map(p->range_tr, range_tr_destroy, NULL); | 831 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
777 | hashtab_destroy(p->range_tr); | 832 | hashtab_destroy(p->range_tr); |
778 | 833 | ||
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p) | |||
788 | flex_array_free(p->type_attr_map_array); | 843 | flex_array_free(p->type_attr_map_array); |
789 | } | 844 | } |
790 | 845 | ||
791 | ft = p->filename_trans; | 846 | ebitmap_destroy(&p->filename_trans_ttypes); |
792 | while (ft) { | ||
793 | nft = ft->next; | ||
794 | kfree(ft->name); | ||
795 | kfree(ft); | ||
796 | ft = nft; | ||
797 | } | ||
798 | |||
799 | ebitmap_destroy(&p->policycaps); | 847 | ebitmap_destroy(&p->policycaps); |
800 | ebitmap_destroy(&p->permissive_map); | 848 | ebitmap_destroy(&p->permissive_map); |
801 | 849 | ||
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp) | |||
1795 | rt = NULL; | 1843 | rt = NULL; |
1796 | r = NULL; | 1844 | r = NULL; |
1797 | } | 1845 | } |
1798 | rangetr_hash_eval(p->range_tr); | 1846 | hash_eval(p->range_tr, "rangetr"); |
1799 | rc = 0; | 1847 | rc = 0; |
1800 | out: | 1848 | out: |
1801 | kfree(rt); | 1849 | kfree(rt); |
@@ -1805,9 +1853,10 @@ out: | |||
1805 | 1853 | ||
1806 | static int filename_trans_read(struct policydb *p, void *fp) | 1854 | static int filename_trans_read(struct policydb *p, void *fp) |
1807 | { | 1855 | { |
1808 | struct filename_trans *ft, *last; | 1856 | struct filename_trans *ft; |
1809 | u32 nel, len; | 1857 | struct filename_trans_datum *otype; |
1810 | char *name; | 1858 | char *name; |
1859 | u32 nel, len; | ||
1811 | __le32 buf[4]; | 1860 | __le32 buf[4]; |
1812 | int rc, i; | 1861 | int rc, i; |
1813 | 1862 | ||
@@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1816 | 1865 | ||
1817 | rc = next_entry(buf, fp, sizeof(u32)); | 1866 | rc = next_entry(buf, fp, sizeof(u32)); |
1818 | if (rc) | 1867 | if (rc) |
1819 | goto out; | 1868 | return rc; |
1820 | nel = le32_to_cpu(buf[0]); | 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 | for (i = 0; i < nel; i++) { | 1871 | for (i = 0; i < nel; i++) { |
1872 | ft = NULL; | ||
1873 | otype = NULL; | ||
1874 | name = NULL; | ||
1875 | |||
1827 | rc = -ENOMEM; | 1876 | rc = -ENOMEM; |
1828 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); | 1877 | ft = kzalloc(sizeof(*ft), GFP_KERNEL); |
1829 | if (!ft) | 1878 | if (!ft) |
1830 | goto out; | 1879 | goto out; |
1831 | 1880 | ||
1832 | /* add it to the tail of the list */ | 1881 | rc = -ENOMEM; |
1833 | if (!last) | 1882 | otype = kmalloc(sizeof(*otype), GFP_KERNEL); |
1834 | p->filename_trans = ft; | 1883 | if (!otype) |
1835 | else | 1884 | goto out; |
1836 | last->next = ft; | ||
1837 | last = ft; | ||
1838 | 1885 | ||
1839 | /* length of the path component string */ | 1886 | /* length of the path component string */ |
1840 | rc = next_entry(buf, fp, sizeof(u32)); | 1887 | rc = next_entry(buf, fp, sizeof(u32)); |
@@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1862 | ft->stype = le32_to_cpu(buf[0]); | 1909 | ft->stype = le32_to_cpu(buf[0]); |
1863 | ft->ttype = le32_to_cpu(buf[1]); | 1910 | ft->ttype = le32_to_cpu(buf[1]); |
1864 | ft->tclass = le32_to_cpu(buf[2]); | 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 | out: | 1923 | out: |
1924 | kfree(ft); | ||
1925 | kfree(name); | ||
1926 | kfree(otype); | ||
1927 | |||
1869 | return rc; | 1928 | return rc; |
1870 | } | 1929 | } |
1871 | 1930 | ||
@@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
2266 | p->symtab[i].nprim = nprim; | 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 | rc = avtab_read(&p->te_avtab, fp, p); | 2333 | rc = avtab_read(&p->te_avtab, fp, p); |
2270 | if (rc) | 2334 | if (rc) |
2271 | goto bad; | 2335 | goto bad; |
@@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp) | |||
2298 | tr->role = le32_to_cpu(buf[0]); | 2362 | tr->role = le32_to_cpu(buf[0]); |
2299 | tr->type = le32_to_cpu(buf[1]); | 2363 | tr->type = le32_to_cpu(buf[1]); |
2300 | tr->new_role = le32_to_cpu(buf[2]); | 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 | if (!policydb_role_isvalid(p, tr->role) || | 2373 | if (!policydb_role_isvalid(p, tr->role) || |
2302 | !policydb_type_isvalid(p, tr->type) || | 2374 | !policydb_type_isvalid(p, tr->type) || |
2375 | !policydb_class_isvalid(p, tr->tclass) || | ||
2303 | !policydb_role_isvalid(p, tr->new_role)) | 2376 | !policydb_role_isvalid(p, tr->new_role)) |
2304 | goto bad; | 2377 | goto bad; |
2305 | ltr = tr; | 2378 | ltr = tr; |
@@ -2341,11 +2414,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
2341 | goto bad; | 2414 | goto bad; |
2342 | 2415 | ||
2343 | rc = -EINVAL; | 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 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); | 2417 | p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition"); |
2350 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); | 2418 | p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition"); |
2351 | if (!p->process_trans_perms) | 2419 | if (!p->process_trans_perms) |
@@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr) | |||
2517 | return 0; | 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 | struct role_trans *tr; | 2591 | struct role_trans *tr; |
2523 | u32 buf[3]; | 2592 | u32 buf[3]; |
2524 | size_t nel; | 2593 | size_t nel; |
@@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp) | |||
2538 | rc = put_entry(buf, sizeof(u32), 3, fp); | 2607 | rc = put_entry(buf, sizeof(u32), 3, fp); |
2539 | if (rc) | 2608 | if (rc) |
2540 | return rc; | 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 | return 0; | 2618 | return 0; |
@@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp) | |||
3045 | return 0; | 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 | int *cnt = ptr; | 3125 | int *cnt = ptr; |
3051 | *cnt = *cnt + 1; | 3126 | *cnt = *cnt + 1; |
@@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp) | |||
3093 | 3168 | ||
3094 | /* count the number of entries in the hashtab */ | 3169 | /* count the number of entries in the hashtab */ |
3095 | nel = 0; | 3170 | nel = 0; |
3096 | rc = hashtab_map(p->range_tr, range_count, &nel); | 3171 | rc = hashtab_map(p->range_tr, hashtab_cnt, &nel); |
3097 | if (rc) | 3172 | if (rc) |
3098 | return rc; | 3173 | return rc; |
3099 | 3174 | ||
@@ -3110,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp) | |||
3110 | return 0; | 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 | __le32 buf[4]; | 3190 | __le32 buf[4]; |
3191 | struct filename_trans *ft = key; | ||
3192 | struct filename_trans_datum *otype = data; | ||
3193 | void *fp = ptr; | ||
3118 | int rc; | 3194 | int rc; |
3195 | u32 len; | ||
3119 | 3196 | ||
3120 | for (ft = p->filename_trans; ft; ft = ft->next) | 3197 | len = strlen(ft->name); |
3121 | nel++; | 3198 | buf[0] = cpu_to_le32(len); |
3122 | |||
3123 | buf[0] = cpu_to_le32(nel); | ||
3124 | rc = put_entry(buf, sizeof(u32), 1, fp); | 3199 | rc = put_entry(buf, sizeof(u32), 1, fp); |
3125 | if (rc) | 3200 | if (rc) |
3126 | return rc; | 3201 | return rc; |
3127 | 3202 | ||
3128 | for (ft = p->filename_trans; ft; ft = ft->next) { | 3203 | rc = put_entry(ft->name, sizeof(char), len, fp); |
3129 | len = strlen(ft->name); | 3204 | if (rc) |
3130 | buf[0] = cpu_to_le32(len); | 3205 | return rc; |
3131 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
3132 | if (rc) | ||
3133 | return rc; | ||
3134 | 3206 | ||
3135 | rc = put_entry(ft->name, sizeof(char), len, fp); | 3207 | buf[0] = ft->stype; |
3136 | if (rc) | 3208 | buf[1] = ft->ttype; |
3137 | return rc; | 3209 | buf[2] = ft->tclass; |
3210 | buf[3] = otype->otype; | ||
3138 | 3211 | ||
3139 | buf[0] = ft->stype; | 3212 | rc = put_entry(buf, sizeof(u32), 4, fp); |
3140 | buf[1] = ft->ttype; | 3213 | if (rc) |
3141 | buf[2] = ft->tclass; | 3214 | return rc; |
3142 | buf[3] = ft->otype; | ||
3143 | 3215 | ||
3144 | rc = put_entry(buf, sizeof(u32), 4, fp); | ||
3145 | if (rc) | ||
3146 | return rc; | ||
3147 | } | ||
3148 | return 0; | 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 | * Write the configuration data in a policy database | 3243 | * Write the configuration data in a policy database |
3152 | * structure to a policy database binary representation | 3244 | * structure to a policy database binary representation |
@@ -3249,7 +3341,7 @@ int policydb_write(struct policydb *p, void *fp) | |||
3249 | if (rc) | 3341 | if (rc) |
3250 | return rc; | 3342 | return rc; |
3251 | 3343 | ||
3252 | rc = role_trans_write(p->role_tr, fp); | 3344 | rc = role_trans_write(p, fp); |
3253 | if (rc) | 3345 | if (rc) |
3254 | return rc; | 3346 | return rc; |
3255 | 3347 | ||
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 732ea4a68682..b846c0387180 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -72,17 +72,20 @@ struct role_datum { | |||
72 | 72 | ||
73 | struct role_trans { | 73 | struct role_trans { |
74 | u32 role; /* current role */ | 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 | u32 new_role; /* new role */ | 77 | u32 new_role; /* new role */ |
77 | struct role_trans *next; | 78 | struct role_trans *next; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | struct filename_trans { | 81 | struct filename_trans { |
81 | struct filename_trans *next; | ||
82 | u32 stype; /* current process */ | 82 | u32 stype; /* current process */ |
83 | u32 ttype; /* parent dir context */ | 83 | u32 ttype; /* parent dir context */ |
84 | u16 tclass; /* class of new object */ | 84 | u16 tclass; /* class of new object */ |
85 | const char *name; /* last path component */ | 85 | const char *name; /* last path component */ |
86 | }; | ||
87 | |||
88 | struct filename_trans_datum { | ||
86 | u32 otype; /* expected of new object */ | 89 | u32 otype; /* expected of new object */ |
87 | }; | 90 | }; |
88 | 91 | ||
@@ -227,7 +230,10 @@ struct policydb { | |||
227 | struct role_trans *role_tr; | 230 | struct role_trans *role_tr; |
228 | 231 | ||
229 | /* file transitions with the last path component */ | 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 | /* bools indexed by (value - 1) */ | 238 | /* bools indexed by (value - 1) */ |
233 | struct cond_bool_datum **bool_val_to_struct; | 239 | struct cond_bool_datum **bool_val_to_struct; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 6ef4af47dac4..c3e4b52699f4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1359,26 +1359,35 @@ out: | |||
1359 | } | 1359 | } |
1360 | 1360 | ||
1361 | static void filename_compute_type(struct policydb *p, struct context *newcontext, | 1361 | static void filename_compute_type(struct policydb *p, struct context *newcontext, |
1362 | u32 scon, u32 tcon, u16 tclass, | 1362 | u32 stype, u32 ttype, u16 tclass, |
1363 | const struct qstr *qstr) | 1363 | const char *objname) |
1364 | { | 1364 | { |
1365 | struct filename_trans *ft; | 1365 | struct filename_trans ft; |
1366 | for (ft = p->filename_trans; ft; ft = ft->next) { | 1366 | struct filename_trans_datum *otype; |
1367 | if (ft->stype == scon && | 1367 | |
1368 | ft->ttype == tcon && | 1368 | /* |
1369 | ft->tclass == tclass && | 1369 | * Most filename trans rules are going to live in specific directories |
1370 | !strcmp(ft->name, qstr->name)) { | 1370 | * like /dev or /var/run. This bitmap will quickly skip rule searches |
1371 | newcontext->type = ft->otype; | 1371 | * if the ttype does not contain any rules. |
1372 | return; | 1372 | */ |
1373 | } | 1373 | if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) |
1374 | } | 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 | static int security_compute_sid(u32 ssid, | 1386 | static int security_compute_sid(u32 ssid, |
1378 | u32 tsid, | 1387 | u32 tsid, |
1379 | u16 orig_tclass, | 1388 | u16 orig_tclass, |
1380 | u32 specified, | 1389 | u32 specified, |
1381 | const struct qstr *qstr, | 1390 | const char *objname, |
1382 | u32 *out_sid, | 1391 | u32 *out_sid, |
1383 | bool kern) | 1392 | bool kern) |
1384 | { | 1393 | { |
@@ -1478,23 +1487,21 @@ static int security_compute_sid(u32 ssid, | |||
1478 | newcontext.type = avdatum->data; | 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 */ | 1490 | /* if we have a objname this is a file trans check so check those rules */ |
1482 | if (qstr) | 1491 | if (objname) |
1483 | filename_compute_type(&policydb, &newcontext, scontext->type, | 1492 | filename_compute_type(&policydb, &newcontext, scontext->type, |
1484 | tcontext->type, tclass, qstr); | 1493 | tcontext->type, tclass, objname); |
1485 | 1494 | ||
1486 | /* Check for class-specific changes. */ | 1495 | /* Check for class-specific changes. */ |
1487 | if (tclass == policydb.process_class) { | 1496 | if (specified & AVTAB_TRANSITION) { |
1488 | if (specified & AVTAB_TRANSITION) { | 1497 | /* Look for a role transition rule. */ |
1489 | /* Look for a role transition rule. */ | 1498 | for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { |
1490 | for (roletr = policydb.role_tr; roletr; | 1499 | if ((roletr->role == scontext->role) && |
1491 | roletr = roletr->next) { | 1500 | (roletr->type == tcontext->type) && |
1492 | if (roletr->role == scontext->role && | 1501 | (roletr->tclass == tclass)) { |
1493 | roletr->type == tcontext->type) { | 1502 | /* Use the role transition rule. */ |
1494 | /* Use the role transition rule. */ | 1503 | newcontext.role = roletr->new_role; |
1495 | newcontext.role = roletr->new_role; | 1504 | break; |
1496 | break; | ||
1497 | } | ||
1498 | } | 1505 | } |
1499 | } | 1506 | } |
1500 | } | 1507 | } |
@@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, | |||
1541 | const struct qstr *qstr, u32 *out_sid) | 1548 | const struct qstr *qstr, u32 *out_sid) |
1542 | { | 1549 | { |
1543 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, | 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 | return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, | 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 @@ out: | |||
3190 | * @len: length of data in bytes | 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 | int rc; | 3203 | int rc; |
3196 | struct policy_file fp; | 3204 | struct policy_file fp; |
diff --git a/security/smack/smack.h b/security/smack/smack.h index b449cfdad21c..2b6c6a516123 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -316,22 +316,17 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, | |||
316 | static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, | 316 | static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a, |
317 | struct dentry *d) | 317 | struct dentry *d) |
318 | { | 318 | { |
319 | a->a.u.fs.path.dentry = d; | 319 | a->a.u.dentry = d; |
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 | } | 320 | } |
326 | static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, | 321 | static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a, |
327 | struct inode *i) | 322 | struct inode *i) |
328 | { | 323 | { |
329 | a->a.u.fs.inode = i; | 324 | a->a.u.inode = i; |
330 | } | 325 | } |
331 | static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, | 326 | static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a, |
332 | struct path p) | 327 | struct path p) |
333 | { | 328 | { |
334 | a->a.u.fs.path = p; | 329 | a->a.u.path = p; |
335 | } | 330 | } |
336 | static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, | 331 | static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a, |
337 | struct sock *sk) | 332 | struct sock *sk) |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 400a5d5cde61..9831a39c11f6 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry) | |||
383 | int rc; | 383 | int rc; |
384 | struct smk_audit_info ad; | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 387 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
388 | 388 | ||
389 | rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); | 389 | rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); |
@@ -407,7 +407,7 @@ static int smack_sb_mount(char *dev_name, struct path *path, | |||
407 | struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; | 407 | struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; |
408 | struct smk_audit_info ad; | 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 | smk_ad_setfield_u_fs_path(&ad, *path); | 411 | smk_ad_setfield_u_fs_path(&ad, *path); |
412 | 412 | ||
413 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | 413 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); |
@@ -425,10 +425,13 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags) | |||
425 | { | 425 | { |
426 | struct superblock_smack *sbp; | 426 | struct superblock_smack *sbp; |
427 | struct smk_audit_info ad; | 427 | struct smk_audit_info ad; |
428 | struct path path; | ||
428 | 429 | ||
429 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | 430 | path.dentry = mnt->mnt_root; |
430 | smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root); | 431 | path.mnt = mnt; |
431 | smk_ad_setfield_u_fs_path_mnt(&ad, mnt); | 432 | |
433 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | ||
434 | smk_ad_setfield_u_fs_path(&ad, path); | ||
432 | 435 | ||
433 | sbp = mnt->mnt_sb->s_security; | 436 | sbp = mnt->mnt_sb->s_security; |
434 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | 437 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); |
@@ -563,7 +566,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, | |||
563 | struct smk_audit_info ad; | 566 | struct smk_audit_info ad; |
564 | int rc; | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); | 570 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); |
568 | 571 | ||
569 | isp = smk_of_inode(old_dentry->d_inode); | 572 | isp = smk_of_inode(old_dentry->d_inode); |
@@ -592,7 +595,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) | |||
592 | struct smk_audit_info ad; | 595 | struct smk_audit_info ad; |
593 | int rc; | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 599 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
597 | 600 | ||
598 | /* | 601 | /* |
@@ -623,7 +626,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) | |||
623 | struct smk_audit_info ad; | 626 | struct smk_audit_info ad; |
624 | int rc; | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 630 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
628 | 631 | ||
629 | /* | 632 | /* |
@@ -663,7 +666,7 @@ static int smack_inode_rename(struct inode *old_inode, | |||
663 | char *isp; | 666 | char *isp; |
664 | struct smk_audit_info ad; | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); | 670 | smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); |
668 | 671 | ||
669 | isp = smk_of_inode(old_dentry->d_inode); | 672 | isp = smk_of_inode(old_dentry->d_inode); |
@@ -700,7 +703,7 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) | |||
700 | /* May be droppable after audit */ | 703 | /* May be droppable after audit */ |
701 | if (flags & IPERM_FLAG_RCU) | 704 | if (flags & IPERM_FLAG_RCU) |
702 | return -ECHILD; | 705 | return -ECHILD; |
703 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | 706 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); |
704 | smk_ad_setfield_u_fs_inode(&ad, inode); | 707 | smk_ad_setfield_u_fs_inode(&ad, inode); |
705 | return smk_curacc(smk_of_inode(inode), mask, &ad); | 708 | return smk_curacc(smk_of_inode(inode), mask, &ad); |
706 | } | 709 | } |
@@ -720,7 +723,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
720 | */ | 723 | */ |
721 | if (iattr->ia_valid & ATTR_FORCE) | 724 | if (iattr->ia_valid & ATTR_FORCE) |
722 | return 0; | 725 | return 0; |
723 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | 726 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); |
724 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 727 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
725 | 728 | ||
726 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); | 729 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
@@ -736,10 +739,13 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
736 | static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 739 | static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
737 | { | 740 | { |
738 | struct smk_audit_info ad; | 741 | struct smk_audit_info ad; |
742 | struct path path; | ||
739 | 743 | ||
740 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | 744 | path.dentry = dentry; |
741 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 745 | path.mnt = mnt; |
742 | smk_ad_setfield_u_fs_path_mnt(&ad, mnt); | 746 | |
747 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | ||
748 | smk_ad_setfield_u_fs_path(&ad, path); | ||
743 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); | 749 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); |
744 | } | 750 | } |
745 | 751 | ||
@@ -784,7 +790,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
784 | } else | 790 | } else |
785 | rc = cap_inode_setxattr(dentry, name, value, size, flags); | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 794 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
789 | 795 | ||
790 | if (rc == 0) | 796 | if (rc == 0) |
@@ -845,7 +851,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) | |||
845 | { | 851 | { |
846 | struct smk_audit_info ad; | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 855 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
850 | 856 | ||
851 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); | 857 | return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); |
@@ -877,7 +883,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
877 | } else | 883 | } else |
878 | rc = cap_inode_removexattr(dentry, name); | 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 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 887 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
882 | if (rc == 0) | 888 | if (rc == 0) |
883 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); | 889 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
@@ -1047,7 +1053,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, | |||
1047 | int rc = 0; | 1053 | int rc = 0; |
1048 | struct smk_audit_info ad; | 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 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | 1057 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
1052 | 1058 | ||
1053 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 1059 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
@@ -1070,8 +1076,8 @@ static int smack_file_lock(struct file *file, unsigned int cmd) | |||
1070 | { | 1076 | { |
1071 | struct smk_audit_info ad; | 1077 | struct smk_audit_info ad; |
1072 | 1078 | ||
1073 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); | 1079 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); |
1074 | smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); | 1080 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
1075 | return smk_curacc(file->f_security, MAY_WRITE, &ad); | 1081 | return smk_curacc(file->f_security, MAY_WRITE, &ad); |
1076 | } | 1082 | } |
1077 | 1083 | ||
@@ -1089,7 +1095,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, | |||
1089 | struct smk_audit_info ad; | 1095 | struct smk_audit_info ad; |
1090 | int rc; | 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 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | 1099 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
1094 | 1100 | ||
1095 | switch (cmd) { | 1101 | switch (cmd) { |