diff options
26 files changed, 1229 insertions, 423 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index df18d87c4837..2193be53e773 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
| @@ -315,3 +315,15 @@ When: 2.6.29 (ideally) or 2.6.30 (more likely) | |||
| 315 | Why: Deprecated by the new (standard) device driver binding model. Use | 315 | Why: Deprecated by the new (standard) device driver binding model. Use |
| 316 | i2c_driver->probe() and ->remove() instead. | 316 | i2c_driver->probe() and ->remove() instead. |
| 317 | Who: Jean Delvare <khali@linux-fr.org> | 317 | Who: Jean Delvare <khali@linux-fr.org> |
| 318 | |||
| 319 | --------------------------- | ||
| 320 | |||
| 321 | What: SELinux "compat_net" functionality | ||
| 322 | When: 2.6.30 at the earliest | ||
| 323 | Why: In 2.6.18 the Secmark concept was introduced to replace the "compat_net" | ||
| 324 | network access control functionality of SELinux. Secmark offers both | ||
| 325 | better performance and greater flexibility than the "compat_net" | ||
| 326 | mechanism. Now that the major Linux distributions have moved to | ||
| 327 | Secmark, it is time to deprecate the older mechanism and start the | ||
| 328 | process of removing the old code. | ||
| 329 | Who: Paul Moore <paul.moore@hp.com> | ||
diff --git a/include/linux/capability.h b/include/linux/capability.h index e22f48c2a46f..02bdb768d43b 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
| @@ -529,8 +529,21 @@ extern const kernel_cap_t __cap_init_eff_set; | |||
| 529 | * | 529 | * |
| 530 | * Note that this does not set PF_SUPERPRIV on the task. | 530 | * Note that this does not set PF_SUPERPRIV on the task. |
| 531 | */ | 531 | */ |
| 532 | #define has_capability(t, cap) (security_capable((t), (cap)) == 0) | 532 | #define has_capability(t, cap) (security_real_capable((t), (cap)) == 0) |
| 533 | #define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0) | 533 | |
| 534 | /** | ||
| 535 | * has_capability_noaudit - Determine if a task has a superior capability available (unaudited) | ||
| 536 | * @t: The task in question | ||
| 537 | * @cap: The capability to be tested for | ||
| 538 | * | ||
| 539 | * Return true if the specified task has the given superior capability | ||
| 540 | * currently in effect, false if not, but don't write an audit message for the | ||
| 541 | * check. | ||
| 542 | * | ||
| 543 | * Note that this does not set PF_SUPERPRIV on the task. | ||
| 544 | */ | ||
| 545 | #define has_capability_noaudit(t, cap) \ | ||
| 546 | (security_real_capable_noaudit((t), (cap)) == 0) | ||
| 534 | 547 | ||
| 535 | extern int capable(int cap); | 548 | extern int capable(int cap); |
| 536 | 549 | ||
diff --git a/include/linux/security.h b/include/linux/security.h index b92b5e453f64..1f2ab6353c00 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -48,7 +48,8 @@ struct audit_krule; | |||
| 48 | * These functions are in security/capability.c and are used | 48 | * These functions are in security/capability.c and are used |
| 49 | * as the default capabilities functions | 49 | * as the default capabilities functions |
| 50 | */ | 50 | */ |
| 51 | extern int cap_capable(struct task_struct *tsk, int cap, int audit); | 51 | extern int cap_capable(struct task_struct *tsk, const struct cred *cred, |
| 52 | int cap, int audit); | ||
| 52 | extern int cap_settime(struct timespec *ts, struct timezone *tz); | 53 | extern int cap_settime(struct timespec *ts, struct timezone *tz); |
| 53 | extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); | 54 | extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); |
| 54 | extern int cap_ptrace_traceme(struct task_struct *parent); | 55 | extern int cap_ptrace_traceme(struct task_struct *parent); |
| @@ -1251,9 +1252,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 1251 | * @permitted contains the permitted capability set. | 1252 | * @permitted contains the permitted capability set. |
| 1252 | * Return 0 and update @new if permission is granted. | 1253 | * Return 0 and update @new if permission is granted. |
| 1253 | * @capable: | 1254 | * @capable: |
| 1254 | * Check whether the @tsk process has the @cap capability. | 1255 | * Check whether the @tsk process has the @cap capability in the indicated |
| 1256 | * credentials. | ||
| 1255 | * @tsk contains the task_struct for the process. | 1257 | * @tsk contains the task_struct for the process. |
| 1258 | * @cred contains the credentials to use. | ||
| 1256 | * @cap contains the capability <include/linux/capability.h>. | 1259 | * @cap contains the capability <include/linux/capability.h>. |
| 1260 | * @audit: Whether to write an audit message or not | ||
| 1257 | * Return 0 if the capability is granted for @tsk. | 1261 | * Return 0 if the capability is granted for @tsk. |
| 1258 | * @acct: | 1262 | * @acct: |
| 1259 | * Check permission before enabling or disabling process accounting. If | 1263 | * Check permission before enabling or disabling process accounting. If |
| @@ -1346,7 +1350,8 @@ struct security_operations { | |||
| 1346 | const kernel_cap_t *effective, | 1350 | const kernel_cap_t *effective, |
| 1347 | const kernel_cap_t *inheritable, | 1351 | const kernel_cap_t *inheritable, |
| 1348 | const kernel_cap_t *permitted); | 1352 | const kernel_cap_t *permitted); |
| 1349 | int (*capable) (struct task_struct *tsk, int cap, int audit); | 1353 | int (*capable) (struct task_struct *tsk, const struct cred *cred, |
| 1354 | int cap, int audit); | ||
| 1350 | int (*acct) (struct file *file); | 1355 | int (*acct) (struct file *file); |
| 1351 | int (*sysctl) (struct ctl_table *table, int op); | 1356 | int (*sysctl) (struct ctl_table *table, int op); |
| 1352 | int (*quotactl) (int cmds, int type, int id, struct super_block *sb); | 1357 | int (*quotactl) (int cmds, int type, int id, struct super_block *sb); |
| @@ -1628,8 +1633,9 @@ int security_capset(struct cred *new, const struct cred *old, | |||
| 1628 | const kernel_cap_t *effective, | 1633 | const kernel_cap_t *effective, |
| 1629 | const kernel_cap_t *inheritable, | 1634 | const kernel_cap_t *inheritable, |
| 1630 | const kernel_cap_t *permitted); | 1635 | const kernel_cap_t *permitted); |
| 1631 | int security_capable(struct task_struct *tsk, int cap); | 1636 | int security_capable(int cap); |
| 1632 | int security_capable_noaudit(struct task_struct *tsk, int cap); | 1637 | int security_real_capable(struct task_struct *tsk, int cap); |
| 1638 | int security_real_capable_noaudit(struct task_struct *tsk, int cap); | ||
| 1633 | int security_acct(struct file *file); | 1639 | int security_acct(struct file *file); |
| 1634 | int security_sysctl(struct ctl_table *table, int op); | 1640 | int security_sysctl(struct ctl_table *table, int op); |
| 1635 | int security_quotactl(int cmds, int type, int id, struct super_block *sb); | 1641 | int security_quotactl(int cmds, int type, int id, struct super_block *sb); |
| @@ -1826,14 +1832,31 @@ static inline int security_capset(struct cred *new, | |||
| 1826 | return cap_capset(new, old, effective, inheritable, permitted); | 1832 | return cap_capset(new, old, effective, inheritable, permitted); |
| 1827 | } | 1833 | } |
| 1828 | 1834 | ||
| 1829 | static inline int security_capable(struct task_struct *tsk, int cap) | 1835 | static inline int security_capable(int cap) |
| 1830 | { | 1836 | { |
| 1831 | return cap_capable(tsk, cap, SECURITY_CAP_AUDIT); | 1837 | return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT); |
| 1832 | } | 1838 | } |
| 1833 | 1839 | ||
| 1834 | static inline int security_capable_noaudit(struct task_struct *tsk, int cap) | 1840 | static inline int security_real_capable(struct task_struct *tsk, int cap) |
| 1835 | { | 1841 | { |
| 1836 | return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT); | 1842 | int ret; |
| 1843 | |||
| 1844 | rcu_read_lock(); | ||
| 1845 | ret = cap_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT); | ||
| 1846 | rcu_read_unlock(); | ||
| 1847 | return ret; | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | static inline | ||
| 1851 | int security_real_capable_noaudit(struct task_struct *tsk, int cap) | ||
| 1852 | { | ||
| 1853 | int ret; | ||
| 1854 | |||
| 1855 | rcu_read_lock(); | ||
| 1856 | ret = cap_capable(tsk, __task_cred(tsk), cap, | ||
| 1857 | SECURITY_CAP_NOAUDIT); | ||
| 1858 | rcu_read_unlock(); | ||
| 1859 | return ret; | ||
| 1837 | } | 1860 | } |
| 1838 | 1861 | ||
| 1839 | static inline int security_acct(struct file *file) | 1862 | static inline int security_acct(struct file *file) |
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index 9909774eb998..bedc7f62e35d 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h | |||
| @@ -131,7 +131,8 @@ extern int cipso_v4_rbm_strictvalid; | |||
| 131 | */ | 131 | */ |
| 132 | 132 | ||
| 133 | #ifdef CONFIG_NETLABEL | 133 | #ifdef CONFIG_NETLABEL |
| 134 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); | 134 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, |
| 135 | struct netlbl_audit *audit_info); | ||
| 135 | void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); | 136 | void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); |
| 136 | int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); | 137 | int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); |
| 137 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); | 138 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); |
| @@ -140,7 +141,8 @@ int cipso_v4_doi_walk(u32 *skip_cnt, | |||
| 140 | int (*callback) (struct cipso_v4_doi *doi_def, void *arg), | 141 | int (*callback) (struct cipso_v4_doi *doi_def, void *arg), |
| 141 | void *cb_arg); | 142 | void *cb_arg); |
| 142 | #else | 143 | #else |
| 143 | static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | 144 | static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, |
| 145 | struct netlbl_audit *audit_info) | ||
| 144 | { | 146 | { |
| 145 | return -ENOSYS; | 147 | return -ENOSYS; |
| 146 | } | 148 | } |
diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 17c442a4514e..749011eedc0b 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h | |||
| @@ -33,6 +33,8 @@ | |||
| 33 | #include <linux/types.h> | 33 | #include <linux/types.h> |
| 34 | #include <linux/net.h> | 34 | #include <linux/net.h> |
| 35 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
| 36 | #include <linux/in.h> | ||
| 37 | #include <linux/in6.h> | ||
| 36 | #include <net/netlink.h> | 38 | #include <net/netlink.h> |
| 37 | #include <asm/atomic.h> | 39 | #include <asm/atomic.h> |
| 38 | 40 | ||
| @@ -353,13 +355,37 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr) | |||
| 353 | /* | 355 | /* |
| 354 | * LSM configuration operations | 356 | * LSM configuration operations |
| 355 | */ | 357 | */ |
| 356 | int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info); | 358 | int netlbl_cfg_map_del(const char *domain, |
| 357 | int netlbl_cfg_unlbl_add_map(const char *domain, | 359 | u16 family, |
| 360 | const void *addr, | ||
| 361 | const void *mask, | ||
| 362 | struct netlbl_audit *audit_info); | ||
| 363 | int netlbl_cfg_unlbl_map_add(const char *domain, | ||
| 364 | u16 family, | ||
| 365 | const void *addr, | ||
| 366 | const void *mask, | ||
| 358 | struct netlbl_audit *audit_info); | 367 | struct netlbl_audit *audit_info); |
| 359 | int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | 368 | int netlbl_cfg_unlbl_static_add(struct net *net, |
| 369 | const char *dev_name, | ||
| 370 | const void *addr, | ||
| 371 | const void *mask, | ||
| 372 | u16 family, | ||
| 373 | u32 secid, | ||
| 374 | struct netlbl_audit *audit_info); | ||
| 375 | int netlbl_cfg_unlbl_static_del(struct net *net, | ||
| 376 | const char *dev_name, | ||
| 377 | const void *addr, | ||
| 378 | const void *mask, | ||
| 379 | u16 family, | ||
| 380 | struct netlbl_audit *audit_info); | ||
| 381 | int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, | ||
| 382 | struct netlbl_audit *audit_info); | ||
| 383 | void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info); | ||
| 384 | int netlbl_cfg_cipsov4_map_add(u32 doi, | ||
| 360 | const char *domain, | 385 | const char *domain, |
| 386 | const struct in_addr *addr, | ||
| 387 | const struct in_addr *mask, | ||
| 361 | struct netlbl_audit *audit_info); | 388 | struct netlbl_audit *audit_info); |
| 362 | |||
| 363 | /* | 389 | /* |
| 364 | * LSM security attribute operations | 390 | * LSM security attribute operations |
| 365 | */ | 391 | */ |
| @@ -401,19 +427,62 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway); | |||
| 401 | void netlbl_cache_invalidate(void); | 427 | void netlbl_cache_invalidate(void); |
| 402 | int netlbl_cache_add(const struct sk_buff *skb, | 428 | int netlbl_cache_add(const struct sk_buff *skb, |
| 403 | const struct netlbl_lsm_secattr *secattr); | 429 | const struct netlbl_lsm_secattr *secattr); |
| 430 | |||
| 431 | /* | ||
| 432 | * Protocol engine operations | ||
| 433 | */ | ||
| 434 | struct audit_buffer *netlbl_audit_start(int type, | ||
| 435 | struct netlbl_audit *audit_info); | ||
| 404 | #else | 436 | #else |
| 405 | static inline int netlbl_cfg_map_del(const char *domain, | 437 | static inline int netlbl_cfg_map_del(const char *domain, |
| 438 | u16 family, | ||
| 439 | const void *addr, | ||
| 440 | const void *mask, | ||
| 406 | struct netlbl_audit *audit_info) | 441 | struct netlbl_audit *audit_info) |
| 407 | { | 442 | { |
| 408 | return -ENOSYS; | 443 | return -ENOSYS; |
| 409 | } | 444 | } |
| 410 | static inline int netlbl_cfg_unlbl_add_map(const char *domain, | 445 | static inline int netlbl_cfg_unlbl_map_add(const char *domain, |
| 446 | u16 family, | ||
| 447 | void *addr, | ||
| 448 | void *mask, | ||
| 411 | struct netlbl_audit *audit_info) | 449 | struct netlbl_audit *audit_info) |
| 412 | { | 450 | { |
| 413 | return -ENOSYS; | 451 | return -ENOSYS; |
| 414 | } | 452 | } |
| 415 | static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | 453 | static inline int netlbl_cfg_unlbl_static_add(struct net *net, |
| 454 | const char *dev_name, | ||
| 455 | const void *addr, | ||
| 456 | const void *mask, | ||
| 457 | u16 family, | ||
| 458 | u32 secid, | ||
| 459 | struct netlbl_audit *audit_info) | ||
| 460 | { | ||
| 461 | return -ENOSYS; | ||
| 462 | } | ||
| 463 | static inline int netlbl_cfg_unlbl_static_del(struct net *net, | ||
| 464 | const char *dev_name, | ||
| 465 | const void *addr, | ||
| 466 | const void *mask, | ||
| 467 | u16 family, | ||
| 468 | struct netlbl_audit *audit_info) | ||
| 469 | { | ||
| 470 | return -ENOSYS; | ||
| 471 | } | ||
| 472 | static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, | ||
| 473 | struct netlbl_audit *audit_info) | ||
| 474 | { | ||
| 475 | return -ENOSYS; | ||
| 476 | } | ||
| 477 | static inline void netlbl_cfg_cipsov4_del(u32 doi, | ||
| 478 | struct netlbl_audit *audit_info) | ||
| 479 | { | ||
| 480 | return; | ||
| 481 | } | ||
| 482 | static inline int netlbl_cfg_cipsov4_map_add(u32 doi, | ||
| 416 | const char *domain, | 483 | const char *domain, |
| 484 | const struct in_addr *addr, | ||
| 485 | const struct in_addr *mask, | ||
| 417 | struct netlbl_audit *audit_info) | 486 | struct netlbl_audit *audit_info) |
| 418 | { | 487 | { |
| 419 | return -ENOSYS; | 488 | return -ENOSYS; |
| @@ -495,6 +564,11 @@ static inline int netlbl_cache_add(const struct sk_buff *skb, | |||
| 495 | { | 564 | { |
| 496 | return 0; | 565 | return 0; |
| 497 | } | 566 | } |
| 567 | static inline struct audit_buffer *netlbl_audit_start(int type, | ||
| 568 | struct netlbl_audit *audit_info) | ||
| 569 | { | ||
| 570 | return NULL; | ||
| 571 | } | ||
| 498 | #endif /* CONFIG_NETLABEL */ | 572 | #endif /* CONFIG_NETLABEL */ |
| 499 | 573 | ||
| 500 | #endif /* _NETLABEL_H */ | 574 | #endif /* _NETLABEL_H */ |
diff --git a/kernel/capability.c b/kernel/capability.c index c598d9d5be4f..688926e496be 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
| @@ -306,7 +306,7 @@ int capable(int cap) | |||
| 306 | BUG(); | 306 | BUG(); |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | if (has_capability(current, cap)) { | 309 | if (security_capable(cap) == 0) { |
| 310 | current->flags |= PF_SUPERPRIV; | 310 | current->flags |= PF_SUPERPRIV; |
| 311 | return 1; | 311 | return 1; |
| 312 | } | 312 | } |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e52799047a5f..6bb2635b5ded 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| 39 | #include <linux/string.h> | 39 | #include <linux/string.h> |
| 40 | #include <linux/jhash.h> | 40 | #include <linux/jhash.h> |
| 41 | #include <linux/audit.h> | ||
| 41 | #include <net/ip.h> | 42 | #include <net/ip.h> |
| 42 | #include <net/icmp.h> | 43 | #include <net/icmp.h> |
| 43 | #include <net/tcp.h> | 44 | #include <net/tcp.h> |
| @@ -449,6 +450,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) | |||
| 449 | /** | 450 | /** |
| 450 | * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine | 451 | * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine |
| 451 | * @doi_def: the DOI structure | 452 | * @doi_def: the DOI structure |
| 453 | * @audit_info: NetLabel audit information | ||
| 452 | * | 454 | * |
| 453 | * Description: | 455 | * Description: |
| 454 | * The caller defines a new DOI for use by the CIPSO engine and calls this | 456 | * The caller defines a new DOI for use by the CIPSO engine and calls this |
| @@ -458,50 +460,78 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) | |||
| 458 | * zero on success and non-zero on failure. | 460 | * zero on success and non-zero on failure. |
| 459 | * | 461 | * |
| 460 | */ | 462 | */ |
| 461 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | 463 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, |
| 464 | struct netlbl_audit *audit_info) | ||
| 462 | { | 465 | { |
| 466 | int ret_val = -EINVAL; | ||
| 463 | u32 iter; | 467 | u32 iter; |
| 468 | u32 doi; | ||
| 469 | u32 doi_type; | ||
| 470 | struct audit_buffer *audit_buf; | ||
| 471 | |||
| 472 | doi = doi_def->doi; | ||
| 473 | doi_type = doi_def->type; | ||
| 464 | 474 | ||
| 465 | if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) | 475 | if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) |
| 466 | return -EINVAL; | 476 | goto doi_add_return; |
| 467 | for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { | 477 | for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { |
| 468 | switch (doi_def->tags[iter]) { | 478 | switch (doi_def->tags[iter]) { |
| 469 | case CIPSO_V4_TAG_RBITMAP: | 479 | case CIPSO_V4_TAG_RBITMAP: |
| 470 | break; | 480 | break; |
| 471 | case CIPSO_V4_TAG_RANGE: | 481 | case CIPSO_V4_TAG_RANGE: |
| 472 | if (doi_def->type != CIPSO_V4_MAP_PASS) | ||
| 473 | return -EINVAL; | ||
| 474 | break; | ||
| 475 | case CIPSO_V4_TAG_INVALID: | ||
| 476 | if (iter == 0) | ||
| 477 | return -EINVAL; | ||
| 478 | break; | ||
| 479 | case CIPSO_V4_TAG_ENUM: | 482 | case CIPSO_V4_TAG_ENUM: |
| 480 | if (doi_def->type != CIPSO_V4_MAP_PASS) | 483 | if (doi_def->type != CIPSO_V4_MAP_PASS) |
| 481 | return -EINVAL; | 484 | goto doi_add_return; |
| 482 | break; | 485 | break; |
| 483 | case CIPSO_V4_TAG_LOCAL: | 486 | case CIPSO_V4_TAG_LOCAL: |
| 484 | if (doi_def->type != CIPSO_V4_MAP_LOCAL) | 487 | if (doi_def->type != CIPSO_V4_MAP_LOCAL) |
| 485 | return -EINVAL; | 488 | goto doi_add_return; |
| 489 | break; | ||
| 490 | case CIPSO_V4_TAG_INVALID: | ||
| 491 | if (iter == 0) | ||
| 492 | goto doi_add_return; | ||
| 486 | break; | 493 | break; |
| 487 | default: | 494 | default: |
| 488 | return -EINVAL; | 495 | goto doi_add_return; |
| 489 | } | 496 | } |
| 490 | } | 497 | } |
| 491 | 498 | ||
| 492 | atomic_set(&doi_def->refcount, 1); | 499 | atomic_set(&doi_def->refcount, 1); |
| 493 | 500 | ||
| 494 | spin_lock(&cipso_v4_doi_list_lock); | 501 | spin_lock(&cipso_v4_doi_list_lock); |
| 495 | if (cipso_v4_doi_search(doi_def->doi) != NULL) | 502 | if (cipso_v4_doi_search(doi_def->doi) != NULL) { |
| 496 | goto doi_add_failure; | 503 | spin_unlock(&cipso_v4_doi_list_lock); |
| 504 | ret_val = -EEXIST; | ||
| 505 | goto doi_add_return; | ||
| 506 | } | ||
| 497 | list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list); | 507 | list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list); |
| 498 | spin_unlock(&cipso_v4_doi_list_lock); | 508 | spin_unlock(&cipso_v4_doi_list_lock); |
| 509 | ret_val = 0; | ||
| 499 | 510 | ||
| 500 | return 0; | 511 | doi_add_return: |
| 512 | audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info); | ||
| 513 | if (audit_buf != NULL) { | ||
| 514 | const char *type_str; | ||
| 515 | switch (doi_type) { | ||
| 516 | case CIPSO_V4_MAP_TRANS: | ||
| 517 | type_str = "trans"; | ||
| 518 | break; | ||
| 519 | case CIPSO_V4_MAP_PASS: | ||
| 520 | type_str = "pass"; | ||
| 521 | break; | ||
| 522 | case CIPSO_V4_MAP_LOCAL: | ||
| 523 | type_str = "local"; | ||
| 524 | break; | ||
| 525 | default: | ||
| 526 | type_str = "(unknown)"; | ||
| 527 | } | ||
| 528 | audit_log_format(audit_buf, | ||
| 529 | " cipso_doi=%u cipso_type=%s res=%u", | ||
| 530 | doi, type_str, ret_val == 0 ? 1 : 0); | ||
| 531 | audit_log_end(audit_buf); | ||
| 532 | } | ||
| 501 | 533 | ||
| 502 | doi_add_failure: | 534 | return ret_val; |
| 503 | spin_unlock(&cipso_v4_doi_list_lock); | ||
| 504 | return -EEXIST; | ||
| 505 | } | 535 | } |
| 506 | 536 | ||
| 507 | /** | 537 | /** |
| @@ -559,25 +589,39 @@ static void cipso_v4_doi_free_rcu(struct rcu_head *entry) | |||
| 559 | */ | 589 | */ |
| 560 | int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) | 590 | int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) |
| 561 | { | 591 | { |
| 592 | int ret_val; | ||
| 562 | struct cipso_v4_doi *doi_def; | 593 | struct cipso_v4_doi *doi_def; |
| 594 | struct audit_buffer *audit_buf; | ||
| 563 | 595 | ||
| 564 | spin_lock(&cipso_v4_doi_list_lock); | 596 | spin_lock(&cipso_v4_doi_list_lock); |
| 565 | doi_def = cipso_v4_doi_search(doi); | 597 | doi_def = cipso_v4_doi_search(doi); |
| 566 | if (doi_def == NULL) { | 598 | if (doi_def == NULL) { |
| 567 | spin_unlock(&cipso_v4_doi_list_lock); | 599 | spin_unlock(&cipso_v4_doi_list_lock); |
| 568 | return -ENOENT; | 600 | ret_val = -ENOENT; |
| 601 | goto doi_remove_return; | ||
| 569 | } | 602 | } |
| 570 | if (!atomic_dec_and_test(&doi_def->refcount)) { | 603 | if (!atomic_dec_and_test(&doi_def->refcount)) { |
| 571 | spin_unlock(&cipso_v4_doi_list_lock); | 604 | spin_unlock(&cipso_v4_doi_list_lock); |
| 572 | return -EBUSY; | 605 | ret_val = -EBUSY; |
| 606 | goto doi_remove_return; | ||
| 573 | } | 607 | } |
| 574 | list_del_rcu(&doi_def->list); | 608 | list_del_rcu(&doi_def->list); |
| 575 | spin_unlock(&cipso_v4_doi_list_lock); | 609 | spin_unlock(&cipso_v4_doi_list_lock); |
| 576 | 610 | ||
| 577 | cipso_v4_cache_invalidate(); | 611 | cipso_v4_cache_invalidate(); |
| 578 | call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); | 612 | call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); |
| 613 | ret_val = 0; | ||
| 614 | |||
| 615 | doi_remove_return: | ||
| 616 | audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info); | ||
| 617 | if (audit_buf != NULL) { | ||
| 618 | audit_log_format(audit_buf, | ||
| 619 | " cipso_doi=%u res=%u", | ||
| 620 | doi, ret_val == 0 ? 1 : 0); | ||
| 621 | audit_log_end(audit_buf); | ||
| 622 | } | ||
| 579 | 623 | ||
| 580 | return 0; | 624 | return ret_val; |
| 581 | } | 625 | } |
| 582 | 626 | ||
| 583 | /** | 627 | /** |
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index fff32b70efa9..bf1ab1a6790d 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c | |||
| @@ -130,6 +130,7 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, | |||
| 130 | /** | 130 | /** |
| 131 | * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition | 131 | * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition |
| 132 | * @info: the Generic NETLINK info block | 132 | * @info: the Generic NETLINK info block |
| 133 | * @audit_info: NetLabel audit information | ||
| 133 | * | 134 | * |
| 134 | * Description: | 135 | * Description: |
| 135 | * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD | 136 | * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD |
| @@ -137,7 +138,8 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, | |||
| 137 | * non-zero on error. | 138 | * non-zero on error. |
| 138 | * | 139 | * |
| 139 | */ | 140 | */ |
| 140 | static int netlbl_cipsov4_add_std(struct genl_info *info) | 141 | static int netlbl_cipsov4_add_std(struct genl_info *info, |
| 142 | struct netlbl_audit *audit_info) | ||
| 141 | { | 143 | { |
| 142 | int ret_val = -EINVAL; | 144 | int ret_val = -EINVAL; |
| 143 | struct cipso_v4_doi *doi_def = NULL; | 145 | struct cipso_v4_doi *doi_def = NULL; |
| @@ -316,7 +318,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) | |||
| 316 | } | 318 | } |
| 317 | } | 319 | } |
| 318 | 320 | ||
| 319 | ret_val = cipso_v4_doi_add(doi_def); | 321 | ret_val = cipso_v4_doi_add(doi_def, audit_info); |
| 320 | if (ret_val != 0) | 322 | if (ret_val != 0) |
| 321 | goto add_std_failure; | 323 | goto add_std_failure; |
| 322 | return 0; | 324 | return 0; |
| @@ -330,6 +332,7 @@ add_std_failure: | |||
| 330 | /** | 332 | /** |
| 331 | * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition | 333 | * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition |
| 332 | * @info: the Generic NETLINK info block | 334 | * @info: the Generic NETLINK info block |
| 335 | * @audit_info: NetLabel audit information | ||
| 333 | * | 336 | * |
| 334 | * Description: | 337 | * Description: |
| 335 | * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message | 338 | * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message |
| @@ -337,7 +340,8 @@ add_std_failure: | |||
| 337 | * error. | 340 | * error. |
| 338 | * | 341 | * |
| 339 | */ | 342 | */ |
| 340 | static int netlbl_cipsov4_add_pass(struct genl_info *info) | 343 | static int netlbl_cipsov4_add_pass(struct genl_info *info, |
| 344 | struct netlbl_audit *audit_info) | ||
| 341 | { | 345 | { |
| 342 | int ret_val; | 346 | int ret_val; |
| 343 | struct cipso_v4_doi *doi_def = NULL; | 347 | struct cipso_v4_doi *doi_def = NULL; |
| @@ -354,7 +358,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info) | |||
| 354 | if (ret_val != 0) | 358 | if (ret_val != 0) |
| 355 | goto add_pass_failure; | 359 | goto add_pass_failure; |
| 356 | 360 | ||
| 357 | ret_val = cipso_v4_doi_add(doi_def); | 361 | ret_val = cipso_v4_doi_add(doi_def, audit_info); |
| 358 | if (ret_val != 0) | 362 | if (ret_val != 0) |
| 359 | goto add_pass_failure; | 363 | goto add_pass_failure; |
| 360 | return 0; | 364 | return 0; |
| @@ -367,6 +371,7 @@ add_pass_failure: | |||
| 367 | /** | 371 | /** |
| 368 | * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition | 372 | * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition |
| 369 | * @info: the Generic NETLINK info block | 373 | * @info: the Generic NETLINK info block |
| 374 | * @audit_info: NetLabel audit information | ||
| 370 | * | 375 | * |
| 371 | * Description: | 376 | * Description: |
| 372 | * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD | 377 | * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD |
| @@ -374,7 +379,8 @@ add_pass_failure: | |||
| 374 | * non-zero on error. | 379 | * non-zero on error. |
| 375 | * | 380 | * |
| 376 | */ | 381 | */ |
| 377 | static int netlbl_cipsov4_add_local(struct genl_info *info) | 382 | static int netlbl_cipsov4_add_local(struct genl_info *info, |
| 383 | struct netlbl_audit *audit_info) | ||
| 378 | { | 384 | { |
| 379 | int ret_val; | 385 | int ret_val; |
| 380 | struct cipso_v4_doi *doi_def = NULL; | 386 | struct cipso_v4_doi *doi_def = NULL; |
| @@ -391,7 +397,7 @@ static int netlbl_cipsov4_add_local(struct genl_info *info) | |||
| 391 | if (ret_val != 0) | 397 | if (ret_val != 0) |
| 392 | goto add_local_failure; | 398 | goto add_local_failure; |
| 393 | 399 | ||
| 394 | ret_val = cipso_v4_doi_add(doi_def); | 400 | ret_val = cipso_v4_doi_add(doi_def, audit_info); |
| 395 | if (ret_val != 0) | 401 | if (ret_val != 0) |
| 396 | goto add_local_failure; | 402 | goto add_local_failure; |
| 397 | return 0; | 403 | return 0; |
| @@ -415,48 +421,31 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) | |||
| 415 | 421 | ||
| 416 | { | 422 | { |
| 417 | int ret_val = -EINVAL; | 423 | int ret_val = -EINVAL; |
| 418 | u32 type; | ||
| 419 | u32 doi; | ||
| 420 | const char *type_str = "(unknown)"; | 424 | const char *type_str = "(unknown)"; |
| 421 | struct audit_buffer *audit_buf; | ||
| 422 | struct netlbl_audit audit_info; | 425 | struct netlbl_audit audit_info; |
| 423 | 426 | ||
| 424 | if (!info->attrs[NLBL_CIPSOV4_A_DOI] || | 427 | if (!info->attrs[NLBL_CIPSOV4_A_DOI] || |
| 425 | !info->attrs[NLBL_CIPSOV4_A_MTYPE]) | 428 | !info->attrs[NLBL_CIPSOV4_A_MTYPE]) |
| 426 | return -EINVAL; | 429 | return -EINVAL; |
| 427 | 430 | ||
| 428 | doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); | ||
| 429 | netlbl_netlink_auditinfo(skb, &audit_info); | 431 | netlbl_netlink_auditinfo(skb, &audit_info); |
| 430 | 432 | switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) { | |
| 431 | type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); | ||
| 432 | switch (type) { | ||
| 433 | case CIPSO_V4_MAP_TRANS: | 433 | case CIPSO_V4_MAP_TRANS: |
| 434 | type_str = "trans"; | 434 | type_str = "trans"; |
| 435 | ret_val = netlbl_cipsov4_add_std(info); | 435 | ret_val = netlbl_cipsov4_add_std(info, &audit_info); |
| 436 | break; | 436 | break; |
| 437 | case CIPSO_V4_MAP_PASS: | 437 | case CIPSO_V4_MAP_PASS: |
| 438 | type_str = "pass"; | 438 | type_str = "pass"; |
| 439 | ret_val = netlbl_cipsov4_add_pass(info); | 439 | ret_val = netlbl_cipsov4_add_pass(info, &audit_info); |
| 440 | break; | 440 | break; |
| 441 | case CIPSO_V4_MAP_LOCAL: | 441 | case CIPSO_V4_MAP_LOCAL: |
| 442 | type_str = "local"; | 442 | type_str = "local"; |
| 443 | ret_val = netlbl_cipsov4_add_local(info); | 443 | ret_val = netlbl_cipsov4_add_local(info, &audit_info); |
| 444 | break; | 444 | break; |
| 445 | } | 445 | } |
| 446 | if (ret_val == 0) | 446 | if (ret_val == 0) |
| 447 | atomic_inc(&netlabel_mgmt_protocount); | 447 | atomic_inc(&netlabel_mgmt_protocount); |
| 448 | 448 | ||
| 449 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, | ||
| 450 | &audit_info); | ||
| 451 | if (audit_buf != NULL) { | ||
| 452 | audit_log_format(audit_buf, | ||
| 453 | " cipso_doi=%u cipso_type=%s res=%u", | ||
| 454 | doi, | ||
| 455 | type_str, | ||
| 456 | ret_val == 0 ? 1 : 0); | ||
| 457 | audit_log_end(audit_buf); | ||
| 458 | } | ||
| 459 | |||
| 460 | return ret_val; | 449 | return ret_val; |
| 461 | } | 450 | } |
| 462 | 451 | ||
| @@ -725,9 +714,7 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg) | |||
| 725 | static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | 714 | static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) |
| 726 | { | 715 | { |
| 727 | int ret_val = -EINVAL; | 716 | int ret_val = -EINVAL; |
| 728 | u32 doi = 0; | ||
| 729 | struct netlbl_domhsh_walk_arg cb_arg; | 717 | struct netlbl_domhsh_walk_arg cb_arg; |
| 730 | struct audit_buffer *audit_buf; | ||
| 731 | struct netlbl_audit audit_info; | 718 | struct netlbl_audit audit_info; |
| 732 | u32 skip_bkt = 0; | 719 | u32 skip_bkt = 0; |
| 733 | u32 skip_chain = 0; | 720 | u32 skip_chain = 0; |
| @@ -735,29 +722,17 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | |||
| 735 | if (!info->attrs[NLBL_CIPSOV4_A_DOI]) | 722 | if (!info->attrs[NLBL_CIPSOV4_A_DOI]) |
| 736 | return -EINVAL; | 723 | return -EINVAL; |
| 737 | 724 | ||
| 738 | doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); | ||
| 739 | netlbl_netlink_auditinfo(skb, &audit_info); | 725 | netlbl_netlink_auditinfo(skb, &audit_info); |
| 740 | 726 | cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); | |
| 741 | cb_arg.doi = doi; | ||
| 742 | cb_arg.audit_info = &audit_info; | 727 | cb_arg.audit_info = &audit_info; |
| 743 | ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, | 728 | ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, |
| 744 | netlbl_cipsov4_remove_cb, &cb_arg); | 729 | netlbl_cipsov4_remove_cb, &cb_arg); |
| 745 | if (ret_val == 0 || ret_val == -ENOENT) { | 730 | if (ret_val == 0 || ret_val == -ENOENT) { |
| 746 | ret_val = cipso_v4_doi_remove(doi, &audit_info); | 731 | ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info); |
| 747 | if (ret_val == 0) | 732 | if (ret_val == 0) |
| 748 | atomic_dec(&netlabel_mgmt_protocount); | 733 | atomic_dec(&netlabel_mgmt_protocount); |
| 749 | } | 734 | } |
| 750 | 735 | ||
| 751 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, | ||
| 752 | &audit_info); | ||
| 753 | if (audit_buf != NULL) { | ||
| 754 | audit_log_format(audit_buf, | ||
| 755 | " cipso_doi=%u res=%u", | ||
| 756 | doi, | ||
| 757 | ret_val == 0 ? 1 : 0); | ||
| 758 | audit_log_end(audit_buf); | ||
| 759 | } | ||
| 760 | |||
| 761 | return ret_val; | 736 | return ret_val; |
| 762 | } | 737 | } |
| 763 | 738 | ||
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 5fadf10e5ddf..7a10bbe02c13 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
| @@ -483,6 +483,73 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, | |||
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | /** | 485 | /** |
| 486 | * netlbl_domhsh_remove_af4 - Removes an address selector entry | ||
| 487 | * @domain: the domain | ||
| 488 | * @addr: IPv4 address | ||
| 489 | * @mask: IPv4 address mask | ||
| 490 | * @audit_info: NetLabel audit information | ||
| 491 | * | ||
| 492 | * Description: | ||
| 493 | * Removes an individual address selector from a domain mapping and potentially | ||
| 494 | * the entire mapping if it is empty. Returns zero on success, negative values | ||
| 495 | * on failure. | ||
| 496 | * | ||
| 497 | */ | ||
| 498 | int netlbl_domhsh_remove_af4(const char *domain, | ||
| 499 | const struct in_addr *addr, | ||
| 500 | const struct in_addr *mask, | ||
| 501 | struct netlbl_audit *audit_info) | ||
| 502 | { | ||
| 503 | struct netlbl_dom_map *entry_map; | ||
| 504 | struct netlbl_af4list *entry_addr; | ||
| 505 | struct netlbl_af4list *iter4; | ||
| 506 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 507 | struct netlbl_af6list *iter6; | ||
| 508 | #endif /* IPv6 */ | ||
| 509 | struct netlbl_domaddr4_map *entry; | ||
| 510 | |||
| 511 | rcu_read_lock(); | ||
| 512 | |||
| 513 | if (domain) | ||
| 514 | entry_map = netlbl_domhsh_search(domain); | ||
| 515 | else | ||
| 516 | entry_map = netlbl_domhsh_search_def(domain); | ||
| 517 | if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT) | ||
| 518 | goto remove_af4_failure; | ||
| 519 | |||
| 520 | spin_lock(&netlbl_domhsh_lock); | ||
| 521 | entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr, | ||
| 522 | &entry_map->type_def.addrsel->list4); | ||
| 523 | spin_unlock(&netlbl_domhsh_lock); | ||
| 524 | |||
| 525 | if (entry_addr == NULL) | ||
| 526 | goto remove_af4_failure; | ||
| 527 | netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4) | ||
| 528 | goto remove_af4_single_addr; | ||
| 529 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 530 | netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6) | ||
| 531 | goto remove_af4_single_addr; | ||
| 532 | #endif /* IPv6 */ | ||
| 533 | /* the domain mapping is empty so remove it from the mapping table */ | ||
| 534 | netlbl_domhsh_remove_entry(entry_map, audit_info); | ||
| 535 | |||
| 536 | remove_af4_single_addr: | ||
| 537 | rcu_read_unlock(); | ||
| 538 | /* yick, we can't use call_rcu here because we don't have a rcu head | ||
| 539 | * pointer but hopefully this should be a rare case so the pause | ||
| 540 | * shouldn't be a problem */ | ||
| 541 | synchronize_rcu(); | ||
| 542 | entry = netlbl_domhsh_addr4_entry(entry_addr); | ||
| 543 | cipso_v4_doi_putdef(entry->type_def.cipsov4); | ||
| 544 | kfree(entry); | ||
| 545 | return 0; | ||
| 546 | |||
| 547 | remove_af4_failure: | ||
| 548 | rcu_read_unlock(); | ||
| 549 | return -ENOENT; | ||
| 550 | } | ||
| 551 | |||
| 552 | /** | ||
| 486 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | 553 | * netlbl_domhsh_remove - Removes an entry from the domain hash table |
| 487 | * @domain: the domain to remove | 554 | * @domain: the domain to remove |
| 488 | * @audit_info: NetLabel audit information | 555 | * @audit_info: NetLabel audit information |
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index bfcb6763a1a1..0261dda3f2d2 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h | |||
| @@ -90,6 +90,10 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, | |||
| 90 | struct netlbl_audit *audit_info); | 90 | struct netlbl_audit *audit_info); |
| 91 | int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, | 91 | int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, |
| 92 | struct netlbl_audit *audit_info); | 92 | struct netlbl_audit *audit_info); |
| 93 | int netlbl_domhsh_remove_af4(const char *domain, | ||
| 94 | const struct in_addr *addr, | ||
| 95 | const struct in_addr *mask, | ||
| 96 | struct netlbl_audit *audit_info); | ||
| 93 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); | 97 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); |
| 94 | int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); | 98 | int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); |
| 95 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); | 99 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); |
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index b32eceb3ab0d..fd9229db075c 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
| @@ -31,7 +31,10 @@ | |||
| 31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 33 | #include <linux/audit.h> | 33 | #include <linux/audit.h> |
| 34 | #include <linux/in.h> | ||
| 35 | #include <linux/in6.h> | ||
| 34 | #include <net/ip.h> | 36 | #include <net/ip.h> |
| 37 | #include <net/ipv6.h> | ||
| 35 | #include <net/netlabel.h> | 38 | #include <net/netlabel.h> |
| 36 | #include <net/cipso_ipv4.h> | 39 | #include <net/cipso_ipv4.h> |
| 37 | #include <asm/bug.h> | 40 | #include <asm/bug.h> |
| @@ -42,6 +45,7 @@ | |||
| 42 | #include "netlabel_cipso_v4.h" | 45 | #include "netlabel_cipso_v4.h" |
| 43 | #include "netlabel_user.h" | 46 | #include "netlabel_user.h" |
| 44 | #include "netlabel_mgmt.h" | 47 | #include "netlabel_mgmt.h" |
| 48 | #include "netlabel_addrlist.h" | ||
| 45 | 49 | ||
| 46 | /* | 50 | /* |
| 47 | * Configuration Functions | 51 | * Configuration Functions |
| @@ -50,6 +54,9 @@ | |||
| 50 | /** | 54 | /** |
| 51 | * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping | 55 | * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping |
| 52 | * @domain: the domain mapping to remove | 56 | * @domain: the domain mapping to remove |
| 57 | * @family: address family | ||
| 58 | * @addr: IP address | ||
| 59 | * @mask: IP address mask | ||
| 53 | * @audit_info: NetLabel audit information | 60 | * @audit_info: NetLabel audit information |
| 54 | * | 61 | * |
| 55 | * Description: | 62 | * Description: |
| @@ -58,14 +65,32 @@ | |||
| 58 | * values on failure. | 65 | * values on failure. |
| 59 | * | 66 | * |
| 60 | */ | 67 | */ |
| 61 | int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info) | 68 | int netlbl_cfg_map_del(const char *domain, |
| 69 | u16 family, | ||
| 70 | const void *addr, | ||
| 71 | const void *mask, | ||
| 72 | struct netlbl_audit *audit_info) | ||
| 62 | { | 73 | { |
| 63 | return netlbl_domhsh_remove(domain, audit_info); | 74 | if (addr == NULL && mask == NULL) { |
| 75 | return netlbl_domhsh_remove(domain, audit_info); | ||
| 76 | } else if (addr != NULL && mask != NULL) { | ||
| 77 | switch (family) { | ||
| 78 | case AF_INET: | ||
| 79 | return netlbl_domhsh_remove_af4(domain, addr, mask, | ||
| 80 | audit_info); | ||
| 81 | default: | ||
| 82 | return -EPFNOSUPPORT; | ||
| 83 | } | ||
| 84 | } else | ||
| 85 | return -EINVAL; | ||
| 64 | } | 86 | } |
| 65 | 87 | ||
| 66 | /** | 88 | /** |
| 67 | * netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping | 89 | * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping |
| 68 | * @domain: the domain mapping to add | 90 | * @domain: the domain mapping to add |
| 91 | * @family: address family | ||
| 92 | * @addr: IP address | ||
| 93 | * @mask: IP address mask | ||
| 69 | * @audit_info: NetLabel audit information | 94 | * @audit_info: NetLabel audit information |
| 70 | * | 95 | * |
| 71 | * Description: | 96 | * Description: |
| @@ -74,11 +99,19 @@ int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info) | |||
| 74 | * negative values on failure. | 99 | * negative values on failure. |
| 75 | * | 100 | * |
| 76 | */ | 101 | */ |
| 77 | int netlbl_cfg_unlbl_add_map(const char *domain, | 102 | int netlbl_cfg_unlbl_map_add(const char *domain, |
| 103 | u16 family, | ||
| 104 | const void *addr, | ||
| 105 | const void *mask, | ||
| 78 | struct netlbl_audit *audit_info) | 106 | struct netlbl_audit *audit_info) |
| 79 | { | 107 | { |
| 80 | int ret_val = -ENOMEM; | 108 | int ret_val = -ENOMEM; |
| 81 | struct netlbl_dom_map *entry; | 109 | struct netlbl_dom_map *entry; |
| 110 | struct netlbl_domaddr_map *addrmap = NULL; | ||
| 111 | struct netlbl_domaddr4_map *map4 = NULL; | ||
| 112 | struct netlbl_domaddr6_map *map6 = NULL; | ||
| 113 | const struct in_addr *addr4, *mask4; | ||
| 114 | const struct in6_addr *addr6, *mask6; | ||
| 82 | 115 | ||
| 83 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 116 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
| 84 | if (entry == NULL) | 117 | if (entry == NULL) |
| @@ -86,49 +119,225 @@ int netlbl_cfg_unlbl_add_map(const char *domain, | |||
| 86 | if (domain != NULL) { | 119 | if (domain != NULL) { |
| 87 | entry->domain = kstrdup(domain, GFP_ATOMIC); | 120 | entry->domain = kstrdup(domain, GFP_ATOMIC); |
| 88 | if (entry->domain == NULL) | 121 | if (entry->domain == NULL) |
| 89 | goto cfg_unlbl_add_map_failure; | 122 | goto cfg_unlbl_map_add_failure; |
| 123 | } | ||
| 124 | |||
| 125 | if (addr == NULL && mask == NULL) | ||
| 126 | entry->type = NETLBL_NLTYPE_UNLABELED; | ||
| 127 | else if (addr != NULL && mask != NULL) { | ||
| 128 | addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); | ||
| 129 | if (addrmap == NULL) | ||
| 130 | goto cfg_unlbl_map_add_failure; | ||
| 131 | INIT_LIST_HEAD(&addrmap->list4); | ||
| 132 | INIT_LIST_HEAD(&addrmap->list6); | ||
| 133 | |||
| 134 | switch (family) { | ||
| 135 | case AF_INET: | ||
| 136 | addr4 = addr; | ||
| 137 | mask4 = mask; | ||
| 138 | map4 = kzalloc(sizeof(*map4), GFP_ATOMIC); | ||
| 139 | if (map4 == NULL) | ||
| 140 | goto cfg_unlbl_map_add_failure; | ||
| 141 | map4->type = NETLBL_NLTYPE_UNLABELED; | ||
| 142 | map4->list.addr = addr4->s_addr & mask4->s_addr; | ||
| 143 | map4->list.mask = mask4->s_addr; | ||
| 144 | map4->list.valid = 1; | ||
| 145 | ret_val = netlbl_af4list_add(&map4->list, | ||
| 146 | &addrmap->list4); | ||
| 147 | if (ret_val != 0) | ||
| 148 | goto cfg_unlbl_map_add_failure; | ||
| 149 | break; | ||
| 150 | case AF_INET6: | ||
| 151 | addr6 = addr; | ||
| 152 | mask6 = mask; | ||
| 153 | map6 = kzalloc(sizeof(*map6), GFP_ATOMIC); | ||
| 154 | if (map4 == NULL) | ||
| 155 | goto cfg_unlbl_map_add_failure; | ||
| 156 | map6->type = NETLBL_NLTYPE_UNLABELED; | ||
| 157 | ipv6_addr_copy(&map6->list.addr, addr6); | ||
| 158 | map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0]; | ||
| 159 | map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1]; | ||
| 160 | map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2]; | ||
| 161 | map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3]; | ||
| 162 | ipv6_addr_copy(&map6->list.mask, mask6); | ||
| 163 | map6->list.valid = 1; | ||
| 164 | ret_val = netlbl_af4list_add(&map4->list, | ||
| 165 | &addrmap->list4); | ||
| 166 | if (ret_val != 0) | ||
| 167 | goto cfg_unlbl_map_add_failure; | ||
| 168 | break; | ||
| 169 | default: | ||
| 170 | goto cfg_unlbl_map_add_failure; | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | |||
| 174 | entry->type_def.addrsel = addrmap; | ||
| 175 | entry->type = NETLBL_NLTYPE_ADDRSELECT; | ||
| 176 | } else { | ||
| 177 | ret_val = -EINVAL; | ||
| 178 | goto cfg_unlbl_map_add_failure; | ||
| 90 | } | 179 | } |
| 91 | entry->type = NETLBL_NLTYPE_UNLABELED; | ||
| 92 | 180 | ||
| 93 | ret_val = netlbl_domhsh_add(entry, audit_info); | 181 | ret_val = netlbl_domhsh_add(entry, audit_info); |
| 94 | if (ret_val != 0) | 182 | if (ret_val != 0) |
| 95 | goto cfg_unlbl_add_map_failure; | 183 | goto cfg_unlbl_map_add_failure; |
| 96 | 184 | ||
| 97 | return 0; | 185 | return 0; |
| 98 | 186 | ||
| 99 | cfg_unlbl_add_map_failure: | 187 | cfg_unlbl_map_add_failure: |
| 100 | if (entry != NULL) | 188 | if (entry != NULL) |
| 101 | kfree(entry->domain); | 189 | kfree(entry->domain); |
| 102 | kfree(entry); | 190 | kfree(entry); |
| 191 | kfree(addrmap); | ||
| 192 | kfree(map4); | ||
| 193 | kfree(map6); | ||
| 103 | return ret_val; | 194 | return ret_val; |
| 104 | } | 195 | } |
| 105 | 196 | ||
| 197 | |||
| 198 | /** | ||
| 199 | * netlbl_cfg_unlbl_static_add - Adds a new static label | ||
| 200 | * @net: network namespace | ||
| 201 | * @dev_name: interface name | ||
| 202 | * @addr: IP address in network byte order (struct in[6]_addr) | ||
| 203 | * @mask: address mask in network byte order (struct in[6]_addr) | ||
| 204 | * @family: address family | ||
| 205 | * @secid: LSM secid value for the entry | ||
| 206 | * @audit_info: NetLabel audit information | ||
| 207 | * | ||
| 208 | * Description: | ||
| 209 | * Adds a new NetLabel static label to be used when protocol provided labels | ||
| 210 | * are not present on incoming traffic. If @dev_name is NULL then the default | ||
| 211 | * interface will be used. Returns zero on success, negative values on failure. | ||
| 212 | * | ||
| 213 | */ | ||
| 214 | int netlbl_cfg_unlbl_static_add(struct net *net, | ||
| 215 | const char *dev_name, | ||
| 216 | const void *addr, | ||
| 217 | const void *mask, | ||
| 218 | u16 family, | ||
| 219 | u32 secid, | ||
| 220 | struct netlbl_audit *audit_info) | ||
| 221 | { | ||
| 222 | u32 addr_len; | ||
| 223 | |||
| 224 | switch (family) { | ||
| 225 | case AF_INET: | ||
| 226 | addr_len = sizeof(struct in_addr); | ||
| 227 | break; | ||
| 228 | case AF_INET6: | ||
| 229 | addr_len = sizeof(struct in6_addr); | ||
| 230 | break; | ||
| 231 | default: | ||
| 232 | return -EPFNOSUPPORT; | ||
| 233 | } | ||
| 234 | |||
| 235 | return netlbl_unlhsh_add(net, | ||
| 236 | dev_name, addr, mask, addr_len, | ||
| 237 | secid, audit_info); | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * netlbl_cfg_unlbl_static_del - Removes an existing static label | ||
| 242 | * @net: network namespace | ||
| 243 | * @dev_name: interface name | ||
| 244 | * @addr: IP address in network byte order (struct in[6]_addr) | ||
| 245 | * @mask: address mask in network byte order (struct in[6]_addr) | ||
| 246 | * @family: address family | ||
| 247 | * @secid: LSM secid value for the entry | ||
| 248 | * @audit_info: NetLabel audit information | ||
| 249 | * | ||
| 250 | * Description: | ||
| 251 | * Removes an existing NetLabel static label used when protocol provided labels | ||
| 252 | * are not present on incoming traffic. If @dev_name is NULL then the default | ||
| 253 | * interface will be used. Returns zero on success, negative values on failure. | ||
| 254 | * | ||
| 255 | */ | ||
| 256 | int netlbl_cfg_unlbl_static_del(struct net *net, | ||
| 257 | const char *dev_name, | ||
| 258 | const void *addr, | ||
| 259 | const void *mask, | ||
| 260 | u16 family, | ||
| 261 | struct netlbl_audit *audit_info) | ||
| 262 | { | ||
| 263 | u32 addr_len; | ||
| 264 | |||
| 265 | switch (family) { | ||
| 266 | case AF_INET: | ||
| 267 | addr_len = sizeof(struct in_addr); | ||
| 268 | break; | ||
| 269 | case AF_INET6: | ||
| 270 | addr_len = sizeof(struct in6_addr); | ||
| 271 | break; | ||
| 272 | default: | ||
| 273 | return -EPFNOSUPPORT; | ||
| 274 | } | ||
| 275 | |||
| 276 | return netlbl_unlhsh_remove(net, | ||
| 277 | dev_name, addr, mask, addr_len, | ||
| 278 | audit_info); | ||
| 279 | } | ||
| 280 | |||
| 281 | /** | ||
| 282 | * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition | ||
| 283 | * @doi_def: CIPSO DOI definition | ||
| 284 | * @audit_info: NetLabel audit information | ||
| 285 | * | ||
| 286 | * Description: | ||
| 287 | * Add a new CIPSO DOI definition as defined by @doi_def. Returns zero on | ||
| 288 | * success and negative values on failure. | ||
| 289 | * | ||
| 290 | */ | ||
| 291 | int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, | ||
| 292 | struct netlbl_audit *audit_info) | ||
| 293 | { | ||
| 294 | return cipso_v4_doi_add(doi_def, audit_info); | ||
| 295 | } | ||
| 296 | |||
| 297 | /** | ||
| 298 | * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition | ||
| 299 | * @doi: CIPSO DOI | ||
| 300 | * @audit_info: NetLabel audit information | ||
| 301 | * | ||
| 302 | * Description: | ||
| 303 | * Remove an existing CIPSO DOI definition matching @doi. Returns zero on | ||
| 304 | * success and negative values on failure. | ||
| 305 | * | ||
| 306 | */ | ||
| 307 | void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info) | ||
| 308 | { | ||
| 309 | cipso_v4_doi_remove(doi, audit_info); | ||
| 310 | } | ||
| 311 | |||
| 106 | /** | 312 | /** |
| 107 | * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping | 313 | * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping |
| 108 | * @doi_def: the DOI definition | 314 | * @doi: the CIPSO DOI |
| 109 | * @domain: the domain mapping to add | 315 | * @domain: the domain mapping to add |
| 316 | * @addr: IP address | ||
| 317 | * @mask: IP address mask | ||
| 110 | * @audit_info: NetLabel audit information | 318 | * @audit_info: NetLabel audit information |
| 111 | * | 319 | * |
| 112 | * Description: | 320 | * Description: |
| 113 | * Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this | 321 | * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel |
| 114 | * new DOI definition to the NetLabel subsystem. A @domain value of NULL adds | 322 | * subsystem. A @domain value of NULL adds a new default domain mapping. |
| 115 | * a new default domain mapping. Returns zero on success, negative values on | 323 | * Returns zero on success, negative values on failure. |
| 116 | * failure. | ||
| 117 | * | 324 | * |
| 118 | */ | 325 | */ |
| 119 | int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | 326 | int netlbl_cfg_cipsov4_map_add(u32 doi, |
| 120 | const char *domain, | 327 | const char *domain, |
| 328 | const struct in_addr *addr, | ||
| 329 | const struct in_addr *mask, | ||
| 121 | struct netlbl_audit *audit_info) | 330 | struct netlbl_audit *audit_info) |
| 122 | { | 331 | { |
| 123 | int ret_val = -ENOMEM; | 332 | int ret_val = -ENOMEM; |
| 124 | u32 doi; | 333 | struct cipso_v4_doi *doi_def; |
| 125 | u32 doi_type; | ||
| 126 | struct netlbl_dom_map *entry; | 334 | struct netlbl_dom_map *entry; |
| 127 | const char *type_str; | 335 | struct netlbl_domaddr_map *addrmap = NULL; |
| 128 | struct audit_buffer *audit_buf; | 336 | struct netlbl_domaddr4_map *addrinfo = NULL; |
| 129 | 337 | ||
| 130 | doi = doi_def->doi; | 338 | doi_def = cipso_v4_doi_getdef(doi); |
| 131 | doi_type = doi_def->type; | 339 | if (doi_def == NULL) |
| 340 | return -ENOENT; | ||
| 132 | 341 | ||
| 133 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 342 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
| 134 | if (entry == NULL) | 343 | if (entry == NULL) |
| @@ -136,56 +345,52 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, | |||
| 136 | if (domain != NULL) { | 345 | if (domain != NULL) { |
| 137 | entry->domain = kstrdup(domain, GFP_ATOMIC); | 346 | entry->domain = kstrdup(domain, GFP_ATOMIC); |
| 138 | if (entry->domain == NULL) | 347 | if (entry->domain == NULL) |
| 139 | goto cfg_cipsov4_add_map_failure; | 348 | goto cfg_cipsov4_map_add_failure; |
| 140 | } | 349 | } |
| 141 | 350 | ||
| 142 | ret_val = cipso_v4_doi_add(doi_def); | 351 | if (addr == NULL && mask == NULL) { |
| 143 | if (ret_val != 0) | 352 | entry->type_def.cipsov4 = doi_def; |
| 144 | goto cfg_cipsov4_add_map_failure_remove_doi; | 353 | entry->type = NETLBL_NLTYPE_CIPSOV4; |
| 145 | entry->type = NETLBL_NLTYPE_CIPSOV4; | 354 | } else if (addr != NULL && mask != NULL) { |
| 146 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi); | 355 | addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); |
| 147 | if (entry->type_def.cipsov4 == NULL) { | 356 | if (addrmap == NULL) |
| 148 | ret_val = -ENOENT; | 357 | goto cfg_cipsov4_map_add_failure; |
| 149 | goto cfg_cipsov4_add_map_failure_remove_doi; | 358 | INIT_LIST_HEAD(&addrmap->list4); |
| 359 | INIT_LIST_HEAD(&addrmap->list6); | ||
| 360 | |||
| 361 | addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC); | ||
| 362 | if (addrinfo == NULL) | ||
| 363 | goto cfg_cipsov4_map_add_failure; | ||
| 364 | addrinfo->type_def.cipsov4 = doi_def; | ||
| 365 | addrinfo->type = NETLBL_NLTYPE_CIPSOV4; | ||
| 366 | addrinfo->list.addr = addr->s_addr & mask->s_addr; | ||
| 367 | addrinfo->list.mask = mask->s_addr; | ||
| 368 | addrinfo->list.valid = 1; | ||
| 369 | ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4); | ||
| 370 | if (ret_val != 0) | ||
| 371 | goto cfg_cipsov4_map_add_failure; | ||
| 372 | |||
| 373 | entry->type_def.addrsel = addrmap; | ||
| 374 | entry->type = NETLBL_NLTYPE_ADDRSELECT; | ||
| 375 | } else { | ||
| 376 | ret_val = -EINVAL; | ||
| 377 | goto cfg_cipsov4_map_add_failure; | ||
| 150 | } | 378 | } |
| 379 | |||
| 151 | ret_val = netlbl_domhsh_add(entry, audit_info); | 380 | ret_val = netlbl_domhsh_add(entry, audit_info); |
| 152 | if (ret_val != 0) | 381 | if (ret_val != 0) |
| 153 | goto cfg_cipsov4_add_map_failure_release_doi; | 382 | goto cfg_cipsov4_map_add_failure; |
| 154 | |||
| 155 | cfg_cipsov4_add_map_return: | ||
| 156 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, | ||
| 157 | audit_info); | ||
| 158 | if (audit_buf != NULL) { | ||
| 159 | switch (doi_type) { | ||
| 160 | case CIPSO_V4_MAP_TRANS: | ||
| 161 | type_str = "trans"; | ||
| 162 | break; | ||
| 163 | case CIPSO_V4_MAP_PASS: | ||
| 164 | type_str = "pass"; | ||
| 165 | break; | ||
| 166 | case CIPSO_V4_MAP_LOCAL: | ||
| 167 | type_str = "local"; | ||
| 168 | break; | ||
| 169 | default: | ||
| 170 | type_str = "(unknown)"; | ||
| 171 | } | ||
| 172 | audit_log_format(audit_buf, | ||
| 173 | " cipso_doi=%u cipso_type=%s res=%u", | ||
| 174 | doi, type_str, ret_val == 0 ? 1 : 0); | ||
| 175 | audit_log_end(audit_buf); | ||
| 176 | } | ||
| 177 | 383 | ||
| 178 | return ret_val; | 384 | return 0; |
| 179 | 385 | ||
| 180 | cfg_cipsov4_add_map_failure_release_doi: | 386 | cfg_cipsov4_map_add_failure: |
| 181 | cipso_v4_doi_putdef(doi_def); | 387 | cipso_v4_doi_putdef(doi_def); |
| 182 | cfg_cipsov4_add_map_failure_remove_doi: | ||
| 183 | cipso_v4_doi_remove(doi, audit_info); | ||
| 184 | cfg_cipsov4_add_map_failure: | ||
| 185 | if (entry != NULL) | 388 | if (entry != NULL) |
| 186 | kfree(entry->domain); | 389 | kfree(entry->domain); |
| 187 | kfree(entry); | 390 | kfree(entry); |
| 188 | goto cfg_cipsov4_add_map_return; | 391 | kfree(addrmap); |
| 392 | kfree(addrinfo); | ||
| 393 | return ret_val; | ||
| 189 | } | 394 | } |
| 190 | 395 | ||
| 191 | /* | 396 | /* |
| @@ -691,6 +896,28 @@ int netlbl_cache_add(const struct sk_buff *skb, | |||
| 691 | } | 896 | } |
| 692 | 897 | ||
| 693 | /* | 898 | /* |
| 899 | * Protocol Engine Functions | ||
| 900 | */ | ||
| 901 | |||
| 902 | /** | ||
| 903 | * netlbl_audit_start - Start an audit message | ||
| 904 | * @type: audit message type | ||
| 905 | * @audit_info: NetLabel audit information | ||
| 906 | * | ||
| 907 | * Description: | ||
| 908 | * Start an audit message using the type specified in @type and fill the audit | ||
| 909 | * message with some fields common to all NetLabel audit messages. This | ||
| 910 | * function should only be used by protocol engines, not LSMs. Returns a | ||
| 911 | * pointer to the audit buffer on success, NULL on failure. | ||
| 912 | * | ||
| 913 | */ | ||
| 914 | struct audit_buffer *netlbl_audit_start(int type, | ||
| 915 | struct netlbl_audit *audit_info) | ||
| 916 | { | ||
| 917 | return netlbl_audit_start_common(type, audit_info); | ||
| 918 | } | ||
| 919 | |||
| 920 | /* | ||
| 694 | * Setup Functions | 921 | * Setup Functions |
| 695 | */ | 922 | */ |
| 696 | 923 | ||
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 8c0308032178..f3c5c68c6848 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c | |||
| @@ -450,13 +450,13 @@ add_iface_failure: | |||
| 450 | * success, negative values on failure. | 450 | * success, negative values on failure. |
| 451 | * | 451 | * |
| 452 | */ | 452 | */ |
| 453 | static int netlbl_unlhsh_add(struct net *net, | 453 | int netlbl_unlhsh_add(struct net *net, |
| 454 | const char *dev_name, | 454 | const char *dev_name, |
| 455 | const void *addr, | 455 | const void *addr, |
| 456 | const void *mask, | 456 | const void *mask, |
| 457 | u32 addr_len, | 457 | u32 addr_len, |
| 458 | u32 secid, | 458 | u32 secid, |
| 459 | struct netlbl_audit *audit_info) | 459 | struct netlbl_audit *audit_info) |
| 460 | { | 460 | { |
| 461 | int ret_val; | 461 | int ret_val; |
| 462 | int ifindex; | 462 | int ifindex; |
| @@ -720,12 +720,12 @@ unlhsh_condremove_failure: | |||
| 720 | * Returns zero on success, negative values on failure. | 720 | * Returns zero on success, negative values on failure. |
| 721 | * | 721 | * |
| 722 | */ | 722 | */ |
| 723 | static int netlbl_unlhsh_remove(struct net *net, | 723 | int netlbl_unlhsh_remove(struct net *net, |
| 724 | const char *dev_name, | 724 | const char *dev_name, |
| 725 | const void *addr, | 725 | const void *addr, |
| 726 | const void *mask, | 726 | const void *mask, |
| 727 | u32 addr_len, | 727 | u32 addr_len, |
| 728 | struct netlbl_audit *audit_info) | 728 | struct netlbl_audit *audit_info) |
| 729 | { | 729 | { |
| 730 | int ret_val; | 730 | int ret_val; |
| 731 | struct net_device *dev; | 731 | struct net_device *dev; |
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h index 06b1301ac072..7aba63595137 100644 --- a/net/netlabel/netlabel_unlabeled.h +++ b/net/netlabel/netlabel_unlabeled.h | |||
| @@ -221,6 +221,21 @@ int netlbl_unlabel_genl_init(void); | |||
| 221 | /* General Unlabeled init function */ | 221 | /* General Unlabeled init function */ |
| 222 | int netlbl_unlabel_init(u32 size); | 222 | int netlbl_unlabel_init(u32 size); |
| 223 | 223 | ||
| 224 | /* Static/Fallback label management functions */ | ||
| 225 | int netlbl_unlhsh_add(struct net *net, | ||
| 226 | const char *dev_name, | ||
| 227 | const void *addr, | ||
| 228 | const void *mask, | ||
| 229 | u32 addr_len, | ||
| 230 | u32 secid, | ||
| 231 | struct netlbl_audit *audit_info); | ||
| 232 | int netlbl_unlhsh_remove(struct net *net, | ||
| 233 | const char *dev_name, | ||
| 234 | const void *addr, | ||
| 235 | const void *mask, | ||
| 236 | u32 addr_len, | ||
| 237 | struct netlbl_audit *audit_info); | ||
| 238 | |||
| 224 | /* Process Unlabeled incoming network packets */ | 239 | /* Process Unlabeled incoming network packets */ |
| 225 | int netlbl_unlabel_getattr(const struct sk_buff *skb, | 240 | int netlbl_unlabel_getattr(const struct sk_buff *skb, |
| 226 | u16 family, | 241 | u16 family, |
diff --git a/security/commoncap.c b/security/commoncap.c index 69fc9952650f..7cd61a5f5205 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -45,26 +45,22 @@ EXPORT_SYMBOL(cap_netlink_recv); | |||
| 45 | /** | 45 | /** |
| 46 | * cap_capable - Determine whether a task has a particular effective capability | 46 | * cap_capable - Determine whether a task has a particular effective capability |
| 47 | * @tsk: The task to query | 47 | * @tsk: The task to query |
| 48 | * @cred: The credentials to use | ||
| 48 | * @cap: The capability to check for | 49 | * @cap: The capability to check for |
| 49 | * @audit: Whether to write an audit message or not | 50 | * @audit: Whether to write an audit message or not |
| 50 | * | 51 | * |
| 51 | * Determine whether the nominated task has the specified capability amongst | 52 | * Determine whether the nominated task has the specified capability amongst |
| 52 | * its effective set, returning 0 if it does, -ve if it does not. | 53 | * its effective set, returning 0 if it does, -ve if it does not. |
| 53 | * | 54 | * |
| 54 | * NOTE WELL: cap_capable() cannot be used like the kernel's capable() | 55 | * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable() |
| 55 | * function. That is, it has the reverse semantics: cap_capable() returns 0 | 56 | * and has_capability() functions. That is, it has the reverse semantics: |
| 56 | * when a task has a capability, but the kernel's capable() returns 1 for this | 57 | * cap_has_capability() returns 0 when a task has a capability, but the |
| 57 | * case. | 58 | * kernel's capable() and has_capability() returns 1 for this case. |
| 58 | */ | 59 | */ |
| 59 | int cap_capable(struct task_struct *tsk, int cap, int audit) | 60 | int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap, |
| 61 | int audit) | ||
| 60 | { | 62 | { |
| 61 | __u32 cap_raised; | 63 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; |
| 62 | |||
| 63 | /* Derived from include/linux/sched.h:capable. */ | ||
| 64 | rcu_read_lock(); | ||
| 65 | cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap); | ||
| 66 | rcu_read_unlock(); | ||
| 67 | return cap_raised ? 0 : -EPERM; | ||
| 68 | } | 64 | } |
| 69 | 65 | ||
| 70 | /** | 66 | /** |
| @@ -160,7 +156,8 @@ static inline int cap_inh_is_capped(void) | |||
| 160 | /* they are so limited unless the current task has the CAP_SETPCAP | 156 | /* they are so limited unless the current task has the CAP_SETPCAP |
| 161 | * capability | 157 | * capability |
| 162 | */ | 158 | */ |
| 163 | if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) | 159 | if (cap_capable(current, current_cred(), CAP_SETPCAP, |
| 160 | SECURITY_CAP_AUDIT) == 0) | ||
| 164 | return 0; | 161 | return 0; |
| 165 | #endif | 162 | #endif |
| 166 | return 1; | 163 | return 1; |
| @@ -869,7 +866,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 869 | & (new->securebits ^ arg2)) /*[1]*/ | 866 | & (new->securebits ^ arg2)) /*[1]*/ |
| 870 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | 867 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
| 871 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 868 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
| 872 | || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ | 869 | || (cap_capable(current, current_cred(), CAP_SETPCAP, |
| 870 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ | ||
| 873 | /* | 871 | /* |
| 874 | * [1] no changing of bits that are locked | 872 | * [1] no changing of bits that are locked |
| 875 | * [2] no unlocking of locks | 873 | * [2] no unlocking of locks |
| @@ -950,7 +948,8 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 950 | { | 948 | { |
| 951 | int cap_sys_admin = 0; | 949 | int cap_sys_admin = 0; |
| 952 | 950 | ||
| 953 | if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) | 951 | if (cap_capable(current, current_cred(), CAP_SYS_ADMIN, |
| 952 | SECURITY_CAP_NOAUDIT) == 0) | ||
| 954 | cap_sys_admin = 1; | 953 | cap_sys_admin = 1; |
| 955 | return __vm_enough_memory(mm, pages, cap_sys_admin); | 954 | return __vm_enough_memory(mm, pages, cap_sys_admin); |
| 956 | } | 955 | } |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 6688765bd8b9..09796797d122 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -1294,7 +1294,7 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 1294 | 1294 | ||
| 1295 | case KEYCTL_GET_SECURITY: | 1295 | case KEYCTL_GET_SECURITY: |
| 1296 | return keyctl_get_security((key_serial_t) arg2, | 1296 | return keyctl_get_security((key_serial_t) arg2, |
| 1297 | (char *) arg3, | 1297 | (char __user *) arg3, |
| 1298 | (size_t) arg4); | 1298 | (size_t) arg4); |
| 1299 | 1299 | ||
| 1300 | default: | 1300 | default: |
diff --git a/security/security.c b/security/security.c index 678d4d07b852..c3586c0d97e2 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -154,14 +154,32 @@ int security_capset(struct cred *new, const struct cred *old, | |||
| 154 | effective, inheritable, permitted); | 154 | effective, inheritable, permitted); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | int security_capable(struct task_struct *tsk, int cap) | 157 | int security_capable(int cap) |
| 158 | { | 158 | { |
| 159 | return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT); | 159 | return security_ops->capable(current, current_cred(), cap, |
| 160 | SECURITY_CAP_AUDIT); | ||
| 160 | } | 161 | } |
| 161 | 162 | ||
| 162 | int security_capable_noaudit(struct task_struct *tsk, int cap) | 163 | int security_real_capable(struct task_struct *tsk, int cap) |
| 163 | { | 164 | { |
| 164 | return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT); | 165 | const struct cred *cred; |
| 166 | int ret; | ||
| 167 | |||
| 168 | cred = get_task_cred(tsk); | ||
| 169 | ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT); | ||
| 170 | put_cred(cred); | ||
| 171 | return ret; | ||
| 172 | } | ||
| 173 | |||
| 174 | int security_real_capable_noaudit(struct task_struct *tsk, int cap) | ||
| 175 | { | ||
| 176 | const struct cred *cred; | ||
| 177 | int ret; | ||
| 178 | |||
| 179 | cred = get_task_cred(tsk); | ||
| 180 | ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT); | ||
| 181 | put_cred(cred); | ||
| 182 | return ret; | ||
| 165 | } | 183 | } |
| 166 | 184 | ||
| 167 | int security_acct(struct file *file) | 185 | int security_acct(struct file *file) |
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 26301dd651d3..bca1b74a4a2f 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig | |||
| @@ -94,33 +94,6 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE | |||
| 94 | 94 | ||
| 95 | If you are unsure how to answer this question, answer 1. | 95 | If you are unsure how to answer this question, answer 1. |
| 96 | 96 | ||
| 97 | config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT | ||
| 98 | bool "NSA SELinux enable new secmark network controls by default" | ||
| 99 | depends on SECURITY_SELINUX | ||
| 100 | default n | ||
| 101 | help | ||
| 102 | This option determines whether the new secmark-based network | ||
| 103 | controls will be enabled by default. If not, the old internal | ||
| 104 | per-packet controls will be enabled by default, preserving | ||
| 105 | old behavior. | ||
| 106 | |||
| 107 | If you enable the new controls, you will need updated | ||
| 108 | SELinux userspace libraries, tools and policy. Typically, | ||
| 109 | your distribution will provide these and enable the new controls | ||
| 110 | in the kernel they also distribute. | ||
| 111 | |||
| 112 | Note that this option can be overridden at boot with the | ||
| 113 | selinux_compat_net parameter, and after boot via | ||
| 114 | /selinux/compat_net. See Documentation/kernel-parameters.txt | ||
| 115 | for details on this parameter. | ||
| 116 | |||
| 117 | If you enable the new network controls, you will likely | ||
| 118 | also require the SECMARK and CONNSECMARK targets, as | ||
| 119 | well as any conntrack helpers for protocols which you | ||
| 120 | wish to control. | ||
| 121 | |||
| 122 | If you are unsure what to do here, select N. | ||
| 123 | |||
| 124 | config SECURITY_SELINUX_POLICYDB_VERSION_MAX | 97 | config SECURITY_SELINUX_POLICYDB_VERSION_MAX |
| 125 | bool "NSA SELinux maximum supported policy format version" | 98 | bool "NSA SELinux maximum supported policy format version" |
| 126 | depends on SECURITY_SELINUX | 99 | depends on SECURITY_SELINUX |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index d43bd6baeeaa..eb41f43e2772 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -53,18 +53,20 @@ static const char *class_to_string[] = { | |||
| 53 | #undef S_ | 53 | #undef S_ |
| 54 | 54 | ||
| 55 | static const struct av_inherit av_inherit[] = { | 55 | static const struct av_inherit av_inherit[] = { |
| 56 | #define S_(c, i, b) { c, common_##i##_perm_to_string, b }, | 56 | #define S_(c, i, b) { .tclass = c,\ |
| 57 | .common_pts = common_##i##_perm_to_string,\ | ||
| 58 | .common_base = b }, | ||
| 57 | #include "av_inherit.h" | 59 | #include "av_inherit.h" |
| 58 | #undef S_ | 60 | #undef S_ |
| 59 | }; | 61 | }; |
| 60 | 62 | ||
| 61 | const struct selinux_class_perm selinux_class_perm = { | 63 | const struct selinux_class_perm selinux_class_perm = { |
| 62 | av_perm_to_string, | 64 | .av_perm_to_string = av_perm_to_string, |
| 63 | ARRAY_SIZE(av_perm_to_string), | 65 | .av_pts_len = ARRAY_SIZE(av_perm_to_string), |
| 64 | class_to_string, | 66 | .class_to_string = class_to_string, |
| 65 | ARRAY_SIZE(class_to_string), | 67 | .cts_len = ARRAY_SIZE(class_to_string), |
| 66 | av_inherit, | 68 | .av_inherit = av_inherit, |
| 67 | ARRAY_SIZE(av_inherit) | 69 | .av_inherit_len = ARRAY_SIZE(av_inherit) |
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 70 | #define AVC_CACHE_SLOTS 512 | 72 | #define AVC_CACHE_SLOTS 512 |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index dbeaa783b2a9..00815973d412 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -1433,12 +1433,13 @@ static int current_has_perm(const struct task_struct *tsk, | |||
| 1433 | 1433 | ||
| 1434 | /* Check whether a task is allowed to use a capability. */ | 1434 | /* Check whether a task is allowed to use a capability. */ |
| 1435 | static int task_has_capability(struct task_struct *tsk, | 1435 | static int task_has_capability(struct task_struct *tsk, |
| 1436 | const struct cred *cred, | ||
| 1436 | int cap, int audit) | 1437 | int cap, int audit) |
| 1437 | { | 1438 | { |
| 1438 | struct avc_audit_data ad; | 1439 | struct avc_audit_data ad; |
| 1439 | struct av_decision avd; | 1440 | struct av_decision avd; |
| 1440 | u16 sclass; | 1441 | u16 sclass; |
| 1441 | u32 sid = task_sid(tsk); | 1442 | u32 sid = cred_sid(cred); |
| 1442 | u32 av = CAP_TO_MASK(cap); | 1443 | u32 av = CAP_TO_MASK(cap); |
| 1443 | int rc; | 1444 | int rc; |
| 1444 | 1445 | ||
| @@ -1865,15 +1866,16 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
| 1865 | return cred_has_perm(old, new, PROCESS__SETCAP); | 1866 | return cred_has_perm(old, new, PROCESS__SETCAP); |
| 1866 | } | 1867 | } |
| 1867 | 1868 | ||
| 1868 | static int selinux_capable(struct task_struct *tsk, int cap, int audit) | 1869 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, |
| 1870 | int cap, int audit) | ||
| 1869 | { | 1871 | { |
| 1870 | int rc; | 1872 | int rc; |
| 1871 | 1873 | ||
| 1872 | rc = secondary_ops->capable(tsk, cap, audit); | 1874 | rc = secondary_ops->capable(tsk, cred, cap, audit); |
| 1873 | if (rc) | 1875 | if (rc) |
| 1874 | return rc; | 1876 | return rc; |
| 1875 | 1877 | ||
| 1876 | return task_has_capability(tsk, cap, audit); | 1878 | return task_has_capability(tsk, cred, cap, audit); |
| 1877 | } | 1879 | } |
| 1878 | 1880 | ||
| 1879 | static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) | 1881 | static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) |
| @@ -2037,7 +2039,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 2037 | { | 2039 | { |
| 2038 | int rc, cap_sys_admin = 0; | 2040 | int rc, cap_sys_admin = 0; |
| 2039 | 2041 | ||
| 2040 | rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); | 2042 | rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN, |
| 2043 | SECURITY_CAP_NOAUDIT); | ||
| 2041 | if (rc == 0) | 2044 | if (rc == 0) |
| 2042 | cap_sys_admin = 1; | 2045 | cap_sys_admin = 1; |
| 2043 | 2046 | ||
| @@ -2880,7 +2883,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name | |||
| 2880 | * and lack of permission just means that we fall back to the | 2883 | * and lack of permission just means that we fall back to the |
| 2881 | * in-core context value, not a denial. | 2884 | * in-core context value, not a denial. |
| 2882 | */ | 2885 | */ |
| 2883 | error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); | 2886 | error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN, |
| 2887 | SECURITY_CAP_NOAUDIT); | ||
| 2884 | if (!error) | 2888 | if (!error) |
| 2885 | error = security_sid_to_context_force(isec->sid, &context, | 2889 | error = security_sid_to_context_force(isec->sid, &context, |
| 2886 | &size); | 2890 | &size); |
| @@ -4185,7 +4189,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | |||
| 4185 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4189 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
| 4186 | u16 family) | 4190 | u16 family) |
| 4187 | { | 4191 | { |
| 4188 | int err; | 4192 | int err = 0; |
| 4189 | struct sk_security_struct *sksec = sk->sk_security; | 4193 | struct sk_security_struct *sksec = sk->sk_security; |
| 4190 | u32 peer_sid; | 4194 | u32 peer_sid; |
| 4191 | u32 sk_sid = sksec->sid; | 4195 | u32 sk_sid = sksec->sid; |
| @@ -4202,7 +4206,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
| 4202 | if (selinux_compat_net) | 4206 | if (selinux_compat_net) |
| 4203 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, | 4207 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, |
| 4204 | family, addrp); | 4208 | family, addrp); |
| 4205 | else | 4209 | else if (selinux_secmark_enabled()) |
| 4206 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4210 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
| 4207 | PACKET__RECV, &ad); | 4211 | PACKET__RECV, &ad); |
| 4208 | if (err) | 4212 | if (err) |
| @@ -4705,7 +4709,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
| 4705 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | 4709 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
| 4706 | &ad, family, addrp)) | 4710 | &ad, family, addrp)) |
| 4707 | return NF_DROP; | 4711 | return NF_DROP; |
| 4708 | } else { | 4712 | } else if (selinux_secmark_enabled()) { |
| 4709 | if (avc_has_perm(sksec->sid, skb->secmark, | 4713 | if (avc_has_perm(sksec->sid, skb->secmark, |
| 4710 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4714 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
| 4711 | return NF_DROP; | 4715 | return NF_DROP; |
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index c0d314d9f8e1..bb1ec801bdfe 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h | |||
| @@ -17,16 +17,16 @@ struct av_perm_to_string { | |||
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | struct av_inherit { | 19 | struct av_inherit { |
| 20 | u16 tclass; | ||
| 21 | const char **common_pts; | 20 | const char **common_pts; |
| 22 | u32 common_base; | 21 | u32 common_base; |
| 22 | u16 tclass; | ||
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | struct selinux_class_perm { | 25 | struct selinux_class_perm { |
| 26 | const struct av_perm_to_string *av_perm_to_string; | 26 | const struct av_perm_to_string *av_perm_to_string; |
| 27 | u32 av_pts_len; | 27 | u32 av_pts_len; |
| 28 | const char **class_to_string; | ||
| 29 | u32 cts_len; | 28 | u32 cts_len; |
| 29 | const char **class_to_string; | ||
| 30 | const struct av_inherit *av_inherit; | 30 | const struct av_inherit *av_inherit; |
| 31 | u32 av_inherit_len; | 31 | u32 av_inherit_len; |
| 32 | }; | 32 | }; |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 8f612c8becb5..01ec6d2c6b97 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -47,13 +47,7 @@ static char *policycap_names[] = { | |||
| 47 | 47 | ||
| 48 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; | 48 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; |
| 49 | 49 | ||
| 50 | #ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT | 50 | int selinux_compat_net = 0; |
| 51 | #define SELINUX_COMPAT_NET_VALUE 0 | ||
| 52 | #else | ||
| 53 | #define SELINUX_COMPAT_NET_VALUE 1 | ||
| 54 | #endif | ||
| 55 | |||
| 56 | int selinux_compat_net = SELINUX_COMPAT_NET_VALUE; | ||
| 57 | 51 | ||
| 58 | static int __init checkreqprot_setup(char *str) | 52 | static int __init checkreqprot_setup(char *str) |
| 59 | { | 53 | { |
| @@ -494,7 +488,13 @@ static ssize_t sel_write_compat_net(struct file *file, const char __user *buf, | |||
| 494 | if (sscanf(page, "%d", &new_value) != 1) | 488 | if (sscanf(page, "%d", &new_value) != 1) |
| 495 | goto out; | 489 | goto out; |
| 496 | 490 | ||
| 497 | selinux_compat_net = new_value ? 1 : 0; | 491 | if (new_value) { |
| 492 | printk(KERN_NOTICE | ||
| 493 | "SELinux: compat_net is deprecated, please use secmark" | ||
| 494 | " instead\n"); | ||
| 495 | selinux_compat_net = 1; | ||
| 496 | } else | ||
| 497 | selinux_compat_net = 0; | ||
| 498 | length = count; | 498 | length = count; |
| 499 | out: | 499 | out: |
| 500 | free_page((unsigned long) page); | 500 | free_page((unsigned long) page); |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 658c2bd17da8..d9dd7a2f6a8a 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
| @@ -27,9 +27,9 @@ struct context { | |||
| 27 | u32 user; | 27 | u32 user; |
| 28 | u32 role; | 28 | u32 role; |
| 29 | u32 type; | 29 | u32 type; |
| 30 | u32 len; /* length of string in bytes */ | ||
| 30 | struct mls_range range; | 31 | struct mls_range range; |
| 31 | char *str; /* string representation if context cannot be mapped. */ | 32 | char *str; /* string representation if context cannot be mapped. */ |
| 32 | u32 len; /* length of string in bytes */ | ||
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | static inline void mls_context_init(struct context *c) | 35 | static inline void mls_context_init(struct context *c) |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 31dce559595a..b79582e4fbfd 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/capability.h> | 16 | #include <linux/capability.h> |
| 17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
| 18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
| 19 | #include <linux/in.h> | ||
| 19 | #include <net/netlabel.h> | 20 | #include <net/netlabel.h> |
| 20 | 21 | ||
| 21 | /* | 22 | /* |
| @@ -39,6 +40,7 @@ struct superblock_smack { | |||
| 39 | struct socket_smack { | 40 | struct socket_smack { |
| 40 | char *smk_out; /* outbound label */ | 41 | char *smk_out; /* outbound label */ |
| 41 | char *smk_in; /* inbound label */ | 42 | char *smk_in; /* inbound label */ |
| 43 | int smk_labeled; /* label scheme */ | ||
| 42 | char smk_packet[SMK_LABELLEN]; /* TCP peer label */ | 44 | char smk_packet[SMK_LABELLEN]; /* TCP peer label */ |
| 43 | }; | 45 | }; |
| 44 | 46 | ||
| @@ -80,6 +82,16 @@ struct smack_cipso { | |||
| 80 | }; | 82 | }; |
| 81 | 83 | ||
| 82 | /* | 84 | /* |
| 85 | * An entry in the table identifying hosts. | ||
| 86 | */ | ||
| 87 | struct smk_netlbladdr { | ||
| 88 | struct smk_netlbladdr *smk_next; | ||
| 89 | struct sockaddr_in smk_host; /* network address */ | ||
| 90 | struct in_addr smk_mask; /* network mask */ | ||
| 91 | char *smk_label; /* label */ | ||
| 92 | }; | ||
| 93 | |||
| 94 | /* | ||
| 83 | * This is the repository for labels seen so that it is | 95 | * This is the repository for labels seen so that it is |
| 84 | * not necessary to keep allocating tiny chuncks of memory | 96 | * not necessary to keep allocating tiny chuncks of memory |
| 85 | * and so that they can be shared. | 97 | * and so that they can be shared. |
| @@ -127,6 +139,20 @@ struct smack_known { | |||
| 127 | #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT | 139 | #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT |
| 128 | 140 | ||
| 129 | /* | 141 | /* |
| 142 | * How communications on this socket are treated. | ||
| 143 | * Usually it's determined by the underlying netlabel code | ||
| 144 | * but there are certain cases, including single label hosts | ||
| 145 | * and potentially single label interfaces for which the | ||
| 146 | * treatment can not be known in advance. | ||
| 147 | * | ||
| 148 | * The possibility of additional labeling schemes being | ||
| 149 | * introduced in the future exists as well. | ||
| 150 | */ | ||
| 151 | #define SMACK_UNLABELED_SOCKET 0 | ||
| 152 | #define SMACK_CIPSO_SOCKET 1 | ||
| 153 | |||
| 154 | /* | ||
| 155 | * smackfs magic number | ||
| 130 | * smackfs macic number | 156 | * smackfs macic number |
| 131 | */ | 157 | */ |
| 132 | #define SMACK_MAGIC 0x43415d53 /* "SMAC" */ | 158 | #define SMACK_MAGIC 0x43415d53 /* "SMAC" */ |
| @@ -141,6 +167,7 @@ struct smack_known { | |||
| 141 | * CIPSO defaults. | 167 | * CIPSO defaults. |
| 142 | */ | 168 | */ |
| 143 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ | 169 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ |
| 170 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ | ||
| 144 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ | 171 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ |
| 145 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ | 172 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ |
| 146 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ | 173 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ |
| @@ -176,7 +203,6 @@ u32 smack_to_secid(const char *); | |||
| 176 | * Shared data. | 203 | * Shared data. |
| 177 | */ | 204 | */ |
| 178 | extern int smack_cipso_direct; | 205 | extern int smack_cipso_direct; |
| 179 | extern int smack_net_nltype; | ||
| 180 | extern char *smack_net_ambient; | 206 | extern char *smack_net_ambient; |
| 181 | extern char *smack_onlycap; | 207 | extern char *smack_onlycap; |
| 182 | 208 | ||
| @@ -186,9 +212,10 @@ extern struct smack_known smack_known_hat; | |||
| 186 | extern struct smack_known smack_known_huh; | 212 | extern struct smack_known smack_known_huh; |
| 187 | extern struct smack_known smack_known_invalid; | 213 | extern struct smack_known smack_known_invalid; |
| 188 | extern struct smack_known smack_known_star; | 214 | extern struct smack_known smack_known_star; |
| 189 | extern struct smack_known smack_known_unset; | 215 | extern struct smack_known smack_known_web; |
| 190 | 216 | ||
| 191 | extern struct smk_list_entry *smack_list; | 217 | extern struct smk_list_entry *smack_list; |
| 218 | extern struct smk_netlbladdr *smack_netlbladdrs; | ||
| 192 | extern struct security_operations smack_ops; | 219 | extern struct security_operations smack_ops; |
| 193 | 220 | ||
| 194 | /* | 221 | /* |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 247cec3b5a43..2e0b83e77ffe 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
| @@ -15,15 +15,8 @@ | |||
| 15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
| 16 | #include "smack.h" | 16 | #include "smack.h" |
| 17 | 17 | ||
| 18 | struct smack_known smack_known_unset = { | ||
| 19 | .smk_next = NULL, | ||
| 20 | .smk_known = "UNSET", | ||
| 21 | .smk_secid = 1, | ||
| 22 | .smk_cipso = NULL, | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct smack_known smack_known_huh = { | 18 | struct smack_known smack_known_huh = { |
| 26 | .smk_next = &smack_known_unset, | 19 | .smk_next = NULL, |
| 27 | .smk_known = "?", | 20 | .smk_known = "?", |
| 28 | .smk_secid = 2, | 21 | .smk_secid = 2, |
| 29 | .smk_cipso = NULL, | 22 | .smk_cipso = NULL, |
| @@ -57,7 +50,14 @@ struct smack_known smack_known_invalid = { | |||
| 57 | .smk_cipso = NULL, | 50 | .smk_cipso = NULL, |
| 58 | }; | 51 | }; |
| 59 | 52 | ||
| 60 | struct smack_known *smack_known = &smack_known_invalid; | 53 | struct smack_known smack_known_web = { |
| 54 | .smk_next = &smack_known_invalid, | ||
| 55 | .smk_known = "@", | ||
| 56 | .smk_secid = 7, | ||
| 57 | .smk_cipso = NULL, | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct smack_known *smack_known = &smack_known_web; | ||
| 61 | 61 | ||
| 62 | /* | 62 | /* |
| 63 | * The initial value needs to be bigger than any of the | 63 | * The initial value needs to be bigger than any of the |
| @@ -99,6 +99,16 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
| 99 | strcmp(subject_label, smack_known_star.smk_known) == 0) | 99 | strcmp(subject_label, smack_known_star.smk_known) == 0) |
| 100 | return -EACCES; | 100 | return -EACCES; |
| 101 | /* | 101 | /* |
| 102 | * An internet object can be accessed by any subject. | ||
| 103 | * Tasks cannot be assigned the internet label. | ||
| 104 | * An internet subject can access any object. | ||
| 105 | */ | ||
| 106 | if (object_label == smack_known_web.smk_known || | ||
| 107 | subject_label == smack_known_web.smk_known || | ||
| 108 | strcmp(object_label, smack_known_web.smk_known) == 0 || | ||
| 109 | strcmp(subject_label, smack_known_web.smk_known) == 0) | ||
| 110 | return 0; | ||
| 111 | /* | ||
| 102 | * A star object can be accessed by any subject. | 112 | * A star object can be accessed by any subject. |
| 103 | */ | 113 | */ |
| 104 | if (object_label == smack_known_star.smk_known || | 114 | if (object_label == smack_known_star.smk_known || |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 848212fd4845..0278bc083044 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -1277,6 +1277,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) | |||
| 1277 | 1277 | ||
| 1278 | ssp->smk_in = csp; | 1278 | ssp->smk_in = csp; |
| 1279 | ssp->smk_out = csp; | 1279 | ssp->smk_out = csp; |
| 1280 | ssp->smk_labeled = SMACK_CIPSO_SOCKET; | ||
| 1280 | ssp->smk_packet[0] = '\0'; | 1281 | ssp->smk_packet[0] = '\0'; |
| 1281 | 1282 | ||
| 1282 | sk->sk_security = ssp; | 1283 | sk->sk_security = ssp; |
| @@ -1341,45 +1342,69 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | |||
| 1341 | struct smack_cipso cipso; | 1342 | struct smack_cipso cipso; |
| 1342 | int rc; | 1343 | int rc; |
| 1343 | 1344 | ||
| 1344 | switch (smack_net_nltype) { | 1345 | nlsp->domain = smack; |
| 1345 | case NETLBL_NLTYPE_CIPSOV4: | 1346 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; |
| 1346 | nlsp->domain = smack; | ||
| 1347 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
| 1348 | 1347 | ||
| 1349 | rc = smack_to_cipso(smack, &cipso); | 1348 | rc = smack_to_cipso(smack, &cipso); |
| 1350 | if (rc == 0) { | 1349 | if (rc == 0) { |
| 1351 | nlsp->attr.mls.lvl = cipso.smk_level; | 1350 | nlsp->attr.mls.lvl = cipso.smk_level; |
| 1352 | smack_set_catset(cipso.smk_catset, nlsp); | 1351 | smack_set_catset(cipso.smk_catset, nlsp); |
| 1353 | } else { | 1352 | } else { |
| 1354 | nlsp->attr.mls.lvl = smack_cipso_direct; | 1353 | nlsp->attr.mls.lvl = smack_cipso_direct; |
| 1355 | smack_set_catset(smack, nlsp); | 1354 | smack_set_catset(smack, nlsp); |
| 1356 | } | ||
| 1357 | break; | ||
| 1358 | default: | ||
| 1359 | break; | ||
| 1360 | } | 1355 | } |
| 1361 | } | 1356 | } |
| 1362 | 1357 | ||
| 1363 | /** | 1358 | /** |
| 1364 | * smack_netlabel - Set the secattr on a socket | 1359 | * smack_netlabel - Set the secattr on a socket |
| 1365 | * @sk: the socket | 1360 | * @sk: the socket |
| 1361 | * @labeled: socket label scheme | ||
| 1366 | * | 1362 | * |
| 1367 | * Convert the outbound smack value (smk_out) to a | 1363 | * Convert the outbound smack value (smk_out) to a |
| 1368 | * secattr and attach it to the socket. | 1364 | * secattr and attach it to the socket. |
| 1369 | * | 1365 | * |
| 1370 | * Returns 0 on success or an error code | 1366 | * Returns 0 on success or an error code |
| 1371 | */ | 1367 | */ |
| 1372 | static int smack_netlabel(struct sock *sk) | 1368 | static int smack_netlabel(struct sock *sk, int labeled) |
| 1373 | { | 1369 | { |
| 1374 | struct socket_smack *ssp; | 1370 | struct socket_smack *ssp; |
| 1375 | struct netlbl_lsm_secattr secattr; | 1371 | struct netlbl_lsm_secattr secattr; |
| 1376 | int rc; | 1372 | int rc = 0; |
| 1377 | 1373 | ||
| 1378 | ssp = sk->sk_security; | 1374 | ssp = sk->sk_security; |
| 1379 | netlbl_secattr_init(&secattr); | 1375 | /* |
| 1380 | smack_to_secattr(ssp->smk_out, &secattr); | 1376 | * Usually the netlabel code will handle changing the |
| 1381 | rc = netlbl_sock_setattr(sk, &secattr); | 1377 | * packet labeling based on the label. |
| 1382 | netlbl_secattr_destroy(&secattr); | 1378 | * The case of a single label host is different, because |
| 1379 | * a single label host should never get a labeled packet | ||
| 1380 | * even though the label is usually associated with a packet | ||
| 1381 | * label. | ||
| 1382 | */ | ||
| 1383 | local_bh_disable(); | ||
| 1384 | bh_lock_sock_nested(sk); | ||
| 1385 | |||
| 1386 | if (ssp->smk_out == smack_net_ambient || | ||
| 1387 | labeled == SMACK_UNLABELED_SOCKET) | ||
| 1388 | netlbl_sock_delattr(sk); | ||
| 1389 | else { | ||
| 1390 | netlbl_secattr_init(&secattr); | ||
| 1391 | smack_to_secattr(ssp->smk_out, &secattr); | ||
| 1392 | rc = netlbl_sock_setattr(sk, &secattr); | ||
| 1393 | netlbl_secattr_destroy(&secattr); | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | bh_unlock_sock(sk); | ||
| 1397 | local_bh_enable(); | ||
| 1398 | /* | ||
| 1399 | * Remember the label scheme used so that it is not | ||
| 1400 | * necessary to do the netlabel setting if it has not | ||
| 1401 | * changed the next time through. | ||
| 1402 | * | ||
| 1403 | * The -EDESTADDRREQ case is an indication that there's | ||
| 1404 | * a single level host involved. | ||
| 1405 | */ | ||
| 1406 | if (rc == 0) | ||
| 1407 | ssp->smk_labeled = labeled; | ||
| 1383 | 1408 | ||
| 1384 | return rc; | 1409 | return rc; |
| 1385 | } | 1410 | } |
| @@ -1432,7 +1457,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
| 1432 | ssp->smk_in = sp; | 1457 | ssp->smk_in = sp; |
| 1433 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { | 1458 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { |
| 1434 | ssp->smk_out = sp; | 1459 | ssp->smk_out = sp; |
| 1435 | rc = smack_netlabel(sock->sk); | 1460 | rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
| 1436 | if (rc != 0) | 1461 | if (rc != 0) |
| 1437 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", | 1462 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", |
| 1438 | __func__, -rc); | 1463 | __func__, -rc); |
| @@ -1462,7 +1487,108 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
| 1462 | /* | 1487 | /* |
| 1463 | * Set the outbound netlbl. | 1488 | * Set the outbound netlbl. |
| 1464 | */ | 1489 | */ |
| 1465 | return smack_netlabel(sock->sk); | 1490 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
| 1491 | } | ||
| 1492 | |||
| 1493 | |||
| 1494 | /** | ||
| 1495 | * smack_host_label - check host based restrictions | ||
| 1496 | * @sip: the object end | ||
| 1497 | * | ||
| 1498 | * looks for host based access restrictions | ||
| 1499 | * | ||
| 1500 | * This version will only be appropriate for really small | ||
| 1501 | * sets of single label hosts. Because of the masking | ||
| 1502 | * it cannot shortcut out on the first match. There are | ||
| 1503 | * numerious ways to address the problem, but none of them | ||
| 1504 | * have been applied here. | ||
| 1505 | * | ||
| 1506 | * Returns the label of the far end or NULL if it's not special. | ||
| 1507 | */ | ||
| 1508 | static char *smack_host_label(struct sockaddr_in *sip) | ||
| 1509 | { | ||
| 1510 | struct smk_netlbladdr *snp; | ||
| 1511 | char *bestlabel = NULL; | ||
| 1512 | struct in_addr *siap = &sip->sin_addr; | ||
| 1513 | struct in_addr *liap; | ||
| 1514 | struct in_addr *miap; | ||
| 1515 | struct in_addr bestmask; | ||
| 1516 | |||
| 1517 | if (siap->s_addr == 0) | ||
| 1518 | return NULL; | ||
| 1519 | |||
| 1520 | bestmask.s_addr = 0; | ||
| 1521 | |||
| 1522 | for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) { | ||
| 1523 | liap = &snp->smk_host.sin_addr; | ||
| 1524 | miap = &snp->smk_mask; | ||
| 1525 | /* | ||
| 1526 | * If the addresses match after applying the list entry mask | ||
| 1527 | * the entry matches the address. If it doesn't move along to | ||
| 1528 | * the next entry. | ||
| 1529 | */ | ||
| 1530 | if ((liap->s_addr & miap->s_addr) != | ||
| 1531 | (siap->s_addr & miap->s_addr)) | ||
| 1532 | continue; | ||
| 1533 | /* | ||
| 1534 | * If the list entry mask identifies a single address | ||
| 1535 | * it can't get any more specific. | ||
| 1536 | */ | ||
| 1537 | if (miap->s_addr == 0xffffffff) | ||
| 1538 | return snp->smk_label; | ||
| 1539 | /* | ||
| 1540 | * If the list entry mask is less specific than the best | ||
| 1541 | * already found this entry is uninteresting. | ||
| 1542 | */ | ||
| 1543 | if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr) | ||
| 1544 | continue; | ||
| 1545 | /* | ||
| 1546 | * This is better than any entry found so far. | ||
| 1547 | */ | ||
| 1548 | bestmask.s_addr = miap->s_addr; | ||
| 1549 | bestlabel = snp->smk_label; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | return bestlabel; | ||
| 1553 | } | ||
| 1554 | |||
| 1555 | /** | ||
| 1556 | * smack_socket_connect - connect access check | ||
| 1557 | * @sock: the socket | ||
| 1558 | * @sap: the other end | ||
| 1559 | * @addrlen: size of sap | ||
| 1560 | * | ||
| 1561 | * Verifies that a connection may be possible | ||
| 1562 | * | ||
| 1563 | * Returns 0 on success, and error code otherwise | ||
| 1564 | */ | ||
| 1565 | static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | ||
| 1566 | int addrlen) | ||
| 1567 | { | ||
| 1568 | struct socket_smack *ssp = sock->sk->sk_security; | ||
| 1569 | char *hostsp; | ||
| 1570 | int rc; | ||
| 1571 | |||
| 1572 | if (sock->sk == NULL || sock->sk->sk_family != PF_INET) | ||
| 1573 | return 0; | ||
| 1574 | |||
| 1575 | if (addrlen < sizeof(struct sockaddr_in)) | ||
| 1576 | return -EINVAL; | ||
| 1577 | |||
| 1578 | hostsp = smack_host_label((struct sockaddr_in *)sap); | ||
| 1579 | if (hostsp == NULL) { | ||
| 1580 | if (ssp->smk_labeled != SMACK_CIPSO_SOCKET) | ||
| 1581 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | ||
| 1582 | return 0; | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
| 1586 | if (rc != 0) | ||
| 1587 | return rc; | ||
| 1588 | |||
| 1589 | if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET) | ||
| 1590 | return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET); | ||
| 1591 | return 0; | ||
| 1466 | } | 1592 | } |
| 1467 | 1593 | ||
| 1468 | /** | 1594 | /** |
| @@ -2101,8 +2227,14 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
| 2101 | if (newsmack == NULL) | 2227 | if (newsmack == NULL) |
| 2102 | return -EINVAL; | 2228 | return -EINVAL; |
| 2103 | 2229 | ||
| 2230 | /* | ||
| 2231 | * No process is ever allowed the web ("@") label. | ||
| 2232 | */ | ||
| 2233 | if (newsmack == smack_known_web.smk_known) | ||
| 2234 | return -EPERM; | ||
| 2235 | |||
| 2104 | new = prepare_creds(); | 2236 | new = prepare_creds(); |
| 2105 | if (!new) | 2237 | if (new == NULL) |
| 2106 | return -ENOMEM; | 2238 | return -ENOMEM; |
| 2107 | new->security = newsmack; | 2239 | new->security = newsmack; |
| 2108 | commit_creds(new); | 2240 | commit_creds(new); |
| @@ -2144,6 +2276,49 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
| 2144 | } | 2276 | } |
| 2145 | 2277 | ||
| 2146 | /** | 2278 | /** |
| 2279 | * smack_socket_sendmsg - Smack check based on destination host | ||
| 2280 | * @sock: the socket | ||
| 2281 | * @msghdr: the message | ||
| 2282 | * @size: the size of the message | ||
| 2283 | * | ||
| 2284 | * Return 0 if the current subject can write to the destination | ||
| 2285 | * host. This is only a question if the destination is a single | ||
| 2286 | * label host. | ||
| 2287 | */ | ||
| 2288 | static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | ||
| 2289 | int size) | ||
| 2290 | { | ||
| 2291 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; | ||
| 2292 | struct socket_smack *ssp = sock->sk->sk_security; | ||
| 2293 | char *hostsp; | ||
| 2294 | int rc; | ||
| 2295 | |||
| 2296 | /* | ||
| 2297 | * Perfectly reasonable for this to be NULL | ||
| 2298 | */ | ||
| 2299 | if (sip == NULL || sip->sin_family != PF_INET) | ||
| 2300 | return 0; | ||
| 2301 | |||
| 2302 | hostsp = smack_host_label(sip); | ||
| 2303 | if (hostsp == NULL) { | ||
| 2304 | if (ssp->smk_labeled != SMACK_CIPSO_SOCKET) | ||
| 2305 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | ||
| 2306 | return 0; | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
| 2310 | if (rc != 0) | ||
| 2311 | return rc; | ||
| 2312 | |||
| 2313 | if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET) | ||
| 2314 | return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET); | ||
| 2315 | |||
| 2316 | return 0; | ||
| 2317 | |||
| 2318 | } | ||
| 2319 | |||
| 2320 | |||
| 2321 | /** | ||
| 2147 | * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat | 2322 | * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat |
| 2148 | * pair to smack | 2323 | * pair to smack |
| 2149 | * @sap: netlabel secattr | 2324 | * @sap: netlabel secattr |
| @@ -2154,44 +2329,66 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
| 2154 | static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) | 2329 | static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) |
| 2155 | { | 2330 | { |
| 2156 | char smack[SMK_LABELLEN]; | 2331 | char smack[SMK_LABELLEN]; |
| 2332 | char *sp; | ||
| 2157 | int pcat; | 2333 | int pcat; |
| 2158 | 2334 | ||
| 2159 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) { | 2335 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { |
| 2160 | /* | 2336 | /* |
| 2337 | * Looks like a CIPSO packet. | ||
| 2161 | * If there are flags but no level netlabel isn't | 2338 | * If there are flags but no level netlabel isn't |
| 2162 | * behaving the way we expect it to. | 2339 | * behaving the way we expect it to. |
| 2163 | * | 2340 | * |
| 2341 | * Get the categories, if any | ||
| 2164 | * Without guidance regarding the smack value | 2342 | * Without guidance regarding the smack value |
| 2165 | * for the packet fall back on the network | 2343 | * for the packet fall back on the network |
| 2166 | * ambient value. | 2344 | * ambient value. |
| 2167 | */ | 2345 | */ |
| 2168 | strncpy(sip, smack_net_ambient, SMK_MAXLEN); | 2346 | memset(smack, '\0', SMK_LABELLEN); |
| 2347 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | ||
| 2348 | for (pcat = -1;;) { | ||
| 2349 | pcat = netlbl_secattr_catmap_walk( | ||
| 2350 | sap->attr.mls.cat, pcat + 1); | ||
| 2351 | if (pcat < 0) | ||
| 2352 | break; | ||
| 2353 | smack_catset_bit(pcat, smack); | ||
| 2354 | } | ||
| 2355 | /* | ||
| 2356 | * If it is CIPSO using smack direct mapping | ||
| 2357 | * we are already done. WeeHee. | ||
| 2358 | */ | ||
| 2359 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
| 2360 | memcpy(sip, smack, SMK_MAXLEN); | ||
| 2361 | return; | ||
| 2362 | } | ||
| 2363 | /* | ||
| 2364 | * Look it up in the supplied table if it is not | ||
| 2365 | * a direct mapping. | ||
| 2366 | */ | ||
| 2367 | smack_from_cipso(sap->attr.mls.lvl, smack, sip); | ||
| 2169 | return; | 2368 | return; |
| 2170 | } | 2369 | } |
| 2171 | /* | 2370 | if ((sap->flags & NETLBL_SECATTR_SECID) != 0) { |
| 2172 | * Get the categories, if any | 2371 | /* |
| 2173 | */ | 2372 | * Looks like a fallback, which gives us a secid. |
| 2174 | memset(smack, '\0', SMK_LABELLEN); | 2373 | */ |
| 2175 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | 2374 | sp = smack_from_secid(sap->attr.secid); |
| 2176 | for (pcat = -1;;) { | 2375 | /* |
| 2177 | pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat, | 2376 | * This has got to be a bug because it is |
| 2178 | pcat + 1); | 2377 | * impossible to specify a fallback without |
| 2179 | if (pcat < 0) | 2378 | * specifying the label, which will ensure |
| 2180 | break; | 2379 | * it has a secid, and the only way to get a |
| 2181 | smack_catset_bit(pcat, smack); | 2380 | * secid is from a fallback. |
| 2182 | } | 2381 | */ |
| 2183 | /* | 2382 | BUG_ON(sp == NULL); |
| 2184 | * If it is CIPSO using smack direct mapping | 2383 | strncpy(sip, sp, SMK_MAXLEN); |
| 2185 | * we are already done. WeeHee. | ||
| 2186 | */ | ||
| 2187 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
| 2188 | memcpy(sip, smack, SMK_MAXLEN); | ||
| 2189 | return; | 2384 | return; |
| 2190 | } | 2385 | } |
| 2191 | /* | 2386 | /* |
| 2192 | * Look it up in the supplied table if it is not a direct mapping. | 2387 | * Without guidance regarding the smack value |
| 2388 | * for the packet fall back on the network | ||
| 2389 | * ambient value. | ||
| 2193 | */ | 2390 | */ |
| 2194 | smack_from_cipso(sap->attr.mls.lvl, smack, sip); | 2391 | strncpy(sip, smack_net_ambient, SMK_MAXLEN); |
| 2195 | return; | 2392 | return; |
| 2196 | } | 2393 | } |
| 2197 | 2394 | ||
| @@ -2207,6 +2404,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 2207 | struct netlbl_lsm_secattr secattr; | 2404 | struct netlbl_lsm_secattr secattr; |
| 2208 | struct socket_smack *ssp = sk->sk_security; | 2405 | struct socket_smack *ssp = sk->sk_security; |
| 2209 | char smack[SMK_LABELLEN]; | 2406 | char smack[SMK_LABELLEN]; |
| 2407 | char *csp; | ||
| 2210 | int rc; | 2408 | int rc; |
| 2211 | 2409 | ||
| 2212 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) | 2410 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) |
| @@ -2215,21 +2413,24 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 2215 | /* | 2413 | /* |
| 2216 | * Translate what netlabel gave us. | 2414 | * Translate what netlabel gave us. |
| 2217 | */ | 2415 | */ |
| 2218 | memset(smack, '\0', SMK_LABELLEN); | ||
| 2219 | netlbl_secattr_init(&secattr); | 2416 | netlbl_secattr_init(&secattr); |
| 2417 | |||
| 2220 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); | 2418 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); |
| 2221 | if (rc == 0) | 2419 | if (rc == 0) { |
| 2222 | smack_from_secattr(&secattr, smack); | 2420 | smack_from_secattr(&secattr, smack); |
| 2223 | else | 2421 | csp = smack; |
| 2224 | strncpy(smack, smack_net_ambient, SMK_MAXLEN); | 2422 | } else |
| 2423 | csp = smack_net_ambient; | ||
| 2424 | |||
| 2225 | netlbl_secattr_destroy(&secattr); | 2425 | netlbl_secattr_destroy(&secattr); |
| 2426 | |||
| 2226 | /* | 2427 | /* |
| 2227 | * Receiving a packet requires that the other end | 2428 | * Receiving a packet requires that the other end |
| 2228 | * be able to write here. Read access is not required. | 2429 | * be able to write here. Read access is not required. |
| 2229 | * This is the simplist possible security model | 2430 | * This is the simplist possible security model |
| 2230 | * for networking. | 2431 | * for networking. |
| 2231 | */ | 2432 | */ |
| 2232 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); | 2433 | rc = smk_access(csp, ssp->smk_in, MAY_WRITE); |
| 2233 | if (rc != 0) | 2434 | if (rc != 0) |
| 2234 | netlbl_skbuff_err(skb, rc, 0); | 2435 | netlbl_skbuff_err(skb, rc, 0); |
| 2235 | return rc; | 2436 | return rc; |
| @@ -2298,7 +2499,6 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, | |||
| 2298 | /* | 2499 | /* |
| 2299 | * Translate what netlabel gave us. | 2500 | * Translate what netlabel gave us. |
| 2300 | */ | 2501 | */ |
| 2301 | memset(smack, '\0', SMK_LABELLEN); | ||
| 2302 | netlbl_secattr_init(&secattr); | 2502 | netlbl_secattr_init(&secattr); |
| 2303 | rc = netlbl_skbuff_getattr(skb, family, &secattr); | 2503 | rc = netlbl_skbuff_getattr(skb, family, &secattr); |
| 2304 | if (rc == 0) | 2504 | if (rc == 0) |
| @@ -2341,7 +2541,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) | |||
| 2341 | ssp->smk_in = ssp->smk_out = current_security(); | 2541 | ssp->smk_in = ssp->smk_out = current_security(); |
| 2342 | ssp->smk_packet[0] = '\0'; | 2542 | ssp->smk_packet[0] = '\0'; |
| 2343 | 2543 | ||
| 2344 | rc = smack_netlabel(sk); | 2544 | rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET); |
| 2345 | if (rc != 0) | 2545 | if (rc != 0) |
| 2346 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", | 2546 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", |
| 2347 | __func__, -rc); | 2547 | __func__, -rc); |
| @@ -2367,7 +2567,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 2367 | if (skb == NULL) | 2567 | if (skb == NULL) |
| 2368 | return -EACCES; | 2568 | return -EACCES; |
| 2369 | 2569 | ||
| 2370 | memset(smack, '\0', SMK_LABELLEN); | ||
| 2371 | netlbl_secattr_init(&skb_secattr); | 2570 | netlbl_secattr_init(&skb_secattr); |
| 2372 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); | 2571 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); |
| 2373 | if (rc == 0) | 2572 | if (rc == 0) |
| @@ -2732,6 +2931,8 @@ struct security_operations smack_ops = { | |||
| 2732 | .unix_may_send = smack_unix_may_send, | 2931 | .unix_may_send = smack_unix_may_send, |
| 2733 | 2932 | ||
| 2734 | .socket_post_create = smack_socket_post_create, | 2933 | .socket_post_create = smack_socket_post_create, |
| 2934 | .socket_connect = smack_socket_connect, | ||
| 2935 | .socket_sendmsg = smack_socket_sendmsg, | ||
| 2735 | .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, | 2936 | .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, |
| 2736 | .socket_getpeersec_stream = smack_socket_getpeersec_stream, | 2937 | .socket_getpeersec_stream = smack_socket_getpeersec_stream, |
| 2737 | .socket_getpeersec_dgram = smack_socket_getpeersec_dgram, | 2938 | .socket_getpeersec_dgram = smack_socket_getpeersec_dgram, |
| @@ -2783,7 +2984,6 @@ static __init int smack_init(void) | |||
| 2783 | /* | 2984 | /* |
| 2784 | * Initialize locks | 2985 | * Initialize locks |
| 2785 | */ | 2986 | */ |
| 2786 | spin_lock_init(&smack_known_unset.smk_cipsolock); | ||
| 2787 | spin_lock_init(&smack_known_huh.smk_cipsolock); | 2987 | spin_lock_init(&smack_known_huh.smk_cipsolock); |
| 2788 | spin_lock_init(&smack_known_hat.smk_cipsolock); | 2988 | spin_lock_init(&smack_known_hat.smk_cipsolock); |
| 2789 | spin_lock_init(&smack_known_star.smk_cipsolock); | 2989 | spin_lock_init(&smack_known_star.smk_cipsolock); |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 247dc9ebbc71..bf107a389ac1 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
| 21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
| 22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
| 23 | #include <net/net_namespace.h> | ||
| 23 | #include <net/netlabel.h> | 24 | #include <net/netlabel.h> |
| 24 | #include <net/cipso_ipv4.h> | 25 | #include <net/cipso_ipv4.h> |
| 25 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
| @@ -38,7 +39,7 @@ enum smk_inos { | |||
| 38 | SMK_DOI = 5, /* CIPSO DOI */ | 39 | SMK_DOI = 5, /* CIPSO DOI */ |
| 39 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ | 40 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ |
| 40 | SMK_AMBIENT = 7, /* internet ambient label */ | 41 | SMK_AMBIENT = 7, /* internet ambient label */ |
| 41 | SMK_NLTYPE = 8, /* label scheme to use by default */ | 42 | SMK_NETLBLADDR = 8, /* single label hosts */ |
| 42 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 43 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
| 43 | }; | 44 | }; |
| 44 | 45 | ||
| @@ -48,6 +49,7 @@ enum smk_inos { | |||
| 48 | static DEFINE_MUTEX(smack_list_lock); | 49 | static DEFINE_MUTEX(smack_list_lock); |
| 49 | static DEFINE_MUTEX(smack_cipso_lock); | 50 | static DEFINE_MUTEX(smack_cipso_lock); |
| 50 | static DEFINE_MUTEX(smack_ambient_lock); | 51 | static DEFINE_MUTEX(smack_ambient_lock); |
| 52 | static DEFINE_MUTEX(smk_netlbladdr_lock); | ||
| 51 | 53 | ||
| 52 | /* | 54 | /* |
| 53 | * This is the "ambient" label for network traffic. | 55 | * This is the "ambient" label for network traffic. |
| @@ -57,12 +59,6 @@ static DEFINE_MUTEX(smack_ambient_lock); | |||
| 57 | char *smack_net_ambient = smack_known_floor.smk_known; | 59 | char *smack_net_ambient = smack_known_floor.smk_known; |
| 58 | 60 | ||
| 59 | /* | 61 | /* |
| 60 | * This is the default packet marking scheme for network traffic. | ||
| 61 | * It can be reset via smackfs/nltype | ||
| 62 | */ | ||
| 63 | int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4; | ||
| 64 | |||
| 65 | /* | ||
| 66 | * This is the level in a CIPSO header that indicates a | 62 | * This is the level in a CIPSO header that indicates a |
| 67 | * smack label is contained directly in the category set. | 63 | * smack label is contained directly in the category set. |
| 68 | * It can be reset via smackfs/direct | 64 | * It can be reset via smackfs/direct |
| @@ -79,6 +75,13 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | |||
| 79 | */ | 75 | */ |
| 80 | char *smack_onlycap; | 76 | char *smack_onlycap; |
| 81 | 77 | ||
| 78 | /* | ||
| 79 | * Certain IP addresses may be designated as single label hosts. | ||
| 80 | * Packets are sent there unlabeled, but only from tasks that | ||
| 81 | * can write to the specified label. | ||
| 82 | */ | ||
| 83 | struct smk_netlbladdr *smack_netlbladdrs; | ||
| 84 | |||
| 82 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 85 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
| 83 | struct smk_list_entry *smack_list; | 86 | struct smk_list_entry *smack_list; |
| 84 | 87 | ||
| @@ -104,6 +107,24 @@ struct smk_list_entry *smack_list; | |||
| 104 | #define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) | 107 | #define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) |
| 105 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) | 108 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) |
| 106 | 109 | ||
| 110 | /** | ||
| 111 | * smk_netlabel_audit_set - fill a netlbl_audit struct | ||
| 112 | * @nap: structure to fill | ||
| 113 | */ | ||
| 114 | static void smk_netlabel_audit_set(struct netlbl_audit *nap) | ||
| 115 | { | ||
| 116 | nap->loginuid = audit_get_loginuid(current); | ||
| 117 | nap->sessionid = audit_get_sessionid(current); | ||
| 118 | nap->secid = smack_to_secid(current_security()); | ||
| 119 | } | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Values for parsing single label host rules | ||
| 123 | * "1.2.3.4 X" | ||
| 124 | * "192.168.138.129/32 abcdefghijklmnopqrstuvw" | ||
| 125 | */ | ||
| 126 | #define SMK_NETLBLADDRMIN 9 | ||
| 127 | #define SMK_NETLBLADDRMAX 42 | ||
| 107 | 128 | ||
| 108 | /* | 129 | /* |
| 109 | * Seq_file read operations for /smack/load | 130 | * Seq_file read operations for /smack/load |
| @@ -344,13 +365,11 @@ static void smk_cipso_doi(void) | |||
| 344 | { | 365 | { |
| 345 | int rc; | 366 | int rc; |
| 346 | struct cipso_v4_doi *doip; | 367 | struct cipso_v4_doi *doip; |
| 347 | struct netlbl_audit audit_info; | 368 | struct netlbl_audit nai; |
| 348 | 369 | ||
| 349 | audit_info.loginuid = audit_get_loginuid(current); | 370 | smk_netlabel_audit_set(&nai); |
| 350 | audit_info.sessionid = audit_get_sessionid(current); | ||
| 351 | audit_info.secid = smack_to_secid(current_security()); | ||
| 352 | 371 | ||
| 353 | rc = netlbl_cfg_map_del(NULL, &audit_info); | 372 | rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); |
| 354 | if (rc != 0) | 373 | if (rc != 0) |
| 355 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 374 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
| 356 | __func__, __LINE__, rc); | 375 | __func__, __LINE__, rc); |
| @@ -365,11 +384,19 @@ static void smk_cipso_doi(void) | |||
| 365 | for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) | 384 | for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) |
| 366 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; | 385 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; |
| 367 | 386 | ||
| 368 | rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); | 387 | rc = netlbl_cfg_cipsov4_add(doip, &nai); |
| 369 | if (rc != 0) { | 388 | if (rc != 0) { |
| 370 | printk(KERN_WARNING "%s:%d add rc = %d\n", | 389 | printk(KERN_WARNING "%s:%d cipso add rc = %d\n", |
| 371 | __func__, __LINE__, rc); | 390 | __func__, __LINE__, rc); |
| 372 | kfree(doip); | 391 | kfree(doip); |
| 392 | return; | ||
| 393 | } | ||
| 394 | rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); | ||
| 395 | if (rc != 0) { | ||
| 396 | printk(KERN_WARNING "%s:%d map add rc = %d\n", | ||
| 397 | __func__, __LINE__, rc); | ||
| 398 | kfree(doip); | ||
| 399 | return; | ||
| 373 | } | 400 | } |
| 374 | } | 401 | } |
| 375 | 402 | ||
| @@ -379,20 +406,19 @@ static void smk_cipso_doi(void) | |||
| 379 | static void smk_unlbl_ambient(char *oldambient) | 406 | static void smk_unlbl_ambient(char *oldambient) |
| 380 | { | 407 | { |
| 381 | int rc; | 408 | int rc; |
| 382 | struct netlbl_audit audit_info; | 409 | struct netlbl_audit nai; |
| 383 | 410 | ||
| 384 | audit_info.loginuid = audit_get_loginuid(current); | 411 | smk_netlabel_audit_set(&nai); |
| 385 | audit_info.sessionid = audit_get_sessionid(current); | ||
| 386 | audit_info.secid = smack_to_secid(current_security()); | ||
| 387 | 412 | ||
| 388 | if (oldambient != NULL) { | 413 | if (oldambient != NULL) { |
| 389 | rc = netlbl_cfg_map_del(oldambient, &audit_info); | 414 | rc = netlbl_cfg_map_del(oldambient, PF_INET, NULL, NULL, &nai); |
| 390 | if (rc != 0) | 415 | if (rc != 0) |
| 391 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 416 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
| 392 | __func__, __LINE__, rc); | 417 | __func__, __LINE__, rc); |
| 393 | } | 418 | } |
| 394 | 419 | ||
| 395 | rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info); | 420 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, |
| 421 | NULL, NULL, &nai); | ||
| 396 | if (rc != 0) | 422 | if (rc != 0) |
| 397 | printk(KERN_WARNING "%s:%d add rc = %d\n", | 423 | printk(KERN_WARNING "%s:%d add rc = %d\n", |
| 398 | __func__, __LINE__, rc); | 424 | __func__, __LINE__, rc); |
| @@ -603,6 +629,201 @@ static const struct file_operations smk_cipso_ops = { | |||
| 603 | .release = seq_release, | 629 | .release = seq_release, |
| 604 | }; | 630 | }; |
| 605 | 631 | ||
| 632 | /* | ||
| 633 | * Seq_file read operations for /smack/netlabel | ||
| 634 | */ | ||
| 635 | |||
| 636 | static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) | ||
| 637 | { | ||
| 638 | if (*pos == SEQ_READ_FINISHED) | ||
| 639 | return NULL; | ||
| 640 | |||
| 641 | return smack_netlbladdrs; | ||
| 642 | } | ||
| 643 | |||
| 644 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
| 645 | { | ||
| 646 | struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next; | ||
| 647 | |||
| 648 | if (skp == NULL) | ||
| 649 | *pos = SEQ_READ_FINISHED; | ||
| 650 | |||
| 651 | return skp; | ||
| 652 | } | ||
| 653 | /* | ||
| 654 | #define BEMASK 0x80000000 | ||
| 655 | */ | ||
| 656 | #define BEMASK 0x00000001 | ||
| 657 | #define BEBITS (sizeof(__be32) * 8) | ||
| 658 | |||
| 659 | /* | ||
| 660 | * Print host/label pairs | ||
| 661 | */ | ||
| 662 | static int netlbladdr_seq_show(struct seq_file *s, void *v) | ||
| 663 | { | ||
| 664 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; | ||
| 665 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | ||
| 666 | __be32 bebits; | ||
| 667 | int maskn = 0; | ||
| 668 | |||
| 669 | for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1) | ||
| 670 | if ((skp->smk_mask.s_addr & bebits) == 0) | ||
| 671 | break; | ||
| 672 | |||
| 673 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", | ||
| 674 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); | ||
| 675 | |||
| 676 | return 0; | ||
| 677 | } | ||
| 678 | |||
| 679 | static void netlbladdr_seq_stop(struct seq_file *s, void *v) | ||
| 680 | { | ||
| 681 | /* No-op */ | ||
| 682 | } | ||
| 683 | |||
| 684 | static struct seq_operations netlbladdr_seq_ops = { | ||
| 685 | .start = netlbladdr_seq_start, | ||
| 686 | .stop = netlbladdr_seq_stop, | ||
| 687 | .next = netlbladdr_seq_next, | ||
| 688 | .show = netlbladdr_seq_show, | ||
| 689 | }; | ||
| 690 | |||
| 691 | /** | ||
| 692 | * smk_open_netlbladdr - open() for /smack/netlabel | ||
| 693 | * @inode: inode structure representing file | ||
| 694 | * @file: "netlabel" file pointer | ||
| 695 | * | ||
| 696 | * Connect our netlbladdr_seq_* operations with /smack/netlabel | ||
| 697 | * file_operations | ||
| 698 | */ | ||
| 699 | static int smk_open_netlbladdr(struct inode *inode, struct file *file) | ||
| 700 | { | ||
| 701 | return seq_open(file, &netlbladdr_seq_ops); | ||
| 702 | } | ||
| 703 | |||
| 704 | /** | ||
| 705 | * smk_write_netlbladdr - write() for /smack/netlabel | ||
| 706 | * @filp: file pointer, not actually used | ||
| 707 | * @buf: where to get the data from | ||
| 708 | * @count: bytes sent | ||
| 709 | * @ppos: where to start | ||
| 710 | * | ||
| 711 | * Accepts only one netlbladdr per write call. | ||
| 712 | * Returns number of bytes written or error code, as appropriate | ||
| 713 | */ | ||
| 714 | static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | ||
| 715 | size_t count, loff_t *ppos) | ||
| 716 | { | ||
| 717 | struct smk_netlbladdr *skp; | ||
| 718 | struct sockaddr_in newname; | ||
| 719 | char smack[SMK_LABELLEN]; | ||
| 720 | char *sp; | ||
| 721 | char data[SMK_NETLBLADDRMAX]; | ||
| 722 | char *host = (char *)&newname.sin_addr.s_addr; | ||
| 723 | int rc; | ||
| 724 | struct netlbl_audit audit_info; | ||
| 725 | struct in_addr mask; | ||
| 726 | unsigned int m; | ||
| 727 | __be32 bebits = BEMASK; | ||
| 728 | __be32 nsa; | ||
| 729 | |||
| 730 | /* | ||
| 731 | * Must have privilege. | ||
| 732 | * No partial writes. | ||
| 733 | * Enough data must be present. | ||
| 734 | * "<addr/mask, as a.b.c.d/e><space><label>" | ||
| 735 | * "<addr, as a.b.c.d><space><label>" | ||
| 736 | */ | ||
| 737 | if (!capable(CAP_MAC_ADMIN)) | ||
| 738 | return -EPERM; | ||
| 739 | if (*ppos != 0) | ||
| 740 | return -EINVAL; | ||
| 741 | if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX) | ||
| 742 | return -EINVAL; | ||
| 743 | if (copy_from_user(data, buf, count) != 0) | ||
| 744 | return -EFAULT; | ||
| 745 | |||
| 746 | data[count] = '\0'; | ||
| 747 | |||
| 748 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s", | ||
| 749 | &host[0], &host[1], &host[2], &host[3], &m, smack); | ||
| 750 | if (rc != 6) { | ||
| 751 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | ||
| 752 | &host[0], &host[1], &host[2], &host[3], smack); | ||
| 753 | if (rc != 5) | ||
| 754 | return -EINVAL; | ||
| 755 | m = BEBITS; | ||
| 756 | } | ||
| 757 | if (m > BEBITS) | ||
| 758 | return -EINVAL; | ||
| 759 | |||
| 760 | sp = smk_import(smack, 0); | ||
| 761 | if (sp == NULL) | ||
| 762 | return -EINVAL; | ||
| 763 | |||
| 764 | for (mask.s_addr = 0; m > 0; m--) { | ||
| 765 | mask.s_addr |= bebits; | ||
| 766 | bebits <<= 1; | ||
| 767 | } | ||
| 768 | /* | ||
| 769 | * Only allow one writer at a time. Writes should be | ||
| 770 | * quite rare and small in any case. | ||
| 771 | */ | ||
| 772 | mutex_lock(&smk_netlbladdr_lock); | ||
| 773 | |||
| 774 | nsa = newname.sin_addr.s_addr; | ||
| 775 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) | ||
| 776 | if (skp->smk_host.sin_addr.s_addr == nsa && | ||
| 777 | skp->smk_mask.s_addr == mask.s_addr) | ||
| 778 | break; | ||
| 779 | |||
| 780 | smk_netlabel_audit_set(&audit_info); | ||
| 781 | |||
| 782 | if (skp == NULL) { | ||
| 783 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); | ||
| 784 | if (skp == NULL) | ||
| 785 | rc = -ENOMEM; | ||
| 786 | else { | ||
| 787 | rc = 0; | ||
| 788 | skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; | ||
| 789 | skp->smk_mask.s_addr = mask.s_addr; | ||
| 790 | skp->smk_next = smack_netlbladdrs; | ||
| 791 | skp->smk_label = sp; | ||
| 792 | smack_netlbladdrs = skp; | ||
| 793 | } | ||
| 794 | } else { | ||
| 795 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | ||
| 796 | &skp->smk_host.sin_addr, &skp->smk_mask, | ||
| 797 | PF_INET, &audit_info); | ||
| 798 | skp->smk_label = sp; | ||
| 799 | } | ||
| 800 | |||
| 801 | /* | ||
| 802 | * Now tell netlabel about the single label nature of | ||
| 803 | * this host so that incoming packets get labeled. | ||
| 804 | */ | ||
| 805 | |||
| 806 | if (rc == 0) | ||
| 807 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, | ||
| 808 | &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET, | ||
| 809 | smack_to_secid(skp->smk_label), &audit_info); | ||
| 810 | |||
| 811 | if (rc == 0) | ||
| 812 | rc = count; | ||
| 813 | |||
| 814 | mutex_unlock(&smk_netlbladdr_lock); | ||
| 815 | |||
| 816 | return rc; | ||
| 817 | } | ||
| 818 | |||
| 819 | static const struct file_operations smk_netlbladdr_ops = { | ||
| 820 | .open = smk_open_netlbladdr, | ||
| 821 | .read = seq_read, | ||
| 822 | .llseek = seq_lseek, | ||
| 823 | .write = smk_write_netlbladdr, | ||
| 824 | .release = seq_release, | ||
| 825 | }; | ||
| 826 | |||
| 606 | /** | 827 | /** |
| 607 | * smk_read_doi - read() for /smack/doi | 828 | * smk_read_doi - read() for /smack/doi |
| 608 | * @filp: file pointer, not actually used | 829 | * @filp: file pointer, not actually used |
| @@ -891,110 +1112,6 @@ static const struct file_operations smk_onlycap_ops = { | |||
| 891 | .write = smk_write_onlycap, | 1112 | .write = smk_write_onlycap, |
| 892 | }; | 1113 | }; |
| 893 | 1114 | ||
| 894 | struct option_names { | ||
| 895 | int o_number; | ||
| 896 | char *o_name; | ||
| 897 | char *o_alias; | ||
| 898 | }; | ||
| 899 | |||
| 900 | static struct option_names netlbl_choices[] = { | ||
| 901 | { NETLBL_NLTYPE_RIPSO, | ||
| 902 | NETLBL_NLTYPE_RIPSO_NAME, "ripso" }, | ||
| 903 | { NETLBL_NLTYPE_CIPSOV4, | ||
| 904 | NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" }, | ||
| 905 | { NETLBL_NLTYPE_CIPSOV4, | ||
| 906 | NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" }, | ||
| 907 | { NETLBL_NLTYPE_CIPSOV6, | ||
| 908 | NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" }, | ||
| 909 | { NETLBL_NLTYPE_UNLABELED, | ||
| 910 | NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" }, | ||
| 911 | }; | ||
| 912 | |||
| 913 | /** | ||
| 914 | * smk_read_nltype - read() for /smack/nltype | ||
| 915 | * @filp: file pointer, not actually used | ||
| 916 | * @buf: where to put the result | ||
| 917 | * @count: maximum to send along | ||
| 918 | * @ppos: where to start | ||
| 919 | * | ||
| 920 | * Returns number of bytes read or error code, as appropriate | ||
| 921 | */ | ||
| 922 | static ssize_t smk_read_nltype(struct file *filp, char __user *buf, | ||
| 923 | size_t count, loff_t *ppos) | ||
| 924 | { | ||
| 925 | char bound[40]; | ||
| 926 | ssize_t rc; | ||
| 927 | int i; | ||
| 928 | |||
| 929 | if (count < SMK_LABELLEN) | ||
| 930 | return -EINVAL; | ||
| 931 | |||
| 932 | if (*ppos != 0) | ||
| 933 | return 0; | ||
| 934 | |||
| 935 | sprintf(bound, "unknown"); | ||
| 936 | |||
| 937 | for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++) | ||
| 938 | if (smack_net_nltype == netlbl_choices[i].o_number) { | ||
| 939 | sprintf(bound, "%s", netlbl_choices[i].o_name); | ||
| 940 | break; | ||
| 941 | } | ||
| 942 | |||
| 943 | rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound)); | ||
| 944 | |||
| 945 | return rc; | ||
| 946 | } | ||
| 947 | |||
| 948 | /** | ||
| 949 | * smk_write_nltype - write() for /smack/nltype | ||
| 950 | * @filp: file pointer, not actually used | ||
| 951 | * @buf: where to get the data from | ||
| 952 | * @count: bytes sent | ||
| 953 | * @ppos: where to start | ||
| 954 | * | ||
| 955 | * Returns number of bytes written or error code, as appropriate | ||
| 956 | */ | ||
| 957 | static ssize_t smk_write_nltype(struct file *file, const char __user *buf, | ||
| 958 | size_t count, loff_t *ppos) | ||
| 959 | { | ||
| 960 | char bound[40]; | ||
| 961 | char *cp; | ||
| 962 | int i; | ||
| 963 | |||
| 964 | if (!capable(CAP_MAC_ADMIN)) | ||
| 965 | return -EPERM; | ||
| 966 | |||
| 967 | if (count >= 40) | ||
| 968 | return -EINVAL; | ||
| 969 | |||
| 970 | if (copy_from_user(bound, buf, count) != 0) | ||
| 971 | return -EFAULT; | ||
| 972 | |||
| 973 | bound[count] = '\0'; | ||
| 974 | cp = strchr(bound, ' '); | ||
| 975 | if (cp != NULL) | ||
| 976 | *cp = '\0'; | ||
| 977 | cp = strchr(bound, '\n'); | ||
| 978 | if (cp != NULL) | ||
| 979 | *cp = '\0'; | ||
| 980 | |||
| 981 | for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++) | ||
| 982 | if (strcmp(bound, netlbl_choices[i].o_name) == 0 || | ||
| 983 | strcmp(bound, netlbl_choices[i].o_alias) == 0) { | ||
| 984 | smack_net_nltype = netlbl_choices[i].o_number; | ||
| 985 | return count; | ||
| 986 | } | ||
| 987 | /* | ||
| 988 | * Not a valid choice. | ||
| 989 | */ | ||
| 990 | return -EINVAL; | ||
| 991 | } | ||
| 992 | |||
| 993 | static const struct file_operations smk_nltype_ops = { | ||
| 994 | .read = smk_read_nltype, | ||
| 995 | .write = smk_write_nltype, | ||
| 996 | }; | ||
| 997 | |||
| 998 | /** | 1115 | /** |
| 999 | * smk_fill_super - fill the /smackfs superblock | 1116 | * smk_fill_super - fill the /smackfs superblock |
| 1000 | * @sb: the empty superblock | 1117 | * @sb: the empty superblock |
| @@ -1021,8 +1138,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1021 | {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, | 1138 | {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, |
| 1022 | [SMK_AMBIENT] = | 1139 | [SMK_AMBIENT] = |
| 1023 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 1140 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
| 1024 | [SMK_NLTYPE] = | 1141 | [SMK_NETLBLADDR] = |
| 1025 | {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, | 1142 | {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, |
| 1026 | [SMK_ONLYCAP] = | 1143 | [SMK_ONLYCAP] = |
| 1027 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | 1144 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, |
| 1028 | /* last one */ {""} | 1145 | /* last one */ {""} |
