Commit c7bdb545 authored by Darrel Goeddel's avatar Darrel Goeddel Committed by David S. Miller

[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: default avatarDarrel Goeddel <dgoeddel@trustedcs.com>
Signed-off-by: default avatarStephen Smalley <sds@tycho.nsa.gov>
Acked-by: default avatarJames Morris <jmorris@namei.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 576a30eb
...@@ -67,7 +67,7 @@ struct xfrm_state; ...@@ -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; ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment