mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
[NETLINK]: Encapsulate eff_cap usage within security framework.
This patch encapsulates the usage of eff_cap (in netlink_skb_params) within the security framework by extending security_netlink_recv to include a required capability parameter and converting all direct usage of eff_caps outside of the lsm modules to use the interface. It also updates the SELinux implementation of the security_netlink_send and security_netlink_recv hooks to take advantage of the sid in the netlink_skb_params struct. This also enables SELinux to perform auditing of netlink capability checks. Please apply, for 2.6.18 if possible. Signed-off-by: Darrel Goeddel <dgoeddel@trustedcs.com> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
576a30eb64
commit
c7bdb545d2
12 changed files with 35 additions and 34 deletions
|
@ -67,7 +67,7 @@ struct xfrm_state;
|
||||||
struct xfrm_user_sec_ctx;
|
struct xfrm_user_sec_ctx;
|
||||||
|
|
||||||
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
|
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
|
||||||
extern int cap_netlink_recv(struct sk_buff *skb);
|
extern int cap_netlink_recv(struct sk_buff *skb, int cap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Values used in the task_security_ops calls
|
* Values used in the task_security_ops calls
|
||||||
|
@ -656,6 +656,7 @@ struct swap_info_struct;
|
||||||
* Check permission before processing the received netlink message in
|
* Check permission before processing the received netlink message in
|
||||||
* @skb.
|
* @skb.
|
||||||
* @skb contains the sk_buff structure for the netlink message.
|
* @skb contains the sk_buff structure for the netlink message.
|
||||||
|
* @cap indicates the capability required
|
||||||
* Return 0 if permission is granted.
|
* Return 0 if permission is granted.
|
||||||
*
|
*
|
||||||
* Security hooks for Unix domain networking.
|
* Security hooks for Unix domain networking.
|
||||||
|
@ -1266,7 +1267,7 @@ struct security_operations {
|
||||||
struct sembuf * sops, unsigned nsops, int alter);
|
struct sembuf * sops, unsigned nsops, int alter);
|
||||||
|
|
||||||
int (*netlink_send) (struct sock * sk, struct sk_buff * skb);
|
int (*netlink_send) (struct sock * sk, struct sk_buff * skb);
|
||||||
int (*netlink_recv) (struct sk_buff * skb);
|
int (*netlink_recv) (struct sk_buff * skb, int cap);
|
||||||
|
|
||||||
/* allow module stacking */
|
/* allow module stacking */
|
||||||
int (*register_security) (const char *name,
|
int (*register_security) (const char *name,
|
||||||
|
@ -2032,9 +2033,9 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff * skb)
|
||||||
return security_ops->netlink_send(sk, skb);
|
return security_ops->netlink_send(sk, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int security_netlink_recv(struct sk_buff * skb)
|
static inline int security_netlink_recv(struct sk_buff * skb, int cap)
|
||||||
{
|
{
|
||||||
return security_ops->netlink_recv(skb);
|
return security_ops->netlink_recv(skb, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
|
@ -2670,9 +2671,9 @@ static inline int security_netlink_send (struct sock *sk, struct sk_buff *skb)
|
||||||
return cap_netlink_send (sk, skb);
|
return cap_netlink_send (sk, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int security_netlink_recv (struct sk_buff *skb)
|
static inline int security_netlink_recv (struct sk_buff *skb, int cap)
|
||||||
{
|
{
|
||||||
return cap_netlink_recv (skb);
|
return cap_netlink_recv (skb, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct dentry *securityfs_create_dir(const char *name,
|
static inline struct dentry *securityfs_create_dir(const char *name,
|
||||||
|
|
|
@ -445,7 +445,7 @@ void audit_send_reply(int pid, int seq, int type, int done, int multi,
|
||||||
* Check for appropriate CAP_AUDIT_ capabilities on incoming audit
|
* Check for appropriate CAP_AUDIT_ capabilities on incoming audit
|
||||||
* control messages.
|
* control messages.
|
||||||
*/
|
*/
|
||||||
static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
|
static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
@ -459,13 +459,13 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
|
||||||
case AUDIT_DEL:
|
case AUDIT_DEL:
|
||||||
case AUDIT_DEL_RULE:
|
case AUDIT_DEL_RULE:
|
||||||
case AUDIT_SIGNAL_INFO:
|
case AUDIT_SIGNAL_INFO:
|
||||||
if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))
|
if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
break;
|
break;
|
||||||
case AUDIT_USER:
|
case AUDIT_USER:
|
||||||
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
|
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
|
||||||
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
|
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
|
||||||
if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))
|
if (security_netlink_recv(skb, CAP_AUDIT_WRITE))
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
break;
|
break;
|
||||||
default: /* bad msg */
|
default: /* bad msg */
|
||||||
|
@ -488,7 +488,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
||||||
char *ctx;
|
char *ctx;
|
||||||
u32 len;
|
u32 len;
|
||||||
|
|
||||||
err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);
|
err = audit_netlink_ok(skb, msg_type);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
|
@ -663,7 +663,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
|
||||||
sz_idx = type>>2;
|
sz_idx = type>>2;
|
||||||
kind = type&3;
|
kind = type&3;
|
||||||
|
|
||||||
if (kind != 2 && security_netlink_recv(skb)) {
|
if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) {
|
||||||
*errp = -EPERM;
|
*errp = -EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
|
||||||
if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
|
if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
|
if (security_netlink_recv(skb, CAP_NET_ADMIN))
|
||||||
RCV_SKB_FAIL(-EPERM);
|
RCV_SKB_FAIL(-EPERM);
|
||||||
|
|
||||||
/* Eventually we might send routing messages too */
|
/* Eventually we might send routing messages too */
|
||||||
|
|
|
@ -515,7 +515,7 @@ ipq_rcv_skb(struct sk_buff *skb)
|
||||||
if (type <= IPQM_BASE)
|
if (type <= IPQM_BASE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (security_netlink_recv(skb))
|
if (security_netlink_recv(skb, CAP_NET_ADMIN))
|
||||||
RCV_SKB_FAIL(-EPERM);
|
RCV_SKB_FAIL(-EPERM);
|
||||||
|
|
||||||
write_lock_bh(&queue_lock);
|
write_lock_bh(&queue_lock);
|
||||||
|
|
|
@ -505,7 +505,7 @@ ipq_rcv_skb(struct sk_buff *skb)
|
||||||
if (type <= IPQM_BASE)
|
if (type <= IPQM_BASE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (security_netlink_recv(skb))
|
if (security_netlink_recv(skb, CAP_NET_ADMIN))
|
||||||
RCV_SKB_FAIL(-EPERM);
|
RCV_SKB_FAIL(-EPERM);
|
||||||
|
|
||||||
write_lock_bh(&queue_lock);
|
write_lock_bh(&queue_lock);
|
||||||
|
|
|
@ -229,7 +229,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb,
|
||||||
NFNL_SUBSYS_ID(nlh->nlmsg_type),
|
NFNL_SUBSYS_ID(nlh->nlmsg_type),
|
||||||
NFNL_MSG_TYPE(nlh->nlmsg_type));
|
NFNL_MSG_TYPE(nlh->nlmsg_type));
|
||||||
|
|
||||||
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
|
if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
|
||||||
DEBUGP("missing CAP_NET_ADMIN\n");
|
DEBUGP("missing CAP_NET_ADMIN\n");
|
||||||
*errp = -EPERM;
|
*errp = -EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -320,7 +320,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) {
|
if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) {
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1435,7 +1435,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err
|
||||||
link = &xfrm_dispatch[type];
|
link = &xfrm_dispatch[type];
|
||||||
|
|
||||||
/* All operations require privileges, even GET */
|
/* All operations require privileges, even GET */
|
||||||
if (security_netlink_recv(skb)) {
|
if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
|
||||||
*errp = -EPERM;
|
*errp = -EPERM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
|
||||||
|
|
||||||
EXPORT_SYMBOL(cap_netlink_send);
|
EXPORT_SYMBOL(cap_netlink_send);
|
||||||
|
|
||||||
int cap_netlink_recv(struct sk_buff *skb)
|
int cap_netlink_recv(struct sk_buff *skb, int cap)
|
||||||
{
|
{
|
||||||
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
|
if (!cap_raised(NETLINK_CB(skb).eff_cap, cap))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -675,9 +675,9 @@ static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dummy_netlink_recv (struct sk_buff *skb)
|
static int dummy_netlink_recv (struct sk_buff *skb, int cap)
|
||||||
{
|
{
|
||||||
if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN))
|
if (!cap_raised (NETLINK_CB (skb).eff_cap, cap))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3641,32 +3641,32 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
|
||||||
|
|
||||||
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
|
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct task_security_struct *tsec;
|
|
||||||
struct av_decision avd;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = secondary_ops->netlink_send(sk, skb);
|
err = secondary_ops->netlink_send(sk, skb);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
tsec = current->security;
|
|
||||||
|
|
||||||
avd.allowed = 0;
|
|
||||||
avc_has_perm_noaudit(tsec->sid, tsec->sid,
|
|
||||||
SECCLASS_CAPABILITY, ~0, &avd);
|
|
||||||
cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed);
|
|
||||||
|
|
||||||
if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
|
if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
|
||||||
err = selinux_nlmsg_perm(sk, skb);
|
err = selinux_nlmsg_perm(sk, skb);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_netlink_recv(struct sk_buff *skb)
|
static int selinux_netlink_recv(struct sk_buff *skb, int capability)
|
||||||
{
|
{
|
||||||
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
|
int err;
|
||||||
return -EPERM;
|
struct avc_audit_data ad;
|
||||||
return 0;
|
|
||||||
|
err = secondary_ops->netlink_recv(skb, capability);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
AVC_AUDIT_DATA_INIT(&ad, CAP);
|
||||||
|
ad.u.cap = capability;
|
||||||
|
|
||||||
|
return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
|
||||||
|
SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ipc_alloc_security(struct task_struct *task,
|
static int ipc_alloc_security(struct task_struct *task,
|
||||||
|
|
Loading…
Reference in a new issue