+ Features/Improvements
- replace spin_is_locked() with lockdep - add base support for secmark labeling and matching + Cleanups - clean an indentation issue, remove extraneous space - remove no-op permission check in policy_unpack - fix checkpatch missing spaces error in Parse secmark policy - fix network performance issue in aa_label_sk_perm + Bug fixes - add #ifdef checks for secmark filtering - fix an error code in __aa_create_ns() - don't try to replace stale label in ptrace checks - fix failure to audit context info in build_change_hat - check buffer bounds when mapping permissions mask - fully initialize aa_perms struct when answering userspace query - fix uninitialized value in aa_split_fqname -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE7cSDD705q2rFEEf7BS82cBjVw9gFAlvb5PAACgkQBS82cBjV w9jrZhAAohmR2SPYDPKsBlmEzEUFg9EgiQmuNTloodZUrc42/cstGsa5B6xxbhZJ ke69xnNj7wxokOLMKzZboEjAuFtAmObF4iwOj5w2xuJktpZrTCXawgZppRnJybwk U8s1fY7sszjN2pJ7CvFIwHk5UPlncu+RK+/8y8yFcrSlrT3lcrpjL3xt97E6H9WA Fv10SQCtw2godT/Je62V83OPG30E6pyUXN+kJeSYGeYaJOnVFCP7wo0muH/UPUU7 MHzlvjCZ1F8BMtvotk/E/0syeb/mS3tluhMYHysKrcknahMWgmV0vr9NrOsXUzDj ExVXmVdtZx3CA7TnOlycJCXv0LK6W0v5FpHTeYket6Dxza7tc4fImQ9lok6vCn2Q 7kfFeDBbujj4lvIJlgbh7W2Yk4T6HWz6ENaHUJrXKgr2OTqgbvTkHpTyMRkqAWiq tcpbhdB7dn+bWw5Ni1OYBfh9pGleOekMuWlB742RoTeml6BFTa9OtOYytdBEogHR yjrfxUZwSsVTGc16uqRFK71QZC2mFZNbw1J8eGG8f2YtN/3q+8JYu0JoIXqcSTep 95mvOwapJ74fy4GyiZdpVvkEozPX/7ITGfKi2f42EPCaC7YKXcdrft0XHJHf6JN5 peGPOyI8SeiGKm+X0FrGk+eSlJRar+bkCzkDHg/vkQQYmqBn9Ec= =GzxZ -----END PGP SIGNATURE----- Merge tag 'apparmor-pr-2018-11-01' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor Pull apparmor updates from John Johansen: "Features/Improvements: - replace spin_is_locked() with lockdep - add base support for secmark labeling and matching Cleanups: - clean an indentation issue, remove extraneous space - remove no-op permission check in policy_unpack - fix checkpatch missing spaces error in Parse secmark policy - fix network performance issue in aa_label_sk_perm Bug fixes: - add #ifdef checks for secmark filtering - fix an error code in __aa_create_ns() - don't try to replace stale label in ptrace checks - fix failure to audit context info in build_change_hat - check buffer bounds when mapping permissions mask - fully initialize aa_perms struct when answering userspace query - fix uninitialized value in aa_split_fqname" * tag 'apparmor-pr-2018-11-01' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: apparmor: clean an indentation issue, remove extraneous space apparmor: fix checkpatch error in Parse secmark policy apparmor: add #ifdef checks for secmark filtering apparmor: Fix uninitialized value in aa_split_fqname apparmor: don't try to replace stale label in ptraceme check apparmor: Replace spin_is_locked() with lockdep apparmor: Allow filtering based on secmark policy apparmor: Parse secmark policy apparmor: Add a wildcard secid apparmor: don't try to replace stale label in ptrace access check apparmor: Fix network performance issue in aa_label_sk_perm
This commit is contained in:
commit
d81f50bd34
|
@ -1742,7 +1742,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry)
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
parent = aa_get_ns(dir->i_private);
|
parent = aa_get_ns(dir->i_private);
|
||||||
/* rmdir calls the generic securityfs functions to remove files
|
/* rmdir calls the generic securityfs functions to remove files
|
||||||
* from the apparmor dir. It is up to the apparmor ns locking
|
* from the apparmor dir. It is up to the apparmor ns locking
|
||||||
* to avoid races.
|
* to avoid races.
|
||||||
|
|
|
@ -496,7 +496,7 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label,
|
||||||
/* update caching of label on file_ctx */
|
/* update caching of label on file_ctx */
|
||||||
spin_lock(&fctx->lock);
|
spin_lock(&fctx->lock);
|
||||||
old = rcu_dereference_protected(fctx->label,
|
old = rcu_dereference_protected(fctx->label,
|
||||||
spin_is_locked(&fctx->lock));
|
lockdep_is_held(&fctx->lock));
|
||||||
l = aa_label_merge(old, label, GFP_ATOMIC);
|
l = aa_label_merge(old, label, GFP_ATOMIC);
|
||||||
if (l) {
|
if (l) {
|
||||||
if (l != old) {
|
if (l != old) {
|
||||||
|
|
|
@ -151,6 +151,8 @@ static inline struct aa_label *begin_current_label_crit_section(void)
|
||||||
{
|
{
|
||||||
struct aa_label *label = aa_current_raw_label();
|
struct aa_label *label = aa_current_raw_label();
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
if (label_is_stale(label)) {
|
if (label_is_stale(label)) {
|
||||||
label = aa_get_newest_label(label);
|
label = aa_get_newest_label(label);
|
||||||
if (aa_replace_current_label(label) == 0)
|
if (aa_replace_current_label(label) == 0)
|
||||||
|
|
|
@ -83,6 +83,13 @@ struct aa_sk_ctx {
|
||||||
__e; \
|
__e; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
struct aa_secmark {
|
||||||
|
u8 audit;
|
||||||
|
u8 deny;
|
||||||
|
u32 secid;
|
||||||
|
char *label;
|
||||||
|
};
|
||||||
|
|
||||||
extern struct aa_sfs_entry aa_sfs_entry_network[];
|
extern struct aa_sfs_entry aa_sfs_entry_network[];
|
||||||
|
|
||||||
void audit_net_cb(struct audit_buffer *ab, void *va);
|
void audit_net_cb(struct audit_buffer *ab, void *va);
|
||||||
|
@ -103,4 +110,7 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk);
|
||||||
int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
|
int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
|
||||||
struct socket *sock);
|
struct socket *sock);
|
||||||
|
|
||||||
|
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
|
||||||
|
u32 secid, struct sock *sk);
|
||||||
|
|
||||||
#endif /* __AA_NET_H */
|
#endif /* __AA_NET_H */
|
||||||
|
|
|
@ -155,6 +155,9 @@ struct aa_profile {
|
||||||
|
|
||||||
struct aa_rlimit rlimits;
|
struct aa_rlimit rlimits;
|
||||||
|
|
||||||
|
int secmark_count;
|
||||||
|
struct aa_secmark *secmark;
|
||||||
|
|
||||||
struct aa_loaddata *rawdata;
|
struct aa_loaddata *rawdata;
|
||||||
unsigned char *hash;
|
unsigned char *hash;
|
||||||
char *dirname;
|
char *dirname;
|
||||||
|
|
|
@ -22,6 +22,9 @@ struct aa_label;
|
||||||
/* secid value that will not be allocated */
|
/* secid value that will not be allocated */
|
||||||
#define AA_SECID_INVALID 0
|
#define AA_SECID_INVALID 0
|
||||||
|
|
||||||
|
/* secid value that matches any other secid */
|
||||||
|
#define AA_SECID_WILDCARD 1
|
||||||
|
|
||||||
struct aa_label *aa_secid_to_label(u32 secid);
|
struct aa_label *aa_secid_to_label(u32 secid);
|
||||||
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
|
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
|
||||||
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
|
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
|
||||||
|
|
|
@ -90,10 +90,12 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
|
||||||
const char *end = fqname + n;
|
const char *end = fqname + n;
|
||||||
const char *name = skipn_spaces(fqname, n);
|
const char *name = skipn_spaces(fqname, n);
|
||||||
|
|
||||||
if (!name)
|
|
||||||
return NULL;
|
|
||||||
*ns_name = NULL;
|
*ns_name = NULL;
|
||||||
*ns_len = 0;
|
*ns_len = 0;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (name[0] == ':') {
|
if (name[0] == ':') {
|
||||||
char *split = strnchr(&name[1], end - &name[1], ':');
|
char *split = strnchr(&name[1], end - &name[1], ':');
|
||||||
*ns_name = skipn_spaces(&name[1], end - &name[1]);
|
*ns_name = skipn_spaces(&name[1], end - &name[1]);
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/audit.h>
|
#include <linux/audit.h>
|
||||||
#include <linux/user_namespace.h>
|
#include <linux/user_namespace.h>
|
||||||
|
#include <linux/netfilter_ipv4.h>
|
||||||
|
#include <linux/netfilter_ipv6.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
|
||||||
#include "include/apparmor.h"
|
#include "include/apparmor.h"
|
||||||
|
@ -114,13 +116,13 @@ static int apparmor_ptrace_access_check(struct task_struct *child,
|
||||||
struct aa_label *tracer, *tracee;
|
struct aa_label *tracer, *tracee;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
tracer = begin_current_label_crit_section();
|
tracer = __begin_current_label_crit_section();
|
||||||
tracee = aa_get_task_label(child);
|
tracee = aa_get_task_label(child);
|
||||||
error = aa_may_ptrace(tracer, tracee,
|
error = aa_may_ptrace(tracer, tracee,
|
||||||
(mode & PTRACE_MODE_READ) ? AA_PTRACE_READ
|
(mode & PTRACE_MODE_READ) ? AA_PTRACE_READ
|
||||||
: AA_PTRACE_TRACE);
|
: AA_PTRACE_TRACE);
|
||||||
aa_put_label(tracee);
|
aa_put_label(tracee);
|
||||||
end_current_label_crit_section(tracer);
|
__end_current_label_crit_section(tracer);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -130,11 +132,11 @@ static int apparmor_ptrace_traceme(struct task_struct *parent)
|
||||||
struct aa_label *tracer, *tracee;
|
struct aa_label *tracer, *tracee;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
tracee = begin_current_label_crit_section();
|
tracee = __begin_current_label_crit_section();
|
||||||
tracer = aa_get_task_label(parent);
|
tracer = aa_get_task_label(parent);
|
||||||
error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE);
|
error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE);
|
||||||
aa_put_label(tracer);
|
aa_put_label(tracer);
|
||||||
end_current_label_crit_section(tracee);
|
__end_current_label_crit_section(tracee);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -1020,6 +1022,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||||
return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
|
return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NETWORK_SECMARK
|
||||||
/**
|
/**
|
||||||
* apparmor_socket_sock_recv_skb - check perms before associating skb to sk
|
* apparmor_socket_sock_recv_skb - check perms before associating skb to sk
|
||||||
*
|
*
|
||||||
|
@ -1030,8 +1033,15 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||||
*/
|
*/
|
||||||
static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
return 0;
|
struct aa_sk_ctx *ctx = SK_CTX(sk);
|
||||||
|
|
||||||
|
if (!skb->secmark)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE,
|
||||||
|
skb->secmark, sk);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static struct aa_label *sk_peer_label(struct sock *sk)
|
static struct aa_label *sk_peer_label(struct sock *sk)
|
||||||
|
@ -1126,6 +1136,20 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
|
||||||
ctx->label = aa_get_current_label();
|
ctx->label = aa_get_current_label();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NETWORK_SECMARK
|
||||||
|
static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||||
|
struct request_sock *req)
|
||||||
|
{
|
||||||
|
struct aa_sk_ctx *ctx = SK_CTX(sk);
|
||||||
|
|
||||||
|
if (!skb->secmark)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT,
|
||||||
|
skb->secmark, sk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||||
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
||||||
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
||||||
|
@ -1177,12 +1201,17 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||||
LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
|
LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
|
||||||
LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
|
LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
|
||||||
LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
|
LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
|
||||||
|
#ifdef CONFIG_NETWORK_SECMARK
|
||||||
LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
|
LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
|
||||||
|
#endif
|
||||||
LSM_HOOK_INIT(socket_getpeersec_stream,
|
LSM_HOOK_INIT(socket_getpeersec_stream,
|
||||||
apparmor_socket_getpeersec_stream),
|
apparmor_socket_getpeersec_stream),
|
||||||
LSM_HOOK_INIT(socket_getpeersec_dgram,
|
LSM_HOOK_INIT(socket_getpeersec_dgram,
|
||||||
apparmor_socket_getpeersec_dgram),
|
apparmor_socket_getpeersec_dgram),
|
||||||
LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
|
LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
|
||||||
|
#ifdef CONFIG_NETWORK_SECMARK
|
||||||
|
LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request),
|
||||||
|
#endif
|
||||||
|
|
||||||
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
|
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
|
||||||
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
|
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
|
||||||
|
@ -1538,6 +1567,97 @@ static inline int apparmor_init_sysctl(void)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SYSCTL */
|
#endif /* CONFIG_SYSCTL */
|
||||||
|
|
||||||
|
#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK)
|
||||||
|
static unsigned int apparmor_ip_postroute(void *priv,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
const struct nf_hook_state *state)
|
||||||
|
{
|
||||||
|
struct aa_sk_ctx *ctx;
|
||||||
|
struct sock *sk;
|
||||||
|
|
||||||
|
if (!skb->secmark)
|
||||||
|
return NF_ACCEPT;
|
||||||
|
|
||||||
|
sk = skb_to_full_sk(skb);
|
||||||
|
if (sk == NULL)
|
||||||
|
return NF_ACCEPT;
|
||||||
|
|
||||||
|
ctx = SK_CTX(sk);
|
||||||
|
if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
|
||||||
|
skb->secmark, sk))
|
||||||
|
return NF_ACCEPT;
|
||||||
|
|
||||||
|
return NF_DROP_ERR(-ECONNREFUSED);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int apparmor_ipv4_postroute(void *priv,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
const struct nf_hook_state *state)
|
||||||
|
{
|
||||||
|
return apparmor_ip_postroute(priv, skb, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int apparmor_ipv6_postroute(void *priv,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
const struct nf_hook_state *state)
|
||||||
|
{
|
||||||
|
return apparmor_ip_postroute(priv, skb, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct nf_hook_ops apparmor_nf_ops[] = {
|
||||||
|
{
|
||||||
|
.hook = apparmor_ipv4_postroute,
|
||||||
|
.pf = NFPROTO_IPV4,
|
||||||
|
.hooknum = NF_INET_POST_ROUTING,
|
||||||
|
.priority = NF_IP_PRI_SELINUX_FIRST,
|
||||||
|
},
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
{
|
||||||
|
.hook = apparmor_ipv6_postroute,
|
||||||
|
.pf = NFPROTO_IPV6,
|
||||||
|
.hooknum = NF_INET_POST_ROUTING,
|
||||||
|
.priority = NF_IP6_PRI_SELINUX_FIRST,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __net_init apparmor_nf_register(struct net *net)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nf_register_net_hooks(net, apparmor_nf_ops,
|
||||||
|
ARRAY_SIZE(apparmor_nf_ops));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __net_exit apparmor_nf_unregister(struct net *net)
|
||||||
|
{
|
||||||
|
nf_unregister_net_hooks(net, apparmor_nf_ops,
|
||||||
|
ARRAY_SIZE(apparmor_nf_ops));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pernet_operations apparmor_net_ops = {
|
||||||
|
.init = apparmor_nf_register,
|
||||||
|
.exit = apparmor_nf_unregister,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init apparmor_nf_ip_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!apparmor_enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = register_pernet_subsys(&apparmor_net_ops);
|
||||||
|
if (err)
|
||||||
|
panic("Apparmor: register_pernet_subsys: error %d\n", err);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
__initcall(apparmor_nf_ip_init);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __init apparmor_init(void)
|
static int __init apparmor_init(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "include/label.h"
|
#include "include/label.h"
|
||||||
#include "include/net.h"
|
#include "include/net.h"
|
||||||
#include "include/policy.h"
|
#include "include/policy.h"
|
||||||
|
#include "include/secid.h"
|
||||||
|
|
||||||
#include "net_names.h"
|
#include "net_names.h"
|
||||||
|
|
||||||
|
@ -146,17 +147,20 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
|
||||||
static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
|
static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
|
||||||
struct sock *sk)
|
struct sock *sk)
|
||||||
{
|
{
|
||||||
struct aa_profile *profile;
|
int error = 0;
|
||||||
DEFINE_AUDIT_SK(sa, op, sk);
|
|
||||||
|
|
||||||
AA_BUG(!label);
|
AA_BUG(!label);
|
||||||
AA_BUG(!sk);
|
AA_BUG(!sk);
|
||||||
|
|
||||||
if (unconfined(label))
|
if (!unconfined(label)) {
|
||||||
return 0;
|
struct aa_profile *profile;
|
||||||
|
DEFINE_AUDIT_SK(sa, op, sk);
|
||||||
|
|
||||||
return fn_for_each_confined(label, profile,
|
error = fn_for_each_confined(label, profile,
|
||||||
aa_profile_af_sk_perm(profile, &sa, request, sk));
|
aa_profile_af_sk_perm(profile, &sa, request, sk));
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int aa_sk_perm(const char *op, u32 request, struct sock *sk)
|
int aa_sk_perm(const char *op, u32 request, struct sock *sk)
|
||||||
|
@ -185,3 +189,70 @@ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
|
||||||
|
|
||||||
return aa_label_sk_perm(label, op, request, sock->sk);
|
return aa_label_sk_perm(label, op, request, sock->sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_NETWORK_SECMARK
|
||||||
|
static int apparmor_secmark_init(struct aa_secmark *secmark)
|
||||||
|
{
|
||||||
|
struct aa_label *label;
|
||||||
|
|
||||||
|
if (secmark->label[0] == '*') {
|
||||||
|
secmark->secid = AA_SECID_WILDCARD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label = aa_label_strn_parse(&root_ns->unconfined->label,
|
||||||
|
secmark->label, strlen(secmark->label),
|
||||||
|
GFP_ATOMIC, false, false);
|
||||||
|
|
||||||
|
if (IS_ERR(label))
|
||||||
|
return PTR_ERR(label);
|
||||||
|
|
||||||
|
secmark->secid = label->secid;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
|
||||||
|
struct common_audit_data *sa, struct sock *sk)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
struct aa_perms perms = { };
|
||||||
|
|
||||||
|
if (profile->secmark_count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < profile->secmark_count; i++) {
|
||||||
|
if (!profile->secmark[i].secid) {
|
||||||
|
ret = apparmor_secmark_init(&profile->secmark[i]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile->secmark[i].secid == secid ||
|
||||||
|
profile->secmark[i].secid == AA_SECID_WILDCARD) {
|
||||||
|
if (profile->secmark[i].deny)
|
||||||
|
perms.deny = ALL_PERMS_MASK;
|
||||||
|
else
|
||||||
|
perms.allow = ALL_PERMS_MASK;
|
||||||
|
|
||||||
|
if (profile->secmark[i].audit)
|
||||||
|
perms.audit = ALL_PERMS_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aa_apply_modes_to_perms(profile, &perms);
|
||||||
|
|
||||||
|
return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
|
||||||
|
u32 secid, struct sock *sk)
|
||||||
|
{
|
||||||
|
struct aa_profile *profile;
|
||||||
|
DEFINE_AUDIT_SK(sa, op, sk);
|
||||||
|
|
||||||
|
return fn_for_each_confined(label, profile,
|
||||||
|
aa_secmark_perm(profile, request, secid,
|
||||||
|
&sa, sk));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -231,6 +231,9 @@ void aa_free_profile(struct aa_profile *profile)
|
||||||
for (i = 0; i < profile->xattr_count; i++)
|
for (i = 0; i < profile->xattr_count; i++)
|
||||||
kzfree(profile->xattrs[i]);
|
kzfree(profile->xattrs[i]);
|
||||||
kzfree(profile->xattrs);
|
kzfree(profile->xattrs);
|
||||||
|
for (i = 0; i < profile->secmark_count; i++)
|
||||||
|
kzfree(profile->secmark[i].label);
|
||||||
|
kzfree(profile->secmark);
|
||||||
kzfree(profile->dirname);
|
kzfree(profile->dirname);
|
||||||
aa_put_dfa(profile->xmatch);
|
aa_put_dfa(profile->xmatch);
|
||||||
aa_put_dfa(profile->policy.dfa);
|
aa_put_dfa(profile->policy.dfa);
|
||||||
|
|
|
@ -292,6 +292,19 @@ fail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
|
||||||
|
{
|
||||||
|
if (unpack_nameX(e, AA_U8, name)) {
|
||||||
|
if (!inbounds(e, sizeof(u8)))
|
||||||
|
return 0;
|
||||||
|
if (data)
|
||||||
|
*data = get_unaligned((u8 *)e->pos);
|
||||||
|
e->pos += sizeof(u8);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
|
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
|
||||||
{
|
{
|
||||||
if (unpack_nameX(e, AA_U32, name)) {
|
if (unpack_nameX(e, AA_U32, name)) {
|
||||||
|
@ -529,6 +542,49 @@ fail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
|
||||||
|
{
|
||||||
|
void *pos = e->pos;
|
||||||
|
int i, size;
|
||||||
|
|
||||||
|
if (unpack_nameX(e, AA_STRUCT, "secmark")) {
|
||||||
|
size = unpack_array(e, NULL);
|
||||||
|
|
||||||
|
profile->secmark = kcalloc(size, sizeof(struct aa_secmark),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!profile->secmark)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
profile->secmark_count = size;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
if (!unpack_u8(e, &profile->secmark[i].audit, NULL))
|
||||||
|
goto fail;
|
||||||
|
if (!unpack_u8(e, &profile->secmark[i].deny, NULL))
|
||||||
|
goto fail;
|
||||||
|
if (!unpack_strdup(e, &profile->secmark[i].label, NULL))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||||
|
goto fail;
|
||||||
|
if (!unpack_nameX(e, AA_STRUCTEND, NULL))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (profile->secmark) {
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
kfree(profile->secmark[i].label);
|
||||||
|
kfree(profile->secmark);
|
||||||
|
profile->secmark_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->pos = pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
|
static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
|
||||||
{
|
{
|
||||||
void *pos = e->pos;
|
void *pos = e->pos;
|
||||||
|
@ -727,6 +783,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!unpack_secmark(e, profile)) {
|
||||||
|
info = "failed to unpack profile secmark rules";
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||||
/* generic policy dfa - optional and may be NULL */
|
/* generic policy dfa - optional and may be NULL */
|
||||||
info = "failed to unpack policydb";
|
info = "failed to unpack policydb";
|
||||||
|
|
|
@ -32,8 +32,7 @@
|
||||||
* secids - do not pin labels with a refcount. They rely on the label
|
* secids - do not pin labels with a refcount. They rely on the label
|
||||||
* properly updating/freeing them
|
* properly updating/freeing them
|
||||||
*/
|
*/
|
||||||
|
#define AA_FIRST_SECID 2
|
||||||
#define AA_FIRST_SECID 1
|
|
||||||
|
|
||||||
static DEFINE_IDR(aa_secids);
|
static DEFINE_IDR(aa_secids);
|
||||||
static DEFINE_SPINLOCK(secid_lock);
|
static DEFINE_SPINLOCK(secid_lock);
|
||||||
|
|
Loading…
Reference in New Issue