diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 229 |
1 files changed, 155 insertions, 74 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1d0b37af2444..c61787b15f27 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -89,6 +89,8 @@ | |||
89 | #include <linux/msg.h> | 89 | #include <linux/msg.h> |
90 | #include <linux/shm.h> | 90 | #include <linux/shm.h> |
91 | #include <linux/bpf.h> | 91 | #include <linux/bpf.h> |
92 | #include <linux/kernfs.h> | ||
93 | #include <linux/stringhash.h> /* for hashlen_string() */ | ||
92 | #include <uapi/linux/mount.h> | 94 | #include <uapi/linux/mount.h> |
93 | 95 | ||
94 | #include "avc.h" | 96 | #include "avc.h" |
@@ -751,11 +753,13 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
751 | 753 | ||
752 | if (!strcmp(sb->s_type->name, "debugfs") || | 754 | if (!strcmp(sb->s_type->name, "debugfs") || |
753 | !strcmp(sb->s_type->name, "tracefs") || | 755 | !strcmp(sb->s_type->name, "tracefs") || |
754 | !strcmp(sb->s_type->name, "sysfs") || | 756 | !strcmp(sb->s_type->name, "pstore")) |
755 | !strcmp(sb->s_type->name, "pstore") || | 757 | sbsec->flags |= SE_SBGENFS; |
758 | |||
759 | if (!strcmp(sb->s_type->name, "sysfs") || | ||
756 | !strcmp(sb->s_type->name, "cgroup") || | 760 | !strcmp(sb->s_type->name, "cgroup") || |
757 | !strcmp(sb->s_type->name, "cgroup2")) | 761 | !strcmp(sb->s_type->name, "cgroup2")) |
758 | sbsec->flags |= SE_SBGENFS; | 762 | sbsec->flags |= SE_SBGENFS | SE_SBGENFS_XATTR; |
759 | 763 | ||
760 | if (!sbsec->behavior) { | 764 | if (!sbsec->behavior) { |
761 | /* | 765 | /* |
@@ -1354,6 +1358,67 @@ static int selinux_genfs_get_sid(struct dentry *dentry, | |||
1354 | return rc; | 1358 | return rc; |
1355 | } | 1359 | } |
1356 | 1360 | ||
1361 | static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry, | ||
1362 | u32 def_sid, u32 *sid) | ||
1363 | { | ||
1364 | #define INITCONTEXTLEN 255 | ||
1365 | char *context; | ||
1366 | unsigned int len; | ||
1367 | int rc; | ||
1368 | |||
1369 | len = INITCONTEXTLEN; | ||
1370 | context = kmalloc(len + 1, GFP_NOFS); | ||
1371 | if (!context) | ||
1372 | return -ENOMEM; | ||
1373 | |||
1374 | context[len] = '\0'; | ||
1375 | rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); | ||
1376 | if (rc == -ERANGE) { | ||
1377 | kfree(context); | ||
1378 | |||
1379 | /* Need a larger buffer. Query for the right size. */ | ||
1380 | rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0); | ||
1381 | if (rc < 0) | ||
1382 | return rc; | ||
1383 | |||
1384 | len = rc; | ||
1385 | context = kmalloc(len + 1, GFP_NOFS); | ||
1386 | if (!context) | ||
1387 | return -ENOMEM; | ||
1388 | |||
1389 | context[len] = '\0'; | ||
1390 | rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, | ||
1391 | context, len); | ||
1392 | } | ||
1393 | if (rc < 0) { | ||
1394 | kfree(context); | ||
1395 | if (rc != -ENODATA) { | ||
1396 | pr_warn("SELinux: %s: getxattr returned %d for dev=%s ino=%ld\n", | ||
1397 | __func__, -rc, inode->i_sb->s_id, inode->i_ino); | ||
1398 | return rc; | ||
1399 | } | ||
1400 | *sid = def_sid; | ||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | rc = security_context_to_sid_default(&selinux_state, context, rc, sid, | ||
1405 | def_sid, GFP_NOFS); | ||
1406 | if (rc) { | ||
1407 | char *dev = inode->i_sb->s_id; | ||
1408 | unsigned long ino = inode->i_ino; | ||
1409 | |||
1410 | if (rc == -EINVAL) { | ||
1411 | pr_notice_ratelimited("SELinux: inode=%lu on dev=%s was found to have an invalid context=%s. This indicates you may need to relabel the inode or the filesystem in question.\n", | ||
1412 | ino, dev, context); | ||
1413 | } else { | ||
1414 | pr_warn("SELinux: %s: context_to_sid(%s) returned %d for dev=%s ino=%ld\n", | ||
1415 | __func__, context, -rc, dev, ino); | ||
1416 | } | ||
1417 | } | ||
1418 | kfree(context); | ||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1357 | /* The inode's security attributes must be initialized before first use. */ | 1422 | /* The inode's security attributes must be initialized before first use. */ |
1358 | static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) | 1423 | static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) |
1359 | { | 1424 | { |
@@ -1362,9 +1427,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1362 | u32 task_sid, sid = 0; | 1427 | u32 task_sid, sid = 0; |
1363 | u16 sclass; | 1428 | u16 sclass; |
1364 | struct dentry *dentry; | 1429 | struct dentry *dentry; |
1365 | #define INITCONTEXTLEN 255 | ||
1366 | char *context = NULL; | ||
1367 | unsigned len = 0; | ||
1368 | int rc = 0; | 1430 | int rc = 0; |
1369 | 1431 | ||
1370 | if (isec->initialized == LABEL_INITIALIZED) | 1432 | if (isec->initialized == LABEL_INITIALIZED) |
@@ -1432,72 +1494,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1432 | goto out; | 1494 | goto out; |
1433 | } | 1495 | } |
1434 | 1496 | ||
1435 | len = INITCONTEXTLEN; | 1497 | rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid, |
1436 | context = kmalloc(len+1, GFP_NOFS); | 1498 | &sid); |
1437 | if (!context) { | ||
1438 | rc = -ENOMEM; | ||
1439 | dput(dentry); | ||
1440 | goto out; | ||
1441 | } | ||
1442 | context[len] = '\0'; | ||
1443 | rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); | ||
1444 | if (rc == -ERANGE) { | ||
1445 | kfree(context); | ||
1446 | |||
1447 | /* Need a larger buffer. Query for the right size. */ | ||
1448 | rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0); | ||
1449 | if (rc < 0) { | ||
1450 | dput(dentry); | ||
1451 | goto out; | ||
1452 | } | ||
1453 | len = rc; | ||
1454 | context = kmalloc(len+1, GFP_NOFS); | ||
1455 | if (!context) { | ||
1456 | rc = -ENOMEM; | ||
1457 | dput(dentry); | ||
1458 | goto out; | ||
1459 | } | ||
1460 | context[len] = '\0'; | ||
1461 | rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); | ||
1462 | } | ||
1463 | dput(dentry); | 1499 | dput(dentry); |
1464 | if (rc < 0) { | 1500 | if (rc) |
1465 | if (rc != -ENODATA) { | 1501 | goto out; |
1466 | pr_warn("SELinux: %s: getxattr returned " | ||
1467 | "%d for dev=%s ino=%ld\n", __func__, | ||
1468 | -rc, inode->i_sb->s_id, inode->i_ino); | ||
1469 | kfree(context); | ||
1470 | goto out; | ||
1471 | } | ||
1472 | /* Map ENODATA to the default file SID */ | ||
1473 | sid = sbsec->def_sid; | ||
1474 | rc = 0; | ||
1475 | } else { | ||
1476 | rc = security_context_to_sid_default(&selinux_state, | ||
1477 | context, rc, &sid, | ||
1478 | sbsec->def_sid, | ||
1479 | GFP_NOFS); | ||
1480 | if (rc) { | ||
1481 | char *dev = inode->i_sb->s_id; | ||
1482 | unsigned long ino = inode->i_ino; | ||
1483 | |||
1484 | if (rc == -EINVAL) { | ||
1485 | if (printk_ratelimit()) | ||
1486 | pr_notice("SELinux: inode=%lu on dev=%s was found to have an invalid " | ||
1487 | "context=%s. This indicates you may need to relabel the inode or the " | ||
1488 | "filesystem in question.\n", ino, dev, context); | ||
1489 | } else { | ||
1490 | pr_warn("SELinux: %s: context_to_sid(%s) " | ||
1491 | "returned %d for dev=%s ino=%ld\n", | ||
1492 | __func__, context, -rc, dev, ino); | ||
1493 | } | ||
1494 | kfree(context); | ||
1495 | /* Leave with the unlabeled SID */ | ||
1496 | rc = 0; | ||
1497 | break; | ||
1498 | } | ||
1499 | } | ||
1500 | kfree(context); | ||
1501 | break; | 1502 | break; |
1502 | case SECURITY_FS_USE_TASK: | 1503 | case SECURITY_FS_USE_TASK: |
1503 | sid = task_sid; | 1504 | sid = task_sid; |
@@ -1548,9 +1549,21 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1548 | goto out; | 1549 | goto out; |
1549 | rc = selinux_genfs_get_sid(dentry, sclass, | 1550 | rc = selinux_genfs_get_sid(dentry, sclass, |
1550 | sbsec->flags, &sid); | 1551 | sbsec->flags, &sid); |
1551 | dput(dentry); | 1552 | if (rc) { |
1552 | if (rc) | 1553 | dput(dentry); |
1553 | goto out; | 1554 | goto out; |
1555 | } | ||
1556 | |||
1557 | if ((sbsec->flags & SE_SBGENFS_XATTR) && | ||
1558 | (inode->i_opflags & IOP_XATTR)) { | ||
1559 | rc = inode_doinit_use_xattr(inode, dentry, | ||
1560 | sid, &sid); | ||
1561 | if (rc) { | ||
1562 | dput(dentry); | ||
1563 | goto out; | ||
1564 | } | ||
1565 | } | ||
1566 | dput(dentry); | ||
1554 | } | 1567 | } |
1555 | break; | 1568 | break; |
1556 | } | 1569 | } |
@@ -3371,6 +3384,67 @@ static int selinux_inode_copy_up_xattr(const char *name) | |||
3371 | return -EOPNOTSUPP; | 3384 | return -EOPNOTSUPP; |
3372 | } | 3385 | } |
3373 | 3386 | ||
3387 | /* kernfs node operations */ | ||
3388 | |||
3389 | static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, | ||
3390 | struct kernfs_node *kn) | ||
3391 | { | ||
3392 | const struct task_security_struct *tsec = current_security(); | ||
3393 | u32 parent_sid, newsid, clen; | ||
3394 | int rc; | ||
3395 | char *context; | ||
3396 | |||
3397 | rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, NULL, 0); | ||
3398 | if (rc == -ENODATA) | ||
3399 | return 0; | ||
3400 | else if (rc < 0) | ||
3401 | return rc; | ||
3402 | |||
3403 | clen = (u32)rc; | ||
3404 | context = kmalloc(clen, GFP_KERNEL); | ||
3405 | if (!context) | ||
3406 | return -ENOMEM; | ||
3407 | |||
3408 | rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, context, clen); | ||
3409 | if (rc < 0) { | ||
3410 | kfree(context); | ||
3411 | return rc; | ||
3412 | } | ||
3413 | |||
3414 | rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid, | ||
3415 | GFP_KERNEL); | ||
3416 | kfree(context); | ||
3417 | if (rc) | ||
3418 | return rc; | ||
3419 | |||
3420 | if (tsec->create_sid) { | ||
3421 | newsid = tsec->create_sid; | ||
3422 | } else { | ||
3423 | u16 secclass = inode_mode_to_security_class(kn->mode); | ||
3424 | struct qstr q; | ||
3425 | |||
3426 | q.name = kn->name; | ||
3427 | q.hash_len = hashlen_string(kn_dir, kn->name); | ||
3428 | |||
3429 | rc = security_transition_sid(&selinux_state, tsec->sid, | ||
3430 | parent_sid, secclass, &q, | ||
3431 | &newsid); | ||
3432 | if (rc) | ||
3433 | return rc; | ||
3434 | } | ||
3435 | |||
3436 | rc = security_sid_to_context_force(&selinux_state, newsid, | ||
3437 | &context, &clen); | ||
3438 | if (rc) | ||
3439 | return rc; | ||
3440 | |||
3441 | rc = kernfs_xattr_set(kn, XATTR_NAME_SELINUX, context, clen, | ||
3442 | XATTR_CREATE); | ||
3443 | kfree(context); | ||
3444 | return rc; | ||
3445 | } | ||
3446 | |||
3447 | |||
3374 | /* file security operations */ | 3448 | /* file security operations */ |
3375 | 3449 | ||
3376 | static int selinux_revalidate_file_permission(struct file *file, int mask) | 3450 | static int selinux_revalidate_file_permission(struct file *file, int mask) |
@@ -4438,7 +4512,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4438 | struct lsm_network_audit net = {0,}; | 4512 | struct lsm_network_audit net = {0,}; |
4439 | struct sockaddr_in *addr4 = NULL; | 4513 | struct sockaddr_in *addr4 = NULL; |
4440 | struct sockaddr_in6 *addr6 = NULL; | 4514 | struct sockaddr_in6 *addr6 = NULL; |
4441 | u16 family_sa = address->sa_family; | 4515 | u16 family_sa; |
4442 | unsigned short snum; | 4516 | unsigned short snum; |
4443 | u32 sid, node_perm; | 4517 | u32 sid, node_perm; |
4444 | 4518 | ||
@@ -4448,6 +4522,9 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
4448 | * need to check address->sa_family as it is possible to have | 4522 | * need to check address->sa_family as it is possible to have |
4449 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. | 4523 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. |
4450 | */ | 4524 | */ |
4525 | if (addrlen < offsetofend(struct sockaddr, sa_family)) | ||
4526 | return -EINVAL; | ||
4527 | family_sa = address->sa_family; | ||
4451 | switch (family_sa) { | 4528 | switch (family_sa) { |
4452 | case AF_UNSPEC: | 4529 | case AF_UNSPEC: |
4453 | case AF_INET: | 4530 | case AF_INET: |
@@ -4580,6 +4657,8 @@ static int selinux_socket_connect_helper(struct socket *sock, | |||
4580 | * need to check address->sa_family as it is possible to have | 4657 | * need to check address->sa_family as it is possible to have |
4581 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. | 4658 | * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. |
4582 | */ | 4659 | */ |
4660 | if (addrlen < offsetofend(struct sockaddr, sa_family)) | ||
4661 | return -EINVAL; | ||
4583 | switch (address->sa_family) { | 4662 | switch (address->sa_family) { |
4584 | case AF_INET: | 4663 | case AF_INET: |
4585 | addr4 = (struct sockaddr_in *)address; | 4664 | addr4 = (struct sockaddr_in *)address; |
@@ -6719,6 +6798,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6719 | LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), | 6798 | LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), |
6720 | LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), | 6799 | LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), |
6721 | 6800 | ||
6801 | LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security), | ||
6802 | |||
6722 | LSM_HOOK_INIT(file_permission, selinux_file_permission), | 6803 | LSM_HOOK_INIT(file_permission, selinux_file_permission), |
6723 | LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), | 6804 | LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), |
6724 | LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), | 6805 | LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), |