diff options
| author | Chris Zankel <chris@zankel.net> | 2014-02-24 03:34:36 -0500 |
|---|---|---|
| committer | Chris Zankel <chris@zankel.net> | 2014-02-24 03:34:36 -0500 |
| commit | b3fdfc1b4b641d372e35ced98814289bc60bc5d1 (patch) | |
| tree | 5f11d5ba885031dde45690745646519fb887f447 /security | |
| parent | c0e50d41126e4786d9cf1105bdf783e55c99f915 (diff) | |
| parent | f63b6d7555cd4064554b39da4d44c4cbbc9d6a4a (diff) | |
Merge tag 'xtensa-for-next-20140221-1' into for_next
Xtensa fixes for 3.14:
- allow booting xtfpga on boards with new uBoot and >128MBytes memory;
- drop nonexistent GPIO32 support from fsf variant;
- don't select USE_GENERIC_SMP_HELPERS;
- enable common clock framework support, set up ethoc clock on xtfpga;
- wire up sched_setattr and sched_getattr syscalls.
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'security')
| -rw-r--r-- | security/Kconfig | 2 | ||||
| -rw-r--r-- | security/device_cgroup.c | 7 | ||||
| -rw-r--r-- | security/integrity/ima/ima_template_lib.c | 18 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 27 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 5 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 3 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 31 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 2 | ||||
| -rw-r--r-- | security/selinux/ss/constraint.h | 1 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 110 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 11 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 70 | ||||
| -rw-r--r-- | security/smack/smack.h | 5 | ||||
| -rw-r--r-- | security/smack/smack_lsm.c | 145 | ||||
| -rw-r--r-- | security/smack/smackfs.c | 134 |
15 files changed, 404 insertions, 167 deletions
diff --git a/security/Kconfig b/security/Kconfig index e9c6ac724fef..beb86b500adf 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
| @@ -103,7 +103,7 @@ config INTEL_TXT | |||
| 103 | config LSM_MMAP_MIN_ADDR | 103 | config LSM_MMAP_MIN_ADDR |
| 104 | int "Low address space for LSM to protect from user allocation" | 104 | int "Low address space for LSM to protect from user allocation" |
| 105 | depends on SECURITY && SECURITY_SELINUX | 105 | depends on SECURITY && SECURITY_SELINUX |
| 106 | default 32768 if ARM | 106 | default 32768 if ARM || (ARM64 && COMPAT) |
| 107 | default 65536 | 107 | default 65536 |
| 108 | help | 108 | help |
| 109 | This is the portion of low virtual memory which should be protected | 109 | This is the portion of low virtual memory which should be protected |
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 7c2a0a71049e..d3b6d2cd3a06 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
| @@ -274,10 +274,9 @@ static void set_majmin(char *str, unsigned m) | |||
| 274 | sprintf(str, "%u", m); | 274 | sprintf(str, "%u", m); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | static int devcgroup_seq_read(struct cgroup_subsys_state *css, | 277 | static int devcgroup_seq_show(struct seq_file *m, void *v) |
| 278 | struct cftype *cft, struct seq_file *m) | ||
| 279 | { | 278 | { |
| 280 | struct dev_cgroup *devcgroup = css_to_devcgroup(css); | 279 | struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m)); |
| 281 | struct dev_exception_item *ex; | 280 | struct dev_exception_item *ex; |
| 282 | char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; | 281 | char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; |
| 283 | 282 | ||
| @@ -679,7 +678,7 @@ static struct cftype dev_cgroup_files[] = { | |||
| 679 | }, | 678 | }, |
| 680 | { | 679 | { |
| 681 | .name = "list", | 680 | .name = "list", |
| 682 | .read_seq_string = devcgroup_seq_read, | 681 | .seq_show = devcgroup_seq_show, |
| 683 | .private = DEVCG_LIST, | 682 | .private = DEVCG_LIST, |
| 684 | }, | 683 | }, |
| 685 | { } /* terminate */ | 684 | { } /* terminate */ |
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index c38adcc910fb..1683bbf289a4 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c | |||
| @@ -162,8 +162,7 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, | |||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, | 164 | static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, |
| 165 | struct ima_field_data *field_data, | 165 | struct ima_field_data *field_data) |
| 166 | bool size_limit) | ||
| 167 | { | 166 | { |
| 168 | /* | 167 | /* |
| 169 | * digest formats: | 168 | * digest formats: |
| @@ -176,11 +175,10 @@ static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, | |||
| 176 | enum data_formats fmt = DATA_FMT_DIGEST; | 175 | enum data_formats fmt = DATA_FMT_DIGEST; |
| 177 | u32 offset = 0; | 176 | u32 offset = 0; |
| 178 | 177 | ||
| 179 | if (!size_limit) { | 178 | if (hash_algo < HASH_ALGO__LAST) { |
| 180 | fmt = DATA_FMT_DIGEST_WITH_ALGO; | 179 | fmt = DATA_FMT_DIGEST_WITH_ALGO; |
| 181 | if (hash_algo < HASH_ALGO__LAST) | 180 | offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s", |
| 182 | offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, | 181 | hash_algo_name[hash_algo]); |
| 183 | "%s", hash_algo_name[hash_algo]); | ||
| 184 | buffer[offset] = ':'; | 182 | buffer[offset] = ':'; |
| 185 | offset += 2; | 183 | offset += 2; |
| 186 | } | 184 | } |
| @@ -243,8 +241,8 @@ int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file, | |||
| 243 | cur_digest = hash.hdr.digest; | 241 | cur_digest = hash.hdr.digest; |
| 244 | cur_digestsize = hash.hdr.length; | 242 | cur_digestsize = hash.hdr.length; |
| 245 | out: | 243 | out: |
| 246 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1, | 244 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, |
| 247 | field_data, true); | 245 | HASH_ALGO__LAST, field_data); |
| 248 | } | 246 | } |
| 249 | 247 | ||
| 250 | /* | 248 | /* |
| @@ -255,7 +253,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, | |||
| 255 | struct evm_ima_xattr_data *xattr_value, | 253 | struct evm_ima_xattr_data *xattr_value, |
| 256 | int xattr_len, struct ima_field_data *field_data) | 254 | int xattr_len, struct ima_field_data *field_data) |
| 257 | { | 255 | { |
| 258 | u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST; | 256 | u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1; |
| 259 | u32 cur_digestsize = 0; | 257 | u32 cur_digestsize = 0; |
| 260 | 258 | ||
| 261 | /* If iint is NULL, we are recording a violation. */ | 259 | /* If iint is NULL, we are recording a violation. */ |
| @@ -268,7 +266,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, | |||
| 268 | hash_algo = iint->ima_hash->algo; | 266 | hash_algo = iint->ima_hash->algo; |
| 269 | out: | 267 | out: |
| 270 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, | 268 | return ima_eventdigest_init_common(cur_digest, cur_digestsize, |
| 271 | hash_algo, field_data, false); | 269 | hash_algo, field_data); |
| 272 | } | 270 | } |
| 273 | 271 | ||
| 274 | static int ima_eventname_init_common(struct integrity_iint_cache *iint, | 272 | static int ima_eventname_init_common(struct integrity_iint_cache *iint, |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6625699f497c..4b34847208cc 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -82,7 +82,6 @@ | |||
| 82 | #include <linux/syslog.h> | 82 | #include <linux/syslog.h> |
| 83 | #include <linux/user_namespace.h> | 83 | #include <linux/user_namespace.h> |
| 84 | #include <linux/export.h> | 84 | #include <linux/export.h> |
| 85 | #include <linux/security.h> | ||
| 86 | #include <linux/msg.h> | 85 | #include <linux/msg.h> |
| 87 | #include <linux/shm.h> | 86 | #include <linux/shm.h> |
| 88 | 87 | ||
| @@ -234,6 +233,14 @@ static int inode_alloc_security(struct inode *inode) | |||
| 234 | return 0; | 233 | return 0; |
| 235 | } | 234 | } |
| 236 | 235 | ||
| 236 | static void inode_free_rcu(struct rcu_head *head) | ||
| 237 | { | ||
| 238 | struct inode_security_struct *isec; | ||
| 239 | |||
| 240 | isec = container_of(head, struct inode_security_struct, rcu); | ||
| 241 | kmem_cache_free(sel_inode_cache, isec); | ||
| 242 | } | ||
| 243 | |||
| 237 | static void inode_free_security(struct inode *inode) | 244 | static void inode_free_security(struct inode *inode) |
| 238 | { | 245 | { |
| 239 | struct inode_security_struct *isec = inode->i_security; | 246 | struct inode_security_struct *isec = inode->i_security; |
| @@ -244,8 +251,16 @@ static void inode_free_security(struct inode *inode) | |||
| 244 | list_del_init(&isec->list); | 251 | list_del_init(&isec->list); |
| 245 | spin_unlock(&sbsec->isec_lock); | 252 | spin_unlock(&sbsec->isec_lock); |
| 246 | 253 | ||
| 247 | inode->i_security = NULL; | 254 | /* |
| 248 | kmem_cache_free(sel_inode_cache, isec); | 255 | * The inode may still be referenced in a path walk and |
| 256 | * a call to selinux_inode_permission() can be made | ||
| 257 | * after inode_free_security() is called. Ideally, the VFS | ||
| 258 | * wouldn't do this, but fixing that is a much harder | ||
| 259 | * job. For now, simply free the i_security via RCU, and | ||
| 260 | * leave the current inode->i_security pointer intact. | ||
| 261 | * The inode will be freed after the RCU grace period too. | ||
| 262 | */ | ||
| 263 | call_rcu(&isec->rcu, inode_free_rcu); | ||
| 249 | } | 264 | } |
| 250 | 265 | ||
| 251 | static int file_alloc_security(struct file *file) | 266 | static int file_alloc_security(struct file *file) |
| @@ -4474,14 +4489,10 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4474 | { | 4489 | { |
| 4475 | struct sk_security_struct *sksec = sk->sk_security; | 4490 | struct sk_security_struct *sksec = sk->sk_security; |
| 4476 | int err; | 4491 | int err; |
| 4477 | u16 family = sk->sk_family; | 4492 | u16 family = req->rsk_ops->family; |
| 4478 | u32 connsid; | 4493 | u32 connsid; |
| 4479 | u32 peersid; | 4494 | u32 peersid; |
| 4480 | 4495 | ||
| 4481 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ | ||
| 4482 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
| 4483 | family = PF_INET; | ||
| 4484 | |||
| 4485 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | 4496 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); |
| 4486 | if (err) | 4497 | if (err) |
| 4487 | return err; | 4498 | return err; |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index b1dfe1049450..078e553f52f2 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -38,7 +38,10 @@ struct task_security_struct { | |||
| 38 | 38 | ||
| 39 | struct inode_security_struct { | 39 | struct inode_security_struct { |
| 40 | struct inode *inode; /* back pointer to inode object */ | 40 | struct inode *inode; /* back pointer to inode object */ |
| 41 | struct list_head list; /* list of inode_security_struct */ | 41 | union { |
| 42 | struct list_head list; /* list of inode_security_struct */ | ||
| 43 | struct rcu_head rcu; /* for freeing the inode_security_struct */ | ||
| 44 | }; | ||
| 42 | u32 task_sid; /* SID of creating task */ | 45 | u32 task_sid; /* SID of creating task */ |
| 43 | u32 sid; /* SID of this object */ | 46 | u32 sid; /* SID of this object */ |
| 44 | u16 sclass; /* security class of this object */ | 47 | u16 sclass; /* security class of this object */ |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index fe341ae37004..8ed8daf7f1ee 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -33,13 +33,14 @@ | |||
| 33 | #define POLICYDB_VERSION_ROLETRANS 26 | 33 | #define POLICYDB_VERSION_ROLETRANS 26 |
| 34 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 | 34 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 |
| 35 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | 35 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 |
| 36 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 | ||
| 36 | 37 | ||
| 37 | /* Range of policy versions we understand*/ | 38 | /* Range of policy versions we understand*/ |
| 38 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 39 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
| 39 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 40 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
| 40 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 41 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
| 41 | #else | 42 | #else |
| 42 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE | 43 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES |
| 43 | #endif | 44 | #endif |
| 44 | 45 | ||
| 45 | /* Mask for just the mount related flags */ | 46 | /* Mask for just the mount related flags */ |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 6235d052338b..0364120d1ec8 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -101,6 +101,32 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) | |||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr | ||
| 105 | * @sk: the socket | ||
| 106 | * @sid: the SID | ||
| 107 | * | ||
| 108 | * Query the socket's cached secattr and if the SID matches the cached value | ||
| 109 | * return the cache, otherwise return NULL. | ||
| 110 | * | ||
| 111 | */ | ||
| 112 | static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr( | ||
| 113 | const struct sock *sk, | ||
| 114 | u32 sid) | ||
| 115 | { | ||
| 116 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 117 | struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr; | ||
| 118 | |||
| 119 | if (secattr == NULL) | ||
| 120 | return NULL; | ||
| 121 | |||
| 122 | if ((secattr->flags & NETLBL_SECATTR_SECID) && | ||
| 123 | (secattr->attr.secid == sid)) | ||
| 124 | return secattr; | ||
| 125 | |||
| 126 | return NULL; | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 104 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache | 130 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache |
| 105 | * | 131 | * |
| 106 | * Description: | 132 | * Description: |
| @@ -224,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, | |||
| 224 | struct sk_security_struct *sksec = sk->sk_security; | 250 | struct sk_security_struct *sksec = sk->sk_security; |
| 225 | if (sksec->nlbl_state != NLBL_REQSKB) | 251 | if (sksec->nlbl_state != NLBL_REQSKB) |
| 226 | return 0; | 252 | return 0; |
| 227 | secattr = sksec->nlbl_secattr; | 253 | secattr = selinux_netlbl_sock_getattr(sk, sid); |
| 228 | } | 254 | } |
| 229 | if (secattr == NULL) { | 255 | if (secattr == NULL) { |
| 230 | secattr = &secattr_storage; | 256 | secattr = &secattr_storage; |
| @@ -410,6 +436,9 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, | |||
| 410 | sksec->nlbl_state == NLBL_CONNLABELED)) { | 436 | sksec->nlbl_state == NLBL_CONNLABELED)) { |
| 411 | netlbl_secattr_init(&secattr); | 437 | netlbl_secattr_init(&secattr); |
| 412 | lock_sock(sk); | 438 | lock_sock(sk); |
| 439 | /* call the netlabel function directly as we want to see the | ||
| 440 | * on-the-wire label that is assigned via the socket's options | ||
| 441 | * and not the cached netlabel/lsm attributes */ | ||
| 413 | rc = netlbl_sock_getattr(sk, &secattr); | 442 | rc = netlbl_sock_getattr(sk, &secattr); |
| 414 | release_sock(sk); | 443 | release_sock(sk); |
| 415 | if (rc == 0) | 444 | if (rc == 0) |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 332ac8a80cf5..2df7b900e259 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/inet_diag.h> | 17 | #include <linux/inet_diag.h> |
| 18 | #include <linux/xfrm.h> | 18 | #include <linux/xfrm.h> |
| 19 | #include <linux/audit.h> | 19 | #include <linux/audit.h> |
| 20 | #include <linux/sock_diag.h> | ||
| 20 | 21 | ||
| 21 | #include "flask.h" | 22 | #include "flask.h" |
| 22 | #include "av_permissions.h" | 23 | #include "av_permissions.h" |
| @@ -78,6 +79,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | |||
| 78 | { | 79 | { |
| 79 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | 80 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| 80 | { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | 81 | { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| 82 | { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | ||
| 81 | }; | 83 | }; |
| 82 | 84 | ||
| 83 | static struct nlmsg_perm nlmsg_xfrm_perms[] = | 85 | static struct nlmsg_perm nlmsg_xfrm_perms[] = |
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h index 149dda731fd3..96fd947c494b 100644 --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h | |||
| @@ -48,6 +48,7 @@ struct constraint_expr { | |||
| 48 | u32 op; /* operator */ | 48 | u32 op; /* operator */ |
| 49 | 49 | ||
| 50 | struct ebitmap names; /* names */ | 50 | struct ebitmap names; /* names */ |
| 51 | struct type_set *type_names; | ||
| 51 | 52 | ||
| 52 | struct constraint_expr *next; /* next expression */ | 53 | struct constraint_expr *next; /* next expression */ |
| 53 | }; | 54 | }; |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f6195ebde3c9..c0f498842129 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
| 143 | .sym_num = SYM_NUM, | 143 | .sym_num = SYM_NUM, |
| 144 | .ocon_num = OCON_NUM, | 144 | .ocon_num = OCON_NUM, |
| 145 | }, | 145 | }, |
| 146 | { | ||
| 147 | .version = POLICYDB_VERSION_CONSTRAINT_NAMES, | ||
| 148 | .sym_num = SYM_NUM, | ||
| 149 | .ocon_num = OCON_NUM, | ||
| 150 | }, | ||
| 146 | }; | 151 | }; |
| 147 | 152 | ||
| 148 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 153 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
| @@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p) | |||
| 613 | return 0; | 618 | return 0; |
| 614 | } | 619 | } |
| 615 | 620 | ||
| 621 | static void constraint_expr_destroy(struct constraint_expr *expr) | ||
| 622 | { | ||
| 623 | if (expr) { | ||
| 624 | ebitmap_destroy(&expr->names); | ||
| 625 | if (expr->type_names) { | ||
| 626 | ebitmap_destroy(&expr->type_names->types); | ||
| 627 | ebitmap_destroy(&expr->type_names->negset); | ||
| 628 | kfree(expr->type_names); | ||
| 629 | } | ||
| 630 | kfree(expr); | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 616 | static int cls_destroy(void *key, void *datum, void *p) | 634 | static int cls_destroy(void *key, void *datum, void *p) |
| 617 | { | 635 | { |
| 618 | struct class_datum *cladatum; | 636 | struct class_datum *cladatum; |
| @@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p) | |||
| 628 | while (constraint) { | 646 | while (constraint) { |
| 629 | e = constraint->expr; | 647 | e = constraint->expr; |
| 630 | while (e) { | 648 | while (e) { |
| 631 | ebitmap_destroy(&e->names); | ||
| 632 | etmp = e; | 649 | etmp = e; |
| 633 | e = e->next; | 650 | e = e->next; |
| 634 | kfree(etmp); | 651 | constraint_expr_destroy(etmp); |
| 635 | } | 652 | } |
| 636 | ctemp = constraint; | 653 | ctemp = constraint; |
| 637 | constraint = constraint->next; | 654 | constraint = constraint->next; |
| @@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p) | |||
| 642 | while (constraint) { | 659 | while (constraint) { |
| 643 | e = constraint->expr; | 660 | e = constraint->expr; |
| 644 | while (e) { | 661 | while (e) { |
| 645 | ebitmap_destroy(&e->names); | ||
| 646 | etmp = e; | 662 | etmp = e; |
| 647 | e = e->next; | 663 | e = e->next; |
| 648 | kfree(etmp); | 664 | constraint_expr_destroy(etmp); |
| 649 | } | 665 | } |
| 650 | ctemp = constraint; | 666 | ctemp = constraint; |
| 651 | constraint = constraint->next; | 667 | constraint = constraint->next; |
| 652 | kfree(ctemp); | 668 | kfree(ctemp); |
| 653 | } | 669 | } |
| 654 | |||
| 655 | kfree(cladatum->comkey); | 670 | kfree(cladatum->comkey); |
| 656 | } | 671 | } |
| 657 | kfree(datum); | 672 | kfree(datum); |
| @@ -1156,8 +1171,34 @@ bad: | |||
| 1156 | return rc; | 1171 | return rc; |
| 1157 | } | 1172 | } |
| 1158 | 1173 | ||
| 1159 | static int read_cons_helper(struct constraint_node **nodep, int ncons, | 1174 | static void type_set_init(struct type_set *t) |
| 1160 | int allowxtarget, void *fp) | 1175 | { |
| 1176 | ebitmap_init(&t->types); | ||
| 1177 | ebitmap_init(&t->negset); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static int type_set_read(struct type_set *t, void *fp) | ||
| 1181 | { | ||
| 1182 | __le32 buf[1]; | ||
| 1183 | int rc; | ||
| 1184 | |||
| 1185 | if (ebitmap_read(&t->types, fp)) | ||
| 1186 | return -EINVAL; | ||
| 1187 | if (ebitmap_read(&t->negset, fp)) | ||
| 1188 | return -EINVAL; | ||
| 1189 | |||
| 1190 | rc = next_entry(buf, fp, sizeof(u32)); | ||
| 1191 | if (rc < 0) | ||
| 1192 | return -EINVAL; | ||
| 1193 | t->flags = le32_to_cpu(buf[0]); | ||
| 1194 | |||
| 1195 | return 0; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | |||
| 1199 | static int read_cons_helper(struct policydb *p, | ||
| 1200 | struct constraint_node **nodep, | ||
| 1201 | int ncons, int allowxtarget, void *fp) | ||
| 1161 | { | 1202 | { |
| 1162 | struct constraint_node *c, *lc; | 1203 | struct constraint_node *c, *lc; |
| 1163 | struct constraint_expr *e, *le; | 1204 | struct constraint_expr *e, *le; |
| @@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, | |||
| 1225 | rc = ebitmap_read(&e->names, fp); | 1266 | rc = ebitmap_read(&e->names, fp); |
| 1226 | if (rc) | 1267 | if (rc) |
| 1227 | return rc; | 1268 | return rc; |
| 1269 | if (p->policyvers >= | ||
| 1270 | POLICYDB_VERSION_CONSTRAINT_NAMES) { | ||
| 1271 | e->type_names = kzalloc(sizeof | ||
| 1272 | (*e->type_names), | ||
| 1273 | GFP_KERNEL); | ||
| 1274 | if (!e->type_names) | ||
| 1275 | return -ENOMEM; | ||
| 1276 | type_set_init(e->type_names); | ||
| 1277 | rc = type_set_read(e->type_names, fp); | ||
| 1278 | if (rc) | ||
| 1279 | return rc; | ||
| 1280 | } | ||
| 1228 | break; | 1281 | break; |
| 1229 | default: | 1282 | default: |
| 1230 | return -EINVAL; | 1283 | return -EINVAL; |
| @@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1301 | goto bad; | 1354 | goto bad; |
| 1302 | } | 1355 | } |
| 1303 | 1356 | ||
| 1304 | rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); | 1357 | rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp); |
| 1305 | if (rc) | 1358 | if (rc) |
| 1306 | goto bad; | 1359 | goto bad; |
| 1307 | 1360 | ||
| @@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1311 | if (rc) | 1364 | if (rc) |
| 1312 | goto bad; | 1365 | goto bad; |
| 1313 | ncons = le32_to_cpu(buf[0]); | 1366 | ncons = le32_to_cpu(buf[0]); |
| 1314 | rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); | 1367 | rc = read_cons_helper(p, &cladatum->validatetrans, |
| 1368 | ncons, 1, fp); | ||
| 1315 | if (rc) | 1369 | if (rc) |
| 1316 | goto bad; | 1370 | goto bad; |
| 1317 | } | 1371 | } |
| @@ -1941,7 +1995,19 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
| 1941 | if (rc) | 1995 | if (rc) |
| 1942 | goto out; | 1996 | goto out; |
| 1943 | 1997 | ||
| 1944 | hashtab_insert(p->filename_trans, ft, otype); | 1998 | rc = hashtab_insert(p->filename_trans, ft, otype); |
| 1999 | if (rc) { | ||
| 2000 | /* | ||
| 2001 | * Do not return -EEXIST to the caller, or the system | ||
| 2002 | * will not boot. | ||
| 2003 | */ | ||
| 2004 | if (rc != -EEXIST) | ||
| 2005 | goto out; | ||
| 2006 | /* But free memory to avoid memory leak. */ | ||
| 2007 | kfree(ft); | ||
| 2008 | kfree(name); | ||
| 2009 | kfree(otype); | ||
| 2010 | } | ||
| 1945 | } | 2011 | } |
| 1946 | hash_eval(p->filename_trans, "filenametr"); | 2012 | hash_eval(p->filename_trans, "filenametr"); |
| 1947 | return 0; | 2013 | return 0; |
| @@ -2753,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr) | |||
| 2753 | return 0; | 2819 | return 0; |
| 2754 | } | 2820 | } |
| 2755 | 2821 | ||
| 2822 | static int type_set_write(struct type_set *t, void *fp) | ||
| 2823 | { | ||
| 2824 | int rc; | ||
| 2825 | __le32 buf[1]; | ||
| 2826 | |||
| 2827 | if (ebitmap_write(&t->types, fp)) | ||
| 2828 | return -EINVAL; | ||
| 2829 | if (ebitmap_write(&t->negset, fp)) | ||
| 2830 | return -EINVAL; | ||
| 2831 | |||
| 2832 | buf[0] = cpu_to_le32(t->flags); | ||
| 2833 | rc = put_entry(buf, sizeof(u32), 1, fp); | ||
| 2834 | if (rc) | ||
| 2835 | return -EINVAL; | ||
| 2836 | |||
| 2837 | return 0; | ||
| 2838 | } | ||
| 2839 | |||
| 2756 | static int write_cons_helper(struct policydb *p, struct constraint_node *node, | 2840 | static int write_cons_helper(struct policydb *p, struct constraint_node *node, |
| 2757 | void *fp) | 2841 | void *fp) |
| 2758 | { | 2842 | { |
| @@ -2784,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node, | |||
| 2784 | rc = ebitmap_write(&e->names, fp); | 2868 | rc = ebitmap_write(&e->names, fp); |
| 2785 | if (rc) | 2869 | if (rc) |
| 2786 | return rc; | 2870 | return rc; |
| 2871 | if (p->policyvers >= | ||
| 2872 | POLICYDB_VERSION_CONSTRAINT_NAMES) { | ||
| 2873 | rc = type_set_write(e->type_names, fp); | ||
| 2874 | if (rc) | ||
| 2875 | return rc; | ||
| 2876 | } | ||
| 2787 | break; | 2877 | break; |
| 2788 | default: | 2878 | default: |
| 2789 | break; | 2879 | break; |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index da637471d4ce..725d5945a97e 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
| @@ -154,6 +154,17 @@ struct cond_bool_datum { | |||
| 154 | struct cond_node; | 154 | struct cond_node; |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * type set preserves data needed to determine constraint info from | ||
| 158 | * policy source. This is not used by the kernel policy but allows | ||
| 159 | * utilities such as audit2allow to determine constraint denials. | ||
| 160 | */ | ||
| 161 | struct type_set { | ||
| 162 | struct ebitmap types; | ||
| 163 | struct ebitmap negset; | ||
| 164 | u32 flags; | ||
| 165 | }; | ||
| 166 | |||
| 167 | /* | ||
| 157 | * The configuration data includes security contexts for | 168 | * The configuration data includes security contexts for |
| 158 | * initial SIDs, unlabeled file systems, TCP and UDP port numbers, | 169 | * initial SIDs, unlabeled file systems, TCP and UDP port numbers, |
| 159 | * network interfaces, and nodes. This structure stores the | 170 | * network interfaces, and nodes. This structure stores the |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d106733ad987..5d0144ee8ed6 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -1232,6 +1232,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
| 1232 | struct context context; | 1232 | struct context context; |
| 1233 | int rc = 0; | 1233 | int rc = 0; |
| 1234 | 1234 | ||
| 1235 | /* An empty security context is never valid. */ | ||
| 1236 | if (!scontext_len) | ||
| 1237 | return -EINVAL; | ||
| 1238 | |||
| 1235 | if (!ss_initialized) { | 1239 | if (!ss_initialized) { |
| 1236 | int i; | 1240 | int i; |
| 1237 | 1241 | ||
| @@ -1831,7 +1835,7 @@ static int security_preserve_bools(struct policydb *p); | |||
| 1831 | */ | 1835 | */ |
| 1832 | int security_load_policy(void *data, size_t len) | 1836 | int security_load_policy(void *data, size_t len) |
| 1833 | { | 1837 | { |
| 1834 | struct policydb oldpolicydb, newpolicydb; | 1838 | struct policydb *oldpolicydb, *newpolicydb; |
| 1835 | struct sidtab oldsidtab, newsidtab; | 1839 | struct sidtab oldsidtab, newsidtab; |
| 1836 | struct selinux_mapping *oldmap, *map = NULL; | 1840 | struct selinux_mapping *oldmap, *map = NULL; |
| 1837 | struct convert_context_args args; | 1841 | struct convert_context_args args; |
| @@ -1840,12 +1844,19 @@ int security_load_policy(void *data, size_t len) | |||
| 1840 | int rc = 0; | 1844 | int rc = 0; |
| 1841 | struct policy_file file = { data, len }, *fp = &file; | 1845 | struct policy_file file = { data, len }, *fp = &file; |
| 1842 | 1846 | ||
| 1847 | oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); | ||
| 1848 | if (!oldpolicydb) { | ||
| 1849 | rc = -ENOMEM; | ||
| 1850 | goto out; | ||
| 1851 | } | ||
| 1852 | newpolicydb = oldpolicydb + 1; | ||
| 1853 | |||
| 1843 | if (!ss_initialized) { | 1854 | if (!ss_initialized) { |
| 1844 | avtab_cache_init(); | 1855 | avtab_cache_init(); |
| 1845 | rc = policydb_read(&policydb, fp); | 1856 | rc = policydb_read(&policydb, fp); |
| 1846 | if (rc) { | 1857 | if (rc) { |
| 1847 | avtab_cache_destroy(); | 1858 | avtab_cache_destroy(); |
| 1848 | return rc; | 1859 | goto out; |
| 1849 | } | 1860 | } |
| 1850 | 1861 | ||
| 1851 | policydb.len = len; | 1862 | policydb.len = len; |
| @@ -1855,14 +1866,14 @@ int security_load_policy(void *data, size_t len) | |||
| 1855 | if (rc) { | 1866 | if (rc) { |
| 1856 | policydb_destroy(&policydb); | 1867 | policydb_destroy(&policydb); |
| 1857 | avtab_cache_destroy(); | 1868 | avtab_cache_destroy(); |
| 1858 | return rc; | 1869 | goto out; |
| 1859 | } | 1870 | } |
| 1860 | 1871 | ||
| 1861 | rc = policydb_load_isids(&policydb, &sidtab); | 1872 | rc = policydb_load_isids(&policydb, &sidtab); |
| 1862 | if (rc) { | 1873 | if (rc) { |
| 1863 | policydb_destroy(&policydb); | 1874 | policydb_destroy(&policydb); |
| 1864 | avtab_cache_destroy(); | 1875 | avtab_cache_destroy(); |
| 1865 | return rc; | 1876 | goto out; |
| 1866 | } | 1877 | } |
| 1867 | 1878 | ||
| 1868 | security_load_policycaps(); | 1879 | security_load_policycaps(); |
| @@ -1874,36 +1885,36 @@ int security_load_policy(void *data, size_t len) | |||
| 1874 | selinux_status_update_policyload(seqno); | 1885 | selinux_status_update_policyload(seqno); |
| 1875 | selinux_netlbl_cache_invalidate(); | 1886 | selinux_netlbl_cache_invalidate(); |
| 1876 | selinux_xfrm_notify_policyload(); | 1887 | selinux_xfrm_notify_policyload(); |
| 1877 | return 0; | 1888 | goto out; |
| 1878 | } | 1889 | } |
| 1879 | 1890 | ||
| 1880 | #if 0 | 1891 | #if 0 |
| 1881 | sidtab_hash_eval(&sidtab, "sids"); | 1892 | sidtab_hash_eval(&sidtab, "sids"); |
| 1882 | #endif | 1893 | #endif |
| 1883 | 1894 | ||
| 1884 | rc = policydb_read(&newpolicydb, fp); | 1895 | rc = policydb_read(newpolicydb, fp); |
| 1885 | if (rc) | 1896 | if (rc) |
| 1886 | return rc; | 1897 | goto out; |
| 1887 | 1898 | ||
| 1888 | newpolicydb.len = len; | 1899 | newpolicydb->len = len; |
| 1889 | /* If switching between different policy types, log MLS status */ | 1900 | /* If switching between different policy types, log MLS status */ |
| 1890 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1901 | if (policydb.mls_enabled && !newpolicydb->mls_enabled) |
| 1891 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | 1902 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); |
| 1892 | else if (!policydb.mls_enabled && newpolicydb.mls_enabled) | 1903 | else if (!policydb.mls_enabled && newpolicydb->mls_enabled) |
| 1893 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); | 1904 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); |
| 1894 | 1905 | ||
| 1895 | rc = policydb_load_isids(&newpolicydb, &newsidtab); | 1906 | rc = policydb_load_isids(newpolicydb, &newsidtab); |
| 1896 | if (rc) { | 1907 | if (rc) { |
| 1897 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); | 1908 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); |
| 1898 | policydb_destroy(&newpolicydb); | 1909 | policydb_destroy(newpolicydb); |
| 1899 | return rc; | 1910 | goto out; |
| 1900 | } | 1911 | } |
| 1901 | 1912 | ||
| 1902 | rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); | 1913 | rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); |
| 1903 | if (rc) | 1914 | if (rc) |
| 1904 | goto err; | 1915 | goto err; |
| 1905 | 1916 | ||
| 1906 | rc = security_preserve_bools(&newpolicydb); | 1917 | rc = security_preserve_bools(newpolicydb); |
| 1907 | if (rc) { | 1918 | if (rc) { |
| 1908 | printk(KERN_ERR "SELinux: unable to preserve booleans\n"); | 1919 | printk(KERN_ERR "SELinux: unable to preserve booleans\n"); |
| 1909 | goto err; | 1920 | goto err; |
| @@ -1921,7 +1932,7 @@ int security_load_policy(void *data, size_t len) | |||
| 1921 | * in the new SID table. | 1932 | * in the new SID table. |
| 1922 | */ | 1933 | */ |
| 1923 | args.oldp = &policydb; | 1934 | args.oldp = &policydb; |
| 1924 | args.newp = &newpolicydb; | 1935 | args.newp = newpolicydb; |
| 1925 | rc = sidtab_map(&newsidtab, convert_context, &args); | 1936 | rc = sidtab_map(&newsidtab, convert_context, &args); |
| 1926 | if (rc) { | 1937 | if (rc) { |
| 1927 | printk(KERN_ERR "SELinux: unable to convert the internal" | 1938 | printk(KERN_ERR "SELinux: unable to convert the internal" |
| @@ -1931,12 +1942,12 @@ int security_load_policy(void *data, size_t len) | |||
| 1931 | } | 1942 | } |
| 1932 | 1943 | ||
| 1933 | /* Save the old policydb and SID table to free later. */ | 1944 | /* Save the old policydb and SID table to free later. */ |
| 1934 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1945 | memcpy(oldpolicydb, &policydb, sizeof(policydb)); |
| 1935 | sidtab_set(&oldsidtab, &sidtab); | 1946 | sidtab_set(&oldsidtab, &sidtab); |
| 1936 | 1947 | ||
| 1937 | /* Install the new policydb and SID table. */ | 1948 | /* Install the new policydb and SID table. */ |
| 1938 | write_lock_irq(&policy_rwlock); | 1949 | write_lock_irq(&policy_rwlock); |
| 1939 | memcpy(&policydb, &newpolicydb, sizeof policydb); | 1950 | memcpy(&policydb, newpolicydb, sizeof(policydb)); |
| 1940 | sidtab_set(&sidtab, &newsidtab); | 1951 | sidtab_set(&sidtab, &newsidtab); |
| 1941 | security_load_policycaps(); | 1952 | security_load_policycaps(); |
| 1942 | oldmap = current_mapping; | 1953 | oldmap = current_mapping; |
| @@ -1946,7 +1957,7 @@ int security_load_policy(void *data, size_t len) | |||
| 1946 | write_unlock_irq(&policy_rwlock); | 1957 | write_unlock_irq(&policy_rwlock); |
| 1947 | 1958 | ||
| 1948 | /* Free the old policydb and SID table. */ | 1959 | /* Free the old policydb and SID table. */ |
| 1949 | policydb_destroy(&oldpolicydb); | 1960 | policydb_destroy(oldpolicydb); |
| 1950 | sidtab_destroy(&oldsidtab); | 1961 | sidtab_destroy(&oldsidtab); |
| 1951 | kfree(oldmap); | 1962 | kfree(oldmap); |
| 1952 | 1963 | ||
| @@ -1956,14 +1967,17 @@ int security_load_policy(void *data, size_t len) | |||
| 1956 | selinux_netlbl_cache_invalidate(); | 1967 | selinux_netlbl_cache_invalidate(); |
| 1957 | selinux_xfrm_notify_policyload(); | 1968 | selinux_xfrm_notify_policyload(); |
| 1958 | 1969 | ||
| 1959 | return 0; | 1970 | rc = 0; |
| 1971 | goto out; | ||
| 1960 | 1972 | ||
| 1961 | err: | 1973 | err: |
| 1962 | kfree(map); | 1974 | kfree(map); |
| 1963 | sidtab_destroy(&newsidtab); | 1975 | sidtab_destroy(&newsidtab); |
| 1964 | policydb_destroy(&newpolicydb); | 1976 | policydb_destroy(newpolicydb); |
| 1965 | return rc; | ||
| 1966 | 1977 | ||
| 1978 | out: | ||
| 1979 | kfree(oldpolicydb); | ||
| 1980 | return rc; | ||
| 1967 | } | 1981 | } |
| 1968 | 1982 | ||
| 1969 | size_t security_policydb_len(void) | 1983 | size_t security_policydb_len(void) |
| @@ -2938,25 +2952,21 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | |||
| 2938 | struct selinux_audit_rule *rule = vrule; | 2952 | struct selinux_audit_rule *rule = vrule; |
| 2939 | int match = 0; | 2953 | int match = 0; |
| 2940 | 2954 | ||
| 2941 | if (!rule) { | 2955 | if (unlikely(!rule)) { |
| 2942 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 2956 | WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); |
| 2943 | "selinux_audit_rule_match: missing rule\n"); | ||
| 2944 | return -ENOENT; | 2957 | return -ENOENT; |
| 2945 | } | 2958 | } |
| 2946 | 2959 | ||
| 2947 | read_lock(&policy_rwlock); | 2960 | read_lock(&policy_rwlock); |
| 2948 | 2961 | ||
| 2949 | if (rule->au_seqno < latest_granting) { | 2962 | if (rule->au_seqno < latest_granting) { |
| 2950 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
| 2951 | "selinux_audit_rule_match: stale rule\n"); | ||
| 2952 | match = -ESTALE; | 2963 | match = -ESTALE; |
| 2953 | goto out; | 2964 | goto out; |
| 2954 | } | 2965 | } |
| 2955 | 2966 | ||
| 2956 | ctxt = sidtab_search(&sidtab, sid); | 2967 | ctxt = sidtab_search(&sidtab, sid); |
| 2957 | if (!ctxt) { | 2968 | if (unlikely(!ctxt)) { |
| 2958 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 2969 | WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", |
| 2959 | "selinux_audit_rule_match: unrecognized SID %d\n", | ||
| 2960 | sid); | 2970 | sid); |
| 2961 | match = -ENOENT; | 2971 | match = -ENOENT; |
| 2962 | goto out; | 2972 | goto out; |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 364cc64fce71..d072fd32212d 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
| @@ -241,7 +241,8 @@ u32 smack_to_secid(const char *); | |||
| 241 | extern int smack_cipso_direct; | 241 | extern int smack_cipso_direct; |
| 242 | extern int smack_cipso_mapped; | 242 | extern int smack_cipso_mapped; |
| 243 | extern struct smack_known *smack_net_ambient; | 243 | extern struct smack_known *smack_net_ambient; |
| 244 | extern char *smack_onlycap; | 244 | extern struct smack_known *smack_onlycap; |
| 245 | extern struct smack_known *smack_syslog_label; | ||
| 245 | extern const char *smack_cipso_option; | 246 | extern const char *smack_cipso_option; |
| 246 | 247 | ||
| 247 | extern struct smack_known smack_known_floor; | 248 | extern struct smack_known smack_known_floor; |
| @@ -312,7 +313,7 @@ static inline int smack_privileged(int cap) | |||
| 312 | 313 | ||
| 313 | if (!capable(cap)) | 314 | if (!capable(cap)) |
| 314 | return 0; | 315 | return 0; |
| 315 | if (smack_onlycap == NULL || smack_onlycap == skp->smk_known) | 316 | if (smack_onlycap == NULL || smack_onlycap == skp) |
| 316 | return 1; | 317 | return 1; |
| 317 | return 0; | 318 | return 0; |
| 318 | } | 319 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b0be893ad44d..14f52be78c75 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -219,8 +219,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp) | |||
| 219 | * smack_syslog - Smack approval on syslog | 219 | * smack_syslog - Smack approval on syslog |
| 220 | * @type: message type | 220 | * @type: message type |
| 221 | * | 221 | * |
| 222 | * Require that the task has the floor label | ||
| 223 | * | ||
| 224 | * Returns 0 on success, error code otherwise. | 222 | * Returns 0 on success, error code otherwise. |
| 225 | */ | 223 | */ |
| 226 | static int smack_syslog(int typefrom_file) | 224 | static int smack_syslog(int typefrom_file) |
| @@ -231,7 +229,7 @@ static int smack_syslog(int typefrom_file) | |||
| 231 | if (smack_privileged(CAP_MAC_OVERRIDE)) | 229 | if (smack_privileged(CAP_MAC_OVERRIDE)) |
| 232 | return 0; | 230 | return 0; |
| 233 | 231 | ||
| 234 | if (skp != &smack_known_floor) | 232 | if (smack_syslog_label != NULL && smack_syslog_label != skp) |
| 235 | rc = -EACCES; | 233 | rc = -EACCES; |
| 236 | 234 | ||
| 237 | return rc; | 235 | return rc; |
| @@ -341,10 +339,12 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 341 | struct inode *inode = root->d_inode; | 339 | struct inode *inode = root->d_inode; |
| 342 | struct superblock_smack *sp = sb->s_security; | 340 | struct superblock_smack *sp = sb->s_security; |
| 343 | struct inode_smack *isp; | 341 | struct inode_smack *isp; |
| 342 | struct smack_known *skp; | ||
| 344 | char *op; | 343 | char *op; |
| 345 | char *commap; | 344 | char *commap; |
| 346 | char *nsp; | 345 | char *nsp; |
| 347 | int transmute = 0; | 346 | int transmute = 0; |
| 347 | int specified = 0; | ||
| 348 | 348 | ||
| 349 | if (sp->smk_initialized) | 349 | if (sp->smk_initialized) |
| 350 | return 0; | 350 | return 0; |
| @@ -359,34 +359,56 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 359 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { | 359 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { |
| 360 | op += strlen(SMK_FSHAT); | 360 | op += strlen(SMK_FSHAT); |
| 361 | nsp = smk_import(op, 0); | 361 | nsp = smk_import(op, 0); |
| 362 | if (nsp != NULL) | 362 | if (nsp != NULL) { |
| 363 | sp->smk_hat = nsp; | 363 | sp->smk_hat = nsp; |
| 364 | specified = 1; | ||
| 365 | } | ||
| 364 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { | 366 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { |
| 365 | op += strlen(SMK_FSFLOOR); | 367 | op += strlen(SMK_FSFLOOR); |
| 366 | nsp = smk_import(op, 0); | 368 | nsp = smk_import(op, 0); |
| 367 | if (nsp != NULL) | 369 | if (nsp != NULL) { |
| 368 | sp->smk_floor = nsp; | 370 | sp->smk_floor = nsp; |
| 371 | specified = 1; | ||
| 372 | } | ||
| 369 | } else if (strncmp(op, SMK_FSDEFAULT, | 373 | } else if (strncmp(op, SMK_FSDEFAULT, |
| 370 | strlen(SMK_FSDEFAULT)) == 0) { | 374 | strlen(SMK_FSDEFAULT)) == 0) { |
| 371 | op += strlen(SMK_FSDEFAULT); | 375 | op += strlen(SMK_FSDEFAULT); |
| 372 | nsp = smk_import(op, 0); | 376 | nsp = smk_import(op, 0); |
| 373 | if (nsp != NULL) | 377 | if (nsp != NULL) { |
| 374 | sp->smk_default = nsp; | 378 | sp->smk_default = nsp; |
| 379 | specified = 1; | ||
| 380 | } | ||
| 375 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { | 381 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { |
| 376 | op += strlen(SMK_FSROOT); | 382 | op += strlen(SMK_FSROOT); |
| 377 | nsp = smk_import(op, 0); | 383 | nsp = smk_import(op, 0); |
| 378 | if (nsp != NULL) | 384 | if (nsp != NULL) { |
| 379 | sp->smk_root = nsp; | 385 | sp->smk_root = nsp; |
| 386 | specified = 1; | ||
| 387 | } | ||
| 380 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { | 388 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { |
| 381 | op += strlen(SMK_FSTRANS); | 389 | op += strlen(SMK_FSTRANS); |
| 382 | nsp = smk_import(op, 0); | 390 | nsp = smk_import(op, 0); |
| 383 | if (nsp != NULL) { | 391 | if (nsp != NULL) { |
| 384 | sp->smk_root = nsp; | 392 | sp->smk_root = nsp; |
| 385 | transmute = 1; | 393 | transmute = 1; |
| 394 | specified = 1; | ||
| 386 | } | 395 | } |
| 387 | } | 396 | } |
| 388 | } | 397 | } |
| 389 | 398 | ||
| 399 | if (!smack_privileged(CAP_MAC_ADMIN)) { | ||
| 400 | /* | ||
| 401 | * Unprivileged mounts don't get to specify Smack values. | ||
| 402 | */ | ||
| 403 | if (specified) | ||
| 404 | return -EPERM; | ||
| 405 | /* | ||
| 406 | * Unprivileged mounts get root and default from the caller. | ||
| 407 | */ | ||
| 408 | skp = smk_of_current(); | ||
| 409 | sp->smk_root = skp->smk_known; | ||
| 410 | sp->smk_default = skp->smk_known; | ||
| 411 | } | ||
| 390 | /* | 412 | /* |
| 391 | * Initialize the root inode. | 413 | * Initialize the root inode. |
| 392 | */ | 414 | */ |
| @@ -423,53 +445,6 @@ static int smack_sb_statfs(struct dentry *dentry) | |||
| 423 | return rc; | 445 | return rc; |
| 424 | } | 446 | } |
| 425 | 447 | ||
| 426 | /** | ||
| 427 | * smack_sb_mount - Smack check for mounting | ||
| 428 | * @dev_name: unused | ||
| 429 | * @path: mount point | ||
| 430 | * @type: unused | ||
| 431 | * @flags: unused | ||
| 432 | * @data: unused | ||
| 433 | * | ||
| 434 | * Returns 0 if current can write the floor of the filesystem | ||
| 435 | * being mounted on, an error code otherwise. | ||
| 436 | */ | ||
| 437 | static int smack_sb_mount(const char *dev_name, struct path *path, | ||
| 438 | const char *type, unsigned long flags, void *data) | ||
| 439 | { | ||
| 440 | struct superblock_smack *sbp = path->dentry->d_sb->s_security; | ||
| 441 | struct smk_audit_info ad; | ||
| 442 | |||
| 443 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | ||
| 444 | smk_ad_setfield_u_fs_path(&ad, *path); | ||
| 445 | |||
| 446 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | ||
| 447 | } | ||
| 448 | |||
| 449 | /** | ||
| 450 | * smack_sb_umount - Smack check for unmounting | ||
| 451 | * @mnt: file system to unmount | ||
| 452 | * @flags: unused | ||
| 453 | * | ||
| 454 | * Returns 0 if current can write the floor of the filesystem | ||
| 455 | * being unmounted, an error code otherwise. | ||
| 456 | */ | ||
| 457 | static int smack_sb_umount(struct vfsmount *mnt, int flags) | ||
| 458 | { | ||
| 459 | struct superblock_smack *sbp; | ||
| 460 | struct smk_audit_info ad; | ||
| 461 | struct path path; | ||
| 462 | |||
| 463 | path.dentry = mnt->mnt_root; | ||
| 464 | path.mnt = mnt; | ||
| 465 | |||
| 466 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | ||
| 467 | smk_ad_setfield_u_fs_path(&ad, path); | ||
| 468 | |||
| 469 | sbp = path.dentry->d_sb->s_security; | ||
| 470 | return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); | ||
| 471 | } | ||
| 472 | |||
| 473 | /* | 448 | /* |
| 474 | * BPRM hooks | 449 | * BPRM hooks |
| 475 | */ | 450 | */ |
| @@ -837,31 +812,43 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 837 | const void *value, size_t size, int flags) | 812 | const void *value, size_t size, int flags) |
| 838 | { | 813 | { |
| 839 | struct smk_audit_info ad; | 814 | struct smk_audit_info ad; |
| 815 | struct smack_known *skp; | ||
| 816 | int check_priv = 0; | ||
| 817 | int check_import = 0; | ||
| 818 | int check_star = 0; | ||
| 840 | int rc = 0; | 819 | int rc = 0; |
| 841 | 820 | ||
| 821 | /* | ||
| 822 | * Check label validity here so import won't fail in post_setxattr | ||
| 823 | */ | ||
| 842 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || | 824 | if (strcmp(name, XATTR_NAME_SMACK) == 0 || |
| 843 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || | 825 | strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || |
| 844 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || | 826 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { |
| 845 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || | 827 | check_priv = 1; |
| 846 | strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | 828 | check_import = 1; |
| 847 | if (!smack_privileged(CAP_MAC_ADMIN)) | 829 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || |
| 848 | rc = -EPERM; | 830 | strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { |
| 849 | /* | 831 | check_priv = 1; |
| 850 | * check label validity here so import wont fail on | 832 | check_import = 1; |
| 851 | * post_setxattr | 833 | check_star = 1; |
| 852 | */ | ||
| 853 | if (size == 0 || size >= SMK_LONGLABEL || | ||
| 854 | smk_import(value, size) == NULL) | ||
| 855 | rc = -EINVAL; | ||
| 856 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 834 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { |
| 857 | if (!smack_privileged(CAP_MAC_ADMIN)) | 835 | check_priv = 1; |
| 858 | rc = -EPERM; | ||
| 859 | if (size != TRANS_TRUE_SIZE || | 836 | if (size != TRANS_TRUE_SIZE || |
| 860 | strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) | 837 | strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) |
| 861 | rc = -EINVAL; | 838 | rc = -EINVAL; |
| 862 | } else | 839 | } else |
| 863 | rc = cap_inode_setxattr(dentry, name, value, size, flags); | 840 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
| 864 | 841 | ||
| 842 | if (check_priv && !smack_privileged(CAP_MAC_ADMIN)) | ||
| 843 | rc = -EPERM; | ||
| 844 | |||
| 845 | if (rc == 0 && check_import) { | ||
| 846 | skp = smk_import_entry(value, size); | ||
| 847 | if (skp == NULL || (check_star && | ||
| 848 | (skp == &smack_known_star || skp == &smack_known_web))) | ||
| 849 | rc = -EINVAL; | ||
| 850 | } | ||
| 851 | |||
| 865 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | 852 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); |
| 866 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 853 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
| 867 | 854 | ||
| @@ -1364,7 +1351,7 @@ static int smack_file_receive(struct file *file) | |||
| 1364 | int may = 0; | 1351 | int may = 0; |
| 1365 | struct smk_audit_info ad; | 1352 | struct smk_audit_info ad; |
| 1366 | 1353 | ||
| 1367 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | 1354 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); |
| 1368 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | 1355 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
| 1369 | /* | 1356 | /* |
| 1370 | * This code relies on bitmasks. | 1357 | * This code relies on bitmasks. |
| @@ -2847,8 +2834,17 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
| 2847 | if (rc >= 0) | 2834 | if (rc >= 0) |
| 2848 | transflag = SMK_INODE_TRANSMUTE; | 2835 | transflag = SMK_INODE_TRANSMUTE; |
| 2849 | } | 2836 | } |
| 2850 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 2837 | /* |
| 2851 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | 2838 | * Don't let the exec or mmap label be "*" or "@". |
| 2839 | */ | ||
| 2840 | skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | ||
| 2841 | if (skp == &smack_known_star || skp == &smack_known_web) | ||
| 2842 | skp = NULL; | ||
| 2843 | isp->smk_task = skp; | ||
| 2844 | skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | ||
| 2845 | if (skp == &smack_known_star || skp == &smack_known_web) | ||
| 2846 | skp = NULL; | ||
| 2847 | isp->smk_mmap = skp; | ||
| 2852 | 2848 | ||
| 2853 | dput(dp); | 2849 | dput(dp); |
| 2854 | break; | 2850 | break; |
| @@ -3620,9 +3616,8 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, | |||
| 3620 | struct smack_known *skp; | 3616 | struct smack_known *skp; |
| 3621 | char *rule = vrule; | 3617 | char *rule = vrule; |
| 3622 | 3618 | ||
| 3623 | if (!rule) { | 3619 | if (unlikely(!rule)) { |
| 3624 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, | 3620 | WARN_ONCE(1, "Smack: missing rule\n"); |
| 3625 | "Smack: missing rule\n"); | ||
| 3626 | return -ENOENT; | 3621 | return -ENOENT; |
| 3627 | } | 3622 | } |
| 3628 | 3623 | ||
| @@ -3743,8 +3738,6 @@ struct security_operations smack_ops = { | |||
| 3743 | .sb_copy_data = smack_sb_copy_data, | 3738 | .sb_copy_data = smack_sb_copy_data, |
| 3744 | .sb_kern_mount = smack_sb_kern_mount, | 3739 | .sb_kern_mount = smack_sb_kern_mount, |
| 3745 | .sb_statfs = smack_sb_statfs, | 3740 | .sb_statfs = smack_sb_statfs, |
| 3746 | .sb_mount = smack_sb_mount, | ||
| 3747 | .sb_umount = smack_sb_umount, | ||
| 3748 | 3741 | ||
| 3749 | .bprm_set_creds = smack_bprm_set_creds, | 3742 | .bprm_set_creds = smack_bprm_set_creds, |
| 3750 | .bprm_committing_creds = smack_bprm_committing_creds, | 3743 | .bprm_committing_creds = smack_bprm_committing_creds, |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 160aa08e3cd5..3198cfe1dcc6 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -52,6 +52,7 @@ enum smk_inos { | |||
| 52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | 52 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ |
| 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ | 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ |
| 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ | 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ |
| 55 | SMK_SYSLOG = 20, /* change syslog label) */ | ||
| 55 | }; | 56 | }; |
| 56 | 57 | ||
| 57 | /* | 58 | /* |
| @@ -59,6 +60,7 @@ enum smk_inos { | |||
| 59 | */ | 60 | */ |
| 60 | static DEFINE_MUTEX(smack_cipso_lock); | 61 | static DEFINE_MUTEX(smack_cipso_lock); |
| 61 | static DEFINE_MUTEX(smack_ambient_lock); | 62 | static DEFINE_MUTEX(smack_ambient_lock); |
| 63 | static DEFINE_MUTEX(smack_syslog_lock); | ||
| 62 | static DEFINE_MUTEX(smk_netlbladdr_lock); | 64 | static DEFINE_MUTEX(smk_netlbladdr_lock); |
| 63 | 65 | ||
| 64 | /* | 66 | /* |
| @@ -90,7 +92,13 @@ int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | |||
| 90 | * everyone. It is expected that the hat (^) label | 92 | * everyone. It is expected that the hat (^) label |
| 91 | * will be used if any label is used. | 93 | * will be used if any label is used. |
| 92 | */ | 94 | */ |
| 93 | char *smack_onlycap; | 95 | struct smack_known *smack_onlycap; |
| 96 | |||
| 97 | /* | ||
| 98 | * If this value is set restrict syslog use to the label specified. | ||
| 99 | * It can be reset via smackfs/syslog | ||
| 100 | */ | ||
| 101 | struct smack_known *smack_syslog_label; | ||
| 94 | 102 | ||
| 95 | /* | 103 | /* |
| 96 | * Certain IP addresses may be designated as single label hosts. | 104 | * Certain IP addresses may be designated as single label hosts. |
| @@ -301,7 +309,8 @@ static int smk_perm_from_str(const char *string) | |||
| 301 | * @import: if non-zero, import labels | 309 | * @import: if non-zero, import labels |
| 302 | * @len: label length limit | 310 | * @len: label length limit |
| 303 | * | 311 | * |
| 304 | * Returns 0 on success, -1 on failure | 312 | * Returns 0 on success, -EINVAL on failure and -ENOENT when either subject |
| 313 | * or object is missing. | ||
| 305 | */ | 314 | */ |
| 306 | static int smk_fill_rule(const char *subject, const char *object, | 315 | static int smk_fill_rule(const char *subject, const char *object, |
| 307 | const char *access1, const char *access2, | 316 | const char *access1, const char *access2, |
| @@ -314,28 +323,28 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
| 314 | if (import) { | 323 | if (import) { |
| 315 | rule->smk_subject = smk_import_entry(subject, len); | 324 | rule->smk_subject = smk_import_entry(subject, len); |
| 316 | if (rule->smk_subject == NULL) | 325 | if (rule->smk_subject == NULL) |
| 317 | return -1; | 326 | return -EINVAL; |
| 318 | 327 | ||
| 319 | rule->smk_object = smk_import(object, len); | 328 | rule->smk_object = smk_import(object, len); |
| 320 | if (rule->smk_object == NULL) | 329 | if (rule->smk_object == NULL) |
| 321 | return -1; | 330 | return -EINVAL; |
| 322 | } else { | 331 | } else { |
| 323 | cp = smk_parse_smack(subject, len); | 332 | cp = smk_parse_smack(subject, len); |
| 324 | if (cp == NULL) | 333 | if (cp == NULL) |
| 325 | return -1; | 334 | return -EINVAL; |
| 326 | skp = smk_find_entry(cp); | 335 | skp = smk_find_entry(cp); |
| 327 | kfree(cp); | 336 | kfree(cp); |
| 328 | if (skp == NULL) | 337 | if (skp == NULL) |
| 329 | return -1; | 338 | return -ENOENT; |
| 330 | rule->smk_subject = skp; | 339 | rule->smk_subject = skp; |
| 331 | 340 | ||
| 332 | cp = smk_parse_smack(object, len); | 341 | cp = smk_parse_smack(object, len); |
| 333 | if (cp == NULL) | 342 | if (cp == NULL) |
| 334 | return -1; | 343 | return -EINVAL; |
| 335 | skp = smk_find_entry(cp); | 344 | skp = smk_find_entry(cp); |
| 336 | kfree(cp); | 345 | kfree(cp); |
| 337 | if (skp == NULL) | 346 | if (skp == NULL) |
| 338 | return -1; | 347 | return -ENOENT; |
| 339 | rule->smk_object = skp->smk_known; | 348 | rule->smk_object = skp->smk_known; |
| 340 | } | 349 | } |
| 341 | 350 | ||
| @@ -381,6 +390,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
| 381 | { | 390 | { |
| 382 | ssize_t cnt = 0; | 391 | ssize_t cnt = 0; |
| 383 | char *tok[4]; | 392 | char *tok[4]; |
| 393 | int rc; | ||
| 384 | int i; | 394 | int i; |
| 385 | 395 | ||
| 386 | /* | 396 | /* |
| @@ -405,10 +415,8 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
| 405 | while (i < 4) | 415 | while (i < 4) |
| 406 | tok[i++] = NULL; | 416 | tok[i++] = NULL; |
| 407 | 417 | ||
| 408 | if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0)) | 418 | rc = smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0); |
| 409 | return -1; | 419 | return rc == 0 ? cnt : rc; |
| 410 | |||
| 411 | return cnt; | ||
| 412 | } | 420 | } |
| 413 | 421 | ||
| 414 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | 422 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ |
| @@ -1603,7 +1611,7 @@ static const struct file_operations smk_ambient_ops = { | |||
| 1603 | }; | 1611 | }; |
| 1604 | 1612 | ||
| 1605 | /** | 1613 | /** |
| 1606 | * smk_read_onlycap - read() for /smack/onlycap | 1614 | * smk_read_onlycap - read() for smackfs/onlycap |
| 1607 | * @filp: file pointer, not actually used | 1615 | * @filp: file pointer, not actually used |
| 1608 | * @buf: where to put the result | 1616 | * @buf: where to put the result |
| 1609 | * @cn: maximum to send along | 1617 | * @cn: maximum to send along |
| @@ -1622,7 +1630,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
| 1622 | return 0; | 1630 | return 0; |
| 1623 | 1631 | ||
| 1624 | if (smack_onlycap != NULL) | 1632 | if (smack_onlycap != NULL) |
| 1625 | smack = smack_onlycap; | 1633 | smack = smack_onlycap->smk_known; |
| 1626 | 1634 | ||
| 1627 | asize = strlen(smack) + 1; | 1635 | asize = strlen(smack) + 1; |
| 1628 | 1636 | ||
| @@ -1633,7 +1641,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
| 1633 | } | 1641 | } |
| 1634 | 1642 | ||
| 1635 | /** | 1643 | /** |
| 1636 | * smk_write_onlycap - write() for /smack/onlycap | 1644 | * smk_write_onlycap - write() for smackfs/onlycap |
| 1637 | * @file: file pointer, not actually used | 1645 | * @file: file pointer, not actually used |
| 1638 | * @buf: where to get the data from | 1646 | * @buf: where to get the data from |
| 1639 | * @count: bytes sent | 1647 | * @count: bytes sent |
| @@ -1656,7 +1664,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
| 1656 | * explicitly for clarity. The smk_access() implementation | 1664 | * explicitly for clarity. The smk_access() implementation |
| 1657 | * would use smk_access(smack_onlycap, MAY_WRITE) | 1665 | * would use smk_access(smack_onlycap, MAY_WRITE) |
| 1658 | */ | 1666 | */ |
| 1659 | if (smack_onlycap != NULL && smack_onlycap != skp->smk_known) | 1667 | if (smack_onlycap != NULL && smack_onlycap != skp) |
| 1660 | return -EPERM; | 1668 | return -EPERM; |
| 1661 | 1669 | ||
| 1662 | data = kzalloc(count, GFP_KERNEL); | 1670 | data = kzalloc(count, GFP_KERNEL); |
| @@ -1676,7 +1684,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
| 1676 | if (copy_from_user(data, buf, count) != 0) | 1684 | if (copy_from_user(data, buf, count) != 0) |
| 1677 | rc = -EFAULT; | 1685 | rc = -EFAULT; |
| 1678 | else | 1686 | else |
| 1679 | smack_onlycap = smk_import(data, count); | 1687 | smack_onlycap = smk_import_entry(data, count); |
| 1680 | 1688 | ||
| 1681 | kfree(data); | 1689 | kfree(data); |
| 1682 | return rc; | 1690 | return rc; |
| @@ -1856,11 +1864,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
| 1856 | res = smk_parse_long_rule(data, &rule, 0, 3); | 1864 | res = smk_parse_long_rule(data, &rule, 0, 3); |
| 1857 | } | 1865 | } |
| 1858 | 1866 | ||
| 1859 | if (res < 0) | 1867 | if (res >= 0) |
| 1868 | res = smk_access(rule.smk_subject, rule.smk_object, | ||
| 1869 | rule.smk_access1, NULL); | ||
| 1870 | else if (res != -ENOENT) | ||
| 1860 | return -EINVAL; | 1871 | return -EINVAL; |
| 1861 | 1872 | ||
| 1862 | res = smk_access(rule.smk_subject, rule.smk_object, | ||
| 1863 | rule.smk_access1, NULL); | ||
| 1864 | data[0] = res == 0 ? '1' : '0'; | 1873 | data[0] = res == 0 ? '1' : '0'; |
| 1865 | data[1] = '\0'; | 1874 | data[1] = '\0'; |
| 1866 | 1875 | ||
| @@ -2143,7 +2152,7 @@ static ssize_t smk_write_change_rule(struct file *file, const char __user *buf, | |||
| 2143 | /* | 2152 | /* |
| 2144 | * Must have privilege. | 2153 | * Must have privilege. |
| 2145 | */ | 2154 | */ |
| 2146 | if (!capable(CAP_MAC_ADMIN)) | 2155 | if (!smack_privileged(CAP_MAC_ADMIN)) |
| 2147 | return -EPERM; | 2156 | return -EPERM; |
| 2148 | 2157 | ||
| 2149 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | 2158 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, |
| @@ -2158,12 +2167,89 @@ static const struct file_operations smk_change_rule_ops = { | |||
| 2158 | }; | 2167 | }; |
| 2159 | 2168 | ||
| 2160 | /** | 2169 | /** |
| 2161 | * smk_fill_super - fill the /smackfs superblock | 2170 | * smk_read_syslog - read() for smackfs/syslog |
| 2171 | * @filp: file pointer, not actually used | ||
| 2172 | * @buf: where to put the result | ||
| 2173 | * @cn: maximum to send along | ||
| 2174 | * @ppos: where to start | ||
| 2175 | * | ||
| 2176 | * Returns number of bytes read or error code, as appropriate | ||
| 2177 | */ | ||
| 2178 | static ssize_t smk_read_syslog(struct file *filp, char __user *buf, | ||
| 2179 | size_t cn, loff_t *ppos) | ||
| 2180 | { | ||
| 2181 | struct smack_known *skp; | ||
| 2182 | ssize_t rc = -EINVAL; | ||
| 2183 | int asize; | ||
| 2184 | |||
| 2185 | if (*ppos != 0) | ||
| 2186 | return 0; | ||
| 2187 | |||
| 2188 | if (smack_syslog_label == NULL) | ||
| 2189 | skp = &smack_known_star; | ||
| 2190 | else | ||
| 2191 | skp = smack_syslog_label; | ||
| 2192 | |||
| 2193 | asize = strlen(skp->smk_known) + 1; | ||
| 2194 | |||
| 2195 | if (cn >= asize) | ||
| 2196 | rc = simple_read_from_buffer(buf, cn, ppos, skp->smk_known, | ||
| 2197 | asize); | ||
| 2198 | |||
| 2199 | return rc; | ||
| 2200 | } | ||
| 2201 | |||
| 2202 | /** | ||
| 2203 | * smk_write_syslog - write() for smackfs/syslog | ||
| 2204 | * @file: file pointer, not actually used | ||
| 2205 | * @buf: where to get the data from | ||
| 2206 | * @count: bytes sent | ||
| 2207 | * @ppos: where to start | ||
| 2208 | * | ||
| 2209 | * Returns number of bytes written or error code, as appropriate | ||
| 2210 | */ | ||
| 2211 | static ssize_t smk_write_syslog(struct file *file, const char __user *buf, | ||
| 2212 | size_t count, loff_t *ppos) | ||
| 2213 | { | ||
| 2214 | char *data; | ||
| 2215 | struct smack_known *skp; | ||
| 2216 | int rc = count; | ||
| 2217 | |||
| 2218 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
| 2219 | return -EPERM; | ||
| 2220 | |||
| 2221 | data = kzalloc(count, GFP_KERNEL); | ||
| 2222 | if (data == NULL) | ||
| 2223 | return -ENOMEM; | ||
| 2224 | |||
| 2225 | if (copy_from_user(data, buf, count) != 0) | ||
| 2226 | rc = -EFAULT; | ||
| 2227 | else { | ||
| 2228 | skp = smk_import_entry(data, count); | ||
| 2229 | if (skp == NULL) | ||
| 2230 | rc = -EINVAL; | ||
| 2231 | else | ||
| 2232 | smack_syslog_label = smk_import_entry(data, count); | ||
| 2233 | } | ||
| 2234 | |||
| 2235 | kfree(data); | ||
| 2236 | return rc; | ||
| 2237 | } | ||
| 2238 | |||
| 2239 | static const struct file_operations smk_syslog_ops = { | ||
| 2240 | .read = smk_read_syslog, | ||
| 2241 | .write = smk_write_syslog, | ||
| 2242 | .llseek = default_llseek, | ||
| 2243 | }; | ||
| 2244 | |||
| 2245 | |||
| 2246 | /** | ||
| 2247 | * smk_fill_super - fill the smackfs superblock | ||
| 2162 | * @sb: the empty superblock | 2248 | * @sb: the empty superblock |
| 2163 | * @data: unused | 2249 | * @data: unused |
| 2164 | * @silent: unused | 2250 | * @silent: unused |
| 2165 | * | 2251 | * |
| 2166 | * Fill in the well known entries for /smack | 2252 | * Fill in the well known entries for the smack filesystem |
| 2167 | * | 2253 | * |
| 2168 | * Returns 0 on success, an error code on failure | 2254 | * Returns 0 on success, an error code on failure |
| 2169 | */ | 2255 | */ |
| @@ -2208,6 +2294,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2208 | S_IRUGO|S_IWUSR}, | 2294 | S_IRUGO|S_IWUSR}, |
| 2209 | [SMK_CHANGE_RULE] = { | 2295 | [SMK_CHANGE_RULE] = { |
| 2210 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, | 2296 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, |
| 2297 | [SMK_SYSLOG] = { | ||
| 2298 | "syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR}, | ||
| 2211 | /* last one */ | 2299 | /* last one */ |
| 2212 | {""} | 2300 | {""} |
| 2213 | }; | 2301 | }; |
