| .. | .. |
|---|
| 973 | 973 | const struct qstr *qstr, const char **name, |
|---|
| 974 | 974 | void **value, size_t *len) |
|---|
| 975 | 975 | { |
|---|
| 976 | + struct task_smack *tsp = smack_cred(current_cred()); |
|---|
| 976 | 977 | struct inode_smack *issp = smack_inode(inode); |
|---|
| 977 | | - struct smack_known *skp = smk_of_current(); |
|---|
| 978 | + struct smack_known *skp = smk_of_task(tsp); |
|---|
| 978 | 979 | struct smack_known *isp = smk_of_inode(inode); |
|---|
| 979 | 980 | struct smack_known *dsp = smk_of_inode(dir); |
|---|
| 980 | 981 | int may; |
|---|
| .. | .. |
|---|
| 983 | 984 | *name = XATTR_SMACK_SUFFIX; |
|---|
| 984 | 985 | |
|---|
| 985 | 986 | if (value && len) { |
|---|
| 986 | | - rcu_read_lock(); |
|---|
| 987 | | - may = smk_access_entry(skp->smk_known, dsp->smk_known, |
|---|
| 988 | | - &skp->smk_rules); |
|---|
| 989 | | - rcu_read_unlock(); |
|---|
| 987 | + /* |
|---|
| 988 | + * If equal, transmuting already occurred in |
|---|
| 989 | + * smack_dentry_create_files_as(). No need to check again. |
|---|
| 990 | + */ |
|---|
| 991 | + if (tsp->smk_task != tsp->smk_transmuted) { |
|---|
| 992 | + rcu_read_lock(); |
|---|
| 993 | + may = smk_access_entry(skp->smk_known, dsp->smk_known, |
|---|
| 994 | + &skp->smk_rules); |
|---|
| 995 | + rcu_read_unlock(); |
|---|
| 996 | + } |
|---|
| 990 | 997 | |
|---|
| 991 | 998 | /* |
|---|
| 992 | | - * If the access rule allows transmutation and |
|---|
| 993 | | - * the directory requests transmutation then |
|---|
| 994 | | - * by all means transmute. |
|---|
| 999 | + * In addition to having smk_task equal to smk_transmuted, |
|---|
| 1000 | + * if the access rule allows transmutation and the directory |
|---|
| 1001 | + * requests transmutation then by all means transmute. |
|---|
| 995 | 1002 | * Mark the inode as changed. |
|---|
| 996 | 1003 | */ |
|---|
| 997 | | - if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && |
|---|
| 998 | | - smk_inode_transmutable(dir)) { |
|---|
| 999 | | - isp = dsp; |
|---|
| 1004 | + if ((tsp->smk_task == tsp->smk_transmuted) || |
|---|
| 1005 | + (may > 0 && ((may & MAY_TRANSMUTE) != 0) && |
|---|
| 1006 | + smk_inode_transmutable(dir))) { |
|---|
| 1007 | + /* |
|---|
| 1008 | + * The caller of smack_dentry_create_files_as() |
|---|
| 1009 | + * should have overridden the current cred, so the |
|---|
| 1010 | + * inode label was already set correctly in |
|---|
| 1011 | + * smack_inode_alloc_security(). |
|---|
| 1012 | + */ |
|---|
| 1013 | + if (tsp->smk_task != tsp->smk_transmuted) |
|---|
| 1014 | + isp = dsp; |
|---|
| 1000 | 1015 | issp->smk_flags |= SMK_INODE_CHANGED; |
|---|
| 1001 | 1016 | } |
|---|
| 1002 | 1017 | |
|---|
| .. | .. |
|---|
| 1430 | 1445 | struct super_block *sbp; |
|---|
| 1431 | 1446 | struct inode *ip = (struct inode *)inode; |
|---|
| 1432 | 1447 | struct smack_known *isp; |
|---|
| 1448 | + struct inode_smack *ispp; |
|---|
| 1449 | + size_t label_len; |
|---|
| 1450 | + char *label = NULL; |
|---|
| 1433 | 1451 | |
|---|
| 1434 | | - if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) |
|---|
| 1452 | + if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { |
|---|
| 1435 | 1453 | isp = smk_of_inode(inode); |
|---|
| 1436 | | - else { |
|---|
| 1454 | + } else if (strcmp(name, XATTR_SMACK_TRANSMUTE) == 0) { |
|---|
| 1455 | + ispp = smack_inode(inode); |
|---|
| 1456 | + if (ispp->smk_flags & SMK_INODE_TRANSMUTE) |
|---|
| 1457 | + label = TRANS_TRUE; |
|---|
| 1458 | + else |
|---|
| 1459 | + label = ""; |
|---|
| 1460 | + } else { |
|---|
| 1437 | 1461 | /* |
|---|
| 1438 | 1462 | * The rest of the Smack xattrs are only on sockets. |
|---|
| 1439 | 1463 | */ |
|---|
| .. | .. |
|---|
| 1455 | 1479 | return -EOPNOTSUPP; |
|---|
| 1456 | 1480 | } |
|---|
| 1457 | 1481 | |
|---|
| 1482 | + if (!label) |
|---|
| 1483 | + label = isp->smk_known; |
|---|
| 1484 | + |
|---|
| 1485 | + label_len = strlen(label); |
|---|
| 1486 | + |
|---|
| 1458 | 1487 | if (alloc) { |
|---|
| 1459 | | - *buffer = kstrdup(isp->smk_known, GFP_KERNEL); |
|---|
| 1488 | + *buffer = kstrdup(label, GFP_KERNEL); |
|---|
| 1460 | 1489 | if (*buffer == NULL) |
|---|
| 1461 | 1490 | return -ENOMEM; |
|---|
| 1462 | 1491 | } |
|---|
| 1463 | 1492 | |
|---|
| 1464 | | - return strlen(isp->smk_known); |
|---|
| 1493 | + return label_len; |
|---|
| 1465 | 1494 | } |
|---|
| 1466 | 1495 | |
|---|
| 1467 | 1496 | |
|---|
| .. | .. |
|---|
| 4635 | 4664 | /* |
|---|
| 4636 | 4665 | * Get label from overlay inode and set it in create_sid |
|---|
| 4637 | 4666 | */ |
|---|
| 4638 | | - isp = smack_inode(d_inode(dentry->d_parent)); |
|---|
| 4667 | + isp = smack_inode(d_inode(dentry)); |
|---|
| 4639 | 4668 | skp = isp->smk_inode; |
|---|
| 4640 | 4669 | tsp->smk_task = skp; |
|---|
| 4641 | 4670 | *new = new_creds; |
|---|
| .. | .. |
|---|
| 4686 | 4715 | * providing access is transmuting use the containing |
|---|
| 4687 | 4716 | * directory label instead of the process label. |
|---|
| 4688 | 4717 | */ |
|---|
| 4689 | | - if (may > 0 && (may & MAY_TRANSMUTE)) |
|---|
| 4718 | + if (may > 0 && (may & MAY_TRANSMUTE)) { |
|---|
| 4690 | 4719 | ntsp->smk_task = isp->smk_inode; |
|---|
| 4720 | + ntsp->smk_transmuted = ntsp->smk_task; |
|---|
| 4721 | + } |
|---|
| 4691 | 4722 | } |
|---|
| 4692 | 4723 | return 0; |
|---|
| 4693 | 4724 | } |
|---|