diff options
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r-- | security/smack/smackfs.c | 134 |
1 files changed, 111 insertions, 23 deletions
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 160aa08e3cd5..3198cfe1dcc6 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -52,6 +52,7 @@ enum smk_inos { | |||
52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | 52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ |
53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ | 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ |
54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ | 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ |
55 | SMK_SYSLOG = 20, /* change syslog label) */ | ||
55 | }; | 56 | }; |
56 | 57 | ||
57 | /* | 58 | /* |
@@ -59,6 +60,7 @@ enum smk_inos { | |||
59 | */ | 60 | */ |
60 | static DEFINE_MUTEX(smack_cipso_lock); | 61 | static DEFINE_MUTEX(smack_cipso_lock); |
61 | static DEFINE_MUTEX(smack_ambient_lock); | 62 | static DEFINE_MUTEX(smack_ambient_lock); |
63 | static DEFINE_MUTEX(smack_syslog_lock); | ||
62 | static DEFINE_MUTEX(smk_netlbladdr_lock); | 64 | static DEFINE_MUTEX(smk_netlbladdr_lock); |
63 | 65 | ||
64 | /* | 66 | /* |
@@ -90,7 +92,13 @@ int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | |||
90 | * everyone. It is expected that the hat (^) label | 92 | * everyone. It is expected that the hat (^) label |
91 | * will be used if any label is used. | 93 | * will be used if any label is used. |
92 | */ | 94 | */ |
93 | char *smack_onlycap; | 95 | struct smack_known *smack_onlycap; |
96 | |||
97 | /* | ||
98 | * If this value is set restrict syslog use to the label specified. | ||
99 | * It can be reset via smackfs/syslog | ||
100 | */ | ||
101 | struct smack_known *smack_syslog_label; | ||
94 | 102 | ||
95 | /* | 103 | /* |
96 | * Certain IP addresses may be designated as single label hosts. | 104 | * Certain IP addresses may be designated as single label hosts. |
@@ -301,7 +309,8 @@ static int smk_perm_from_str(const char *string) | |||
301 | * @import: if non-zero, import labels | 309 | * @import: if non-zero, import labels |
302 | * @len: label length limit | 310 | * @len: label length limit |
303 | * | 311 | * |
304 | * Returns 0 on success, -1 on failure | 312 | * Returns 0 on success, -EINVAL on failure and -ENOENT when either subject |
313 | * or object is missing. | ||
305 | */ | 314 | */ |
306 | static int smk_fill_rule(const char *subject, const char *object, | 315 | static int smk_fill_rule(const char *subject, const char *object, |
307 | const char *access1, const char *access2, | 316 | const char *access1, const char *access2, |
@@ -314,28 +323,28 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
314 | if (import) { | 323 | if (import) { |
315 | rule->smk_subject = smk_import_entry(subject, len); | 324 | rule->smk_subject = smk_import_entry(subject, len); |
316 | if (rule->smk_subject == NULL) | 325 | if (rule->smk_subject == NULL) |
317 | return -1; | 326 | return -EINVAL; |
318 | 327 | ||
319 | rule->smk_object = smk_import(object, len); | 328 | rule->smk_object = smk_import(object, len); |
320 | if (rule->smk_object == NULL) | 329 | if (rule->smk_object == NULL) |
321 | return -1; | 330 | return -EINVAL; |
322 | } else { | 331 | } else { |
323 | cp = smk_parse_smack(subject, len); | 332 | cp = smk_parse_smack(subject, len); |
324 | if (cp == NULL) | 333 | if (cp == NULL) |
325 | return -1; | 334 | return -EINVAL; |
326 | skp = smk_find_entry(cp); | 335 | skp = smk_find_entry(cp); |
327 | kfree(cp); | 336 | kfree(cp); |
328 | if (skp == NULL) | 337 | if (skp == NULL) |
329 | return -1; | 338 | return -ENOENT; |
330 | rule->smk_subject = skp; | 339 | rule->smk_subject = skp; |
331 | 340 | ||
332 | cp = smk_parse_smack(object, len); | 341 | cp = smk_parse_smack(object, len); |
333 | if (cp == NULL) | 342 | if (cp == NULL) |
334 | return -1; | 343 | return -EINVAL; |
335 | skp = smk_find_entry(cp); | 344 | skp = smk_find_entry(cp); |
336 | kfree(cp); | 345 | kfree(cp); |
337 | if (skp == NULL) | 346 | if (skp == NULL) |
338 | return -1; | 347 | return -ENOENT; |
339 | rule->smk_object = skp->smk_known; | 348 | rule->smk_object = skp->smk_known; |
340 | } | 349 | } |
341 | 350 | ||
@@ -381,6 +390,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
381 | { | 390 | { |
382 | ssize_t cnt = 0; | 391 | ssize_t cnt = 0; |
383 | char *tok[4]; | 392 | char *tok[4]; |
393 | int rc; | ||
384 | int i; | 394 | int i; |
385 | 395 | ||
386 | /* | 396 | /* |
@@ -405,10 +415,8 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
405 | while (i < 4) | 415 | while (i < 4) |
406 | tok[i++] = NULL; | 416 | tok[i++] = NULL; |
407 | 417 | ||
408 | if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0)) | 418 | rc = smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0); |
409 | return -1; | 419 | return rc == 0 ? cnt : rc; |
410 | |||
411 | return cnt; | ||
412 | } | 420 | } |
413 | 421 | ||
414 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | 422 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ |
@@ -1603,7 +1611,7 @@ static const struct file_operations smk_ambient_ops = { | |||
1603 | }; | 1611 | }; |
1604 | 1612 | ||
1605 | /** | 1613 | /** |
1606 | * smk_read_onlycap - read() for /smack/onlycap | 1614 | * smk_read_onlycap - read() for smackfs/onlycap |
1607 | * @filp: file pointer, not actually used | 1615 | * @filp: file pointer, not actually used |
1608 | * @buf: where to put the result | 1616 | * @buf: where to put the result |
1609 | * @cn: maximum to send along | 1617 | * @cn: maximum to send along |
@@ -1622,7 +1630,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
1622 | return 0; | 1630 | return 0; |
1623 | 1631 | ||
1624 | if (smack_onlycap != NULL) | 1632 | if (smack_onlycap != NULL) |
1625 | smack = smack_onlycap; | 1633 | smack = smack_onlycap->smk_known; |
1626 | 1634 | ||
1627 | asize = strlen(smack) + 1; | 1635 | asize = strlen(smack) + 1; |
1628 | 1636 | ||
@@ -1633,7 +1641,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
1633 | } | 1641 | } |
1634 | 1642 | ||
1635 | /** | 1643 | /** |
1636 | * smk_write_onlycap - write() for /smack/onlycap | 1644 | * smk_write_onlycap - write() for smackfs/onlycap |
1637 | * @file: file pointer, not actually used | 1645 | * @file: file pointer, not actually used |
1638 | * @buf: where to get the data from | 1646 | * @buf: where to get the data from |
1639 | * @count: bytes sent | 1647 | * @count: bytes sent |
@@ -1656,7 +1664,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1656 | * explicitly for clarity. The smk_access() implementation | 1664 | * explicitly for clarity. The smk_access() implementation |
1657 | * would use smk_access(smack_onlycap, MAY_WRITE) | 1665 | * would use smk_access(smack_onlycap, MAY_WRITE) |
1658 | */ | 1666 | */ |
1659 | if (smack_onlycap != NULL && smack_onlycap != skp->smk_known) | 1667 | if (smack_onlycap != NULL && smack_onlycap != skp) |
1660 | return -EPERM; | 1668 | return -EPERM; |
1661 | 1669 | ||
1662 | data = kzalloc(count, GFP_KERNEL); | 1670 | data = kzalloc(count, GFP_KERNEL); |
@@ -1676,7 +1684,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1676 | if (copy_from_user(data, buf, count) != 0) | 1684 | if (copy_from_user(data, buf, count) != 0) |
1677 | rc = -EFAULT; | 1685 | rc = -EFAULT; |
1678 | else | 1686 | else |
1679 | smack_onlycap = smk_import(data, count); | 1687 | smack_onlycap = smk_import_entry(data, count); |
1680 | 1688 | ||
1681 | kfree(data); | 1689 | kfree(data); |
1682 | return rc; | 1690 | return rc; |
@@ -1856,11 +1864,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1856 | res = smk_parse_long_rule(data, &rule, 0, 3); | 1864 | res = smk_parse_long_rule(data, &rule, 0, 3); |
1857 | } | 1865 | } |
1858 | 1866 | ||
1859 | if (res < 0) | 1867 | if (res >= 0) |
1868 | res = smk_access(rule.smk_subject, rule.smk_object, | ||
1869 | rule.smk_access1, NULL); | ||
1870 | else if (res != -ENOENT) | ||
1860 | return -EINVAL; | 1871 | return -EINVAL; |
1861 | 1872 | ||
1862 | res = smk_access(rule.smk_subject, rule.smk_object, | ||
1863 | rule.smk_access1, NULL); | ||
1864 | data[0] = res == 0 ? '1' : '0'; | 1873 | data[0] = res == 0 ? '1' : '0'; |
1865 | data[1] = '\0'; | 1874 | data[1] = '\0'; |
1866 | 1875 | ||
@@ -2143,7 +2152,7 @@ static ssize_t smk_write_change_rule(struct file *file, const char __user *buf, | |||
2143 | /* | 2152 | /* |
2144 | * Must have privilege. | 2153 | * Must have privilege. |
2145 | */ | 2154 | */ |
2146 | if (!capable(CAP_MAC_ADMIN)) | 2155 | if (!smack_privileged(CAP_MAC_ADMIN)) |
2147 | return -EPERM; | 2156 | return -EPERM; |
2148 | 2157 | ||
2149 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | 2158 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, |
@@ -2158,12 +2167,89 @@ static const struct file_operations smk_change_rule_ops = { | |||
2158 | }; | 2167 | }; |
2159 | 2168 | ||
2160 | /** | 2169 | /** |
2161 | * smk_fill_super - fill the /smackfs superblock | 2170 | * smk_read_syslog - read() for smackfs/syslog |
2171 | * @filp: file pointer, not actually used | ||
2172 | * @buf: where to put the result | ||
2173 | * @cn: maximum to send along | ||
2174 | * @ppos: where to start | ||
2175 | * | ||
2176 | * Returns number of bytes read or error code, as appropriate | ||
2177 | */ | ||
2178 | static ssize_t smk_read_syslog(struct file *filp, char __user *buf, | ||
2179 | size_t cn, loff_t *ppos) | ||
2180 | { | ||
2181 | struct smack_known *skp; | ||
2182 | ssize_t rc = -EINVAL; | ||
2183 | int asize; | ||
2184 | |||
2185 | if (*ppos != 0) | ||
2186 | return 0; | ||
2187 | |||
2188 | if (smack_syslog_label == NULL) | ||
2189 | skp = &smack_known_star; | ||
2190 | else | ||
2191 | skp = smack_syslog_label; | ||
2192 | |||
2193 | asize = strlen(skp->smk_known) + 1; | ||
2194 | |||
2195 | if (cn >= asize) | ||
2196 | rc = simple_read_from_buffer(buf, cn, ppos, skp->smk_known, | ||
2197 | asize); | ||
2198 | |||
2199 | return rc; | ||
2200 | } | ||
2201 | |||
2202 | /** | ||
2203 | * smk_write_syslog - write() for smackfs/syslog | ||
2204 | * @file: file pointer, not actually used | ||
2205 | * @buf: where to get the data from | ||
2206 | * @count: bytes sent | ||
2207 | * @ppos: where to start | ||
2208 | * | ||
2209 | * Returns number of bytes written or error code, as appropriate | ||
2210 | */ | ||
2211 | static ssize_t smk_write_syslog(struct file *file, const char __user *buf, | ||
2212 | size_t count, loff_t *ppos) | ||
2213 | { | ||
2214 | char *data; | ||
2215 | struct smack_known *skp; | ||
2216 | int rc = count; | ||
2217 | |||
2218 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
2219 | return -EPERM; | ||
2220 | |||
2221 | data = kzalloc(count, GFP_KERNEL); | ||
2222 | if (data == NULL) | ||
2223 | return -ENOMEM; | ||
2224 | |||
2225 | if (copy_from_user(data, buf, count) != 0) | ||
2226 | rc = -EFAULT; | ||
2227 | else { | ||
2228 | skp = smk_import_entry(data, count); | ||
2229 | if (skp == NULL) | ||
2230 | rc = -EINVAL; | ||
2231 | else | ||
2232 | smack_syslog_label = smk_import_entry(data, count); | ||
2233 | } | ||
2234 | |||
2235 | kfree(data); | ||
2236 | return rc; | ||
2237 | } | ||
2238 | |||
2239 | static const struct file_operations smk_syslog_ops = { | ||
2240 | .read = smk_read_syslog, | ||
2241 | .write = smk_write_syslog, | ||
2242 | .llseek = default_llseek, | ||
2243 | }; | ||
2244 | |||
2245 | |||
2246 | /** | ||
2247 | * smk_fill_super - fill the smackfs superblock | ||
2162 | * @sb: the empty superblock | 2248 | * @sb: the empty superblock |
2163 | * @data: unused | 2249 | * @data: unused |
2164 | * @silent: unused | 2250 | * @silent: unused |
2165 | * | 2251 | * |
2166 | * Fill in the well known entries for /smack | 2252 | * Fill in the well known entries for the smack filesystem |
2167 | * | 2253 | * |
2168 | * Returns 0 on success, an error code on failure | 2254 | * Returns 0 on success, an error code on failure |
2169 | */ | 2255 | */ |
@@ -2208,6 +2294,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
2208 | S_IRUGO|S_IWUSR}, | 2294 | S_IRUGO|S_IWUSR}, |
2209 | [SMK_CHANGE_RULE] = { | 2295 | [SMK_CHANGE_RULE] = { |
2210 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, | 2296 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, |
2297 | [SMK_SYSLOG] = { | ||
2298 | "syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR}, | ||
2211 | /* last one */ | 2299 | /* last one */ |
2212 | {""} | 2300 | {""} |
2213 | }; | 2301 | }; |