You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' into for-linus
This commit is contained in:
+29
-2
@@ -16,6 +16,7 @@
|
||||
#include <linux/capability.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/in.h>
|
||||
#include <net/netlabel.h>
|
||||
|
||||
/*
|
||||
@@ -39,6 +40,7 @@ struct superblock_smack {
|
||||
struct socket_smack {
|
||||
char *smk_out; /* outbound label */
|
||||
char *smk_in; /* inbound label */
|
||||
int smk_labeled; /* label scheme */
|
||||
char smk_packet[SMK_LABELLEN]; /* TCP peer label */
|
||||
};
|
||||
|
||||
@@ -79,6 +81,16 @@ struct smack_cipso {
|
||||
char smk_catset[SMK_LABELLEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* An entry in the table identifying hosts.
|
||||
*/
|
||||
struct smk_netlbladdr {
|
||||
struct smk_netlbladdr *smk_next;
|
||||
struct sockaddr_in smk_host; /* network address */
|
||||
struct in_addr smk_mask; /* network mask */
|
||||
char *smk_label; /* label */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the repository for labels seen so that it is
|
||||
* not necessary to keep allocating tiny chuncks of memory
|
||||
@@ -127,6 +139,20 @@ struct smack_known {
|
||||
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
|
||||
|
||||
/*
|
||||
* How communications on this socket are treated.
|
||||
* Usually it's determined by the underlying netlabel code
|
||||
* but there are certain cases, including single label hosts
|
||||
* and potentially single label interfaces for which the
|
||||
* treatment can not be known in advance.
|
||||
*
|
||||
* The possibility of additional labeling schemes being
|
||||
* introduced in the future exists as well.
|
||||
*/
|
||||
#define SMACK_UNLABELED_SOCKET 0
|
||||
#define SMACK_CIPSO_SOCKET 1
|
||||
|
||||
/*
|
||||
* smackfs magic number
|
||||
* smackfs macic number
|
||||
*/
|
||||
#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
|
||||
@@ -141,6 +167,7 @@ struct smack_known {
|
||||
* CIPSO defaults.
|
||||
*/
|
||||
#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
|
||||
#define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */
|
||||
#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */
|
||||
#define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */
|
||||
#define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */
|
||||
@@ -176,7 +203,6 @@ u32 smack_to_secid(const char *);
|
||||
* Shared data.
|
||||
*/
|
||||
extern int smack_cipso_direct;
|
||||
extern int smack_net_nltype;
|
||||
extern char *smack_net_ambient;
|
||||
extern char *smack_onlycap;
|
||||
|
||||
@@ -186,9 +212,10 @@ extern struct smack_known smack_known_hat;
|
||||
extern struct smack_known smack_known_huh;
|
||||
extern struct smack_known smack_known_invalid;
|
||||
extern struct smack_known smack_known_star;
|
||||
extern struct smack_known smack_known_unset;
|
||||
extern struct smack_known smack_known_web;
|
||||
|
||||
extern struct smk_list_entry *smack_list;
|
||||
extern struct smk_netlbladdr *smack_netlbladdrs;
|
||||
extern struct security_operations smack_ops;
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,15 +15,8 @@
|
||||
#include <linux/sched.h>
|
||||
#include "smack.h"
|
||||
|
||||
struct smack_known smack_known_unset = {
|
||||
.smk_next = NULL,
|
||||
.smk_known = "UNSET",
|
||||
.smk_secid = 1,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_huh = {
|
||||
.smk_next = &smack_known_unset,
|
||||
.smk_next = NULL,
|
||||
.smk_known = "?",
|
||||
.smk_secid = 2,
|
||||
.smk_cipso = NULL,
|
||||
@@ -57,7 +50,14 @@ struct smack_known smack_known_invalid = {
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known *smack_known = &smack_known_invalid;
|
||||
struct smack_known smack_known_web = {
|
||||
.smk_next = &smack_known_invalid,
|
||||
.smk_known = "@",
|
||||
.smk_secid = 7,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known *smack_known = &smack_known_web;
|
||||
|
||||
/*
|
||||
* The initial value needs to be bigger than any of the
|
||||
@@ -98,6 +98,16 @@ int smk_access(char *subject_label, char *object_label, int request)
|
||||
if (subject_label == smack_known_star.smk_known ||
|
||||
strcmp(subject_label, smack_known_star.smk_known) == 0)
|
||||
return -EACCES;
|
||||
/*
|
||||
* An internet object can be accessed by any subject.
|
||||
* Tasks cannot be assigned the internet label.
|
||||
* An internet subject can access any object.
|
||||
*/
|
||||
if (object_label == smack_known_web.smk_known ||
|
||||
subject_label == smack_known_web.smk_known ||
|
||||
strcmp(object_label, smack_known_web.smk_known) == 0 ||
|
||||
strcmp(subject_label, smack_known_web.smk_known) == 0)
|
||||
return 0;
|
||||
/*
|
||||
* A star object can be accessed by any subject.
|
||||
*/
|
||||
|
||||
+256
-56
@@ -1277,6 +1277,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
|
||||
|
||||
ssp->smk_in = csp;
|
||||
ssp->smk_out = csp;
|
||||
ssp->smk_labeled = SMACK_CIPSO_SOCKET;
|
||||
ssp->smk_packet[0] = '\0';
|
||||
|
||||
sk->sk_security = ssp;
|
||||
@@ -1341,45 +1342,69 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
|
||||
struct smack_cipso cipso;
|
||||
int rc;
|
||||
|
||||
switch (smack_net_nltype) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
nlsp->domain = smack;
|
||||
nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
|
||||
nlsp->domain = smack;
|
||||
nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
|
||||
|
||||
rc = smack_to_cipso(smack, &cipso);
|
||||
if (rc == 0) {
|
||||
nlsp->attr.mls.lvl = cipso.smk_level;
|
||||
smack_set_catset(cipso.smk_catset, nlsp);
|
||||
} else {
|
||||
nlsp->attr.mls.lvl = smack_cipso_direct;
|
||||
smack_set_catset(smack, nlsp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
rc = smack_to_cipso(smack, &cipso);
|
||||
if (rc == 0) {
|
||||
nlsp->attr.mls.lvl = cipso.smk_level;
|
||||
smack_set_catset(cipso.smk_catset, nlsp);
|
||||
} else {
|
||||
nlsp->attr.mls.lvl = smack_cipso_direct;
|
||||
smack_set_catset(smack, nlsp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_netlabel - Set the secattr on a socket
|
||||
* @sk: the socket
|
||||
* @labeled: socket label scheme
|
||||
*
|
||||
* Convert the outbound smack value (smk_out) to a
|
||||
* secattr and attach it to the socket.
|
||||
*
|
||||
* Returns 0 on success or an error code
|
||||
*/
|
||||
static int smack_netlabel(struct sock *sk)
|
||||
static int smack_netlabel(struct sock *sk, int labeled)
|
||||
{
|
||||
struct socket_smack *ssp;
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
ssp = sk->sk_security;
|
||||
netlbl_secattr_init(&secattr);
|
||||
smack_to_secattr(ssp->smk_out, &secattr);
|
||||
rc = netlbl_sock_setattr(sk, &secattr);
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
/*
|
||||
* Usually the netlabel code will handle changing the
|
||||
* packet labeling based on the label.
|
||||
* The case of a single label host is different, because
|
||||
* a single label host should never get a labeled packet
|
||||
* even though the label is usually associated with a packet
|
||||
* label.
|
||||
*/
|
||||
local_bh_disable();
|
||||
bh_lock_sock_nested(sk);
|
||||
|
||||
if (ssp->smk_out == smack_net_ambient ||
|
||||
labeled == SMACK_UNLABELED_SOCKET)
|
||||
netlbl_sock_delattr(sk);
|
||||
else {
|
||||
netlbl_secattr_init(&secattr);
|
||||
smack_to_secattr(ssp->smk_out, &secattr);
|
||||
rc = netlbl_sock_setattr(sk, &secattr);
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
}
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
local_bh_enable();
|
||||
/*
|
||||
* Remember the label scheme used so that it is not
|
||||
* necessary to do the netlabel setting if it has not
|
||||
* changed the next time through.
|
||||
*
|
||||
* The -EDESTADDRREQ case is an indication that there's
|
||||
* a single level host involved.
|
||||
*/
|
||||
if (rc == 0)
|
||||
ssp->smk_labeled = labeled;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1432,7 +1457,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
||||
ssp->smk_in = sp;
|
||||
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
|
||||
ssp->smk_out = sp;
|
||||
rc = smack_netlabel(sock->sk);
|
||||
rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
@@ -1462,7 +1487,108 @@ static int smack_socket_post_create(struct socket *sock, int family,
|
||||
/*
|
||||
* Set the outbound netlbl.
|
||||
*/
|
||||
return smack_netlabel(sock->sk);
|
||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* smack_host_label - check host based restrictions
|
||||
* @sip: the object end
|
||||
*
|
||||
* looks for host based access restrictions
|
||||
*
|
||||
* This version will only be appropriate for really small
|
||||
* sets of single label hosts. Because of the masking
|
||||
* it cannot shortcut out on the first match. There are
|
||||
* numerious ways to address the problem, but none of them
|
||||
* have been applied here.
|
||||
*
|
||||
* Returns the label of the far end or NULL if it's not special.
|
||||
*/
|
||||
static char *smack_host_label(struct sockaddr_in *sip)
|
||||
{
|
||||
struct smk_netlbladdr *snp;
|
||||
char *bestlabel = NULL;
|
||||
struct in_addr *siap = &sip->sin_addr;
|
||||
struct in_addr *liap;
|
||||
struct in_addr *miap;
|
||||
struct in_addr bestmask;
|
||||
|
||||
if (siap->s_addr == 0)
|
||||
return NULL;
|
||||
|
||||
bestmask.s_addr = 0;
|
||||
|
||||
for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
|
||||
liap = &snp->smk_host.sin_addr;
|
||||
miap = &snp->smk_mask;
|
||||
/*
|
||||
* If the addresses match after applying the list entry mask
|
||||
* the entry matches the address. If it doesn't move along to
|
||||
* the next entry.
|
||||
*/
|
||||
if ((liap->s_addr & miap->s_addr) !=
|
||||
(siap->s_addr & miap->s_addr))
|
||||
continue;
|
||||
/*
|
||||
* If the list entry mask identifies a single address
|
||||
* it can't get any more specific.
|
||||
*/
|
||||
if (miap->s_addr == 0xffffffff)
|
||||
return snp->smk_label;
|
||||
/*
|
||||
* If the list entry mask is less specific than the best
|
||||
* already found this entry is uninteresting.
|
||||
*/
|
||||
if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr)
|
||||
continue;
|
||||
/*
|
||||
* This is better than any entry found so far.
|
||||
*/
|
||||
bestmask.s_addr = miap->s_addr;
|
||||
bestlabel = snp->smk_label;
|
||||
}
|
||||
|
||||
return bestlabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_socket_connect - connect access check
|
||||
* @sock: the socket
|
||||
* @sap: the other end
|
||||
* @addrlen: size of sap
|
||||
*
|
||||
* Verifies that a connection may be possible
|
||||
*
|
||||
* Returns 0 on success, and error code otherwise
|
||||
*/
|
||||
static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
|
||||
int addrlen)
|
||||
{
|
||||
struct socket_smack *ssp = sock->sk->sk_security;
|
||||
char *hostsp;
|
||||
int rc;
|
||||
|
||||
if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
|
||||
return 0;
|
||||
|
||||
if (addrlen < sizeof(struct sockaddr_in))
|
||||
return -EINVAL;
|
||||
|
||||
hostsp = smack_host_label((struct sockaddr_in *)sap);
|
||||
if (hostsp == NULL) {
|
||||
if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2101,8 +2227,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
|
||||
if (newsmack == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* No process is ever allowed the web ("@") label.
|
||||
*/
|
||||
if (newsmack == smack_known_web.smk_known)
|
||||
return -EPERM;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
if (new == NULL)
|
||||
return -ENOMEM;
|
||||
new->security = newsmack;
|
||||
commit_creds(new);
|
||||
@@ -2143,6 +2275,49 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
|
||||
return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_socket_sendmsg - Smack check based on destination host
|
||||
* @sock: the socket
|
||||
* @msghdr: the message
|
||||
* @size: the size of the message
|
||||
*
|
||||
* Return 0 if the current subject can write to the destination
|
||||
* host. This is only a question if the destination is a single
|
||||
* label host.
|
||||
*/
|
||||
static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
int size)
|
||||
{
|
||||
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
|
||||
struct socket_smack *ssp = sock->sk->sk_security;
|
||||
char *hostsp;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Perfectly reasonable for this to be NULL
|
||||
*/
|
||||
if (sip == NULL || sip->sin_family != PF_INET)
|
||||
return 0;
|
||||
|
||||
hostsp = smack_host_label(sip);
|
||||
if (hostsp == NULL) {
|
||||
if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
|
||||
* pair to smack
|
||||
@@ -2154,44 +2329,66 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
|
||||
static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
|
||||
{
|
||||
char smack[SMK_LABELLEN];
|
||||
char *sp;
|
||||
int pcat;
|
||||
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
|
||||
/*
|
||||
* Looks like a CIPSO packet.
|
||||
* If there are flags but no level netlabel isn't
|
||||
* behaving the way we expect it to.
|
||||
*
|
||||
* Get the categories, if any
|
||||
* Without guidance regarding the smack value
|
||||
* for the packet fall back on the network
|
||||
* ambient value.
|
||||
*/
|
||||
strncpy(sip, smack_net_ambient, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Get the categories, if any
|
||||
*/
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
|
||||
for (pcat = -1;;) {
|
||||
pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat,
|
||||
pcat + 1);
|
||||
if (pcat < 0)
|
||||
break;
|
||||
smack_catset_bit(pcat, smack);
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
|
||||
for (pcat = -1;;) {
|
||||
pcat = netlbl_secattr_catmap_walk(
|
||||
sap->attr.mls.cat, pcat + 1);
|
||||
if (pcat < 0)
|
||||
break;
|
||||
smack_catset_bit(pcat, smack);
|
||||
}
|
||||
/*
|
||||
* If it is CIPSO using smack direct mapping
|
||||
* we are already done. WeeHee.
|
||||
*/
|
||||
if (sap->attr.mls.lvl == smack_cipso_direct) {
|
||||
memcpy(sip, smack, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If it is CIPSO using smack direct mapping
|
||||
* we are already done. WeeHee.
|
||||
*/
|
||||
if (sap->attr.mls.lvl == smack_cipso_direct) {
|
||||
memcpy(sip, smack, SMK_MAXLEN);
|
||||
/*
|
||||
* Look it up in the supplied table if it is not
|
||||
* a direct mapping.
|
||||
*/
|
||||
smack_from_cipso(sap->attr.mls.lvl, smack, sip);
|
||||
return;
|
||||
}
|
||||
if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
|
||||
/*
|
||||
* Looks like a fallback, which gives us a secid.
|
||||
*/
|
||||
sp = smack_from_secid(sap->attr.secid);
|
||||
/*
|
||||
* This has got to be a bug because it is
|
||||
* impossible to specify a fallback without
|
||||
* specifying the label, which will ensure
|
||||
* it has a secid, and the only way to get a
|
||||
* secid is from a fallback.
|
||||
*/
|
||||
BUG_ON(sp == NULL);
|
||||
strncpy(sip, sp, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Look it up in the supplied table if it is not a direct mapping.
|
||||
* Without guidance regarding the smack value
|
||||
* for the packet fall back on the network
|
||||
* ambient value.
|
||||
*/
|
||||
smack_from_cipso(sap->attr.mls.lvl, smack, sip);
|
||||
strncpy(sip, smack_net_ambient, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2207,6 +2404,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
struct socket_smack *ssp = sk->sk_security;
|
||||
char smack[SMK_LABELLEN];
|
||||
char *csp;
|
||||
int rc;
|
||||
|
||||
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
|
||||
@@ -2215,21 +2413,24 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||
/*
|
||||
* Translate what netlabel gave us.
|
||||
*/
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
netlbl_secattr_init(&secattr);
|
||||
|
||||
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
smack_from_secattr(&secattr, smack);
|
||||
else
|
||||
strncpy(smack, smack_net_ambient, SMK_MAXLEN);
|
||||
csp = smack;
|
||||
} else
|
||||
csp = smack_net_ambient;
|
||||
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
|
||||
/*
|
||||
* Receiving a packet requires that the other end
|
||||
* be able to write here. Read access is not required.
|
||||
* This is the simplist possible security model
|
||||
* for networking.
|
||||
*/
|
||||
rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
|
||||
rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
|
||||
if (rc != 0)
|
||||
netlbl_skbuff_err(skb, rc, 0);
|
||||
return rc;
|
||||
@@ -2298,7 +2499,6 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
||||
/*
|
||||
* Translate what netlabel gave us.
|
||||
*/
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
netlbl_secattr_init(&secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0)
|
||||
@@ -2341,7 +2541,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
||||
ssp->smk_in = ssp->smk_out = current_security();
|
||||
ssp->smk_packet[0] = '\0';
|
||||
|
||||
rc = smack_netlabel(sk);
|
||||
rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
@@ -2367,7 +2567,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||
if (skb == NULL)
|
||||
return -EACCES;
|
||||
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
netlbl_secattr_init(&skb_secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
|
||||
if (rc == 0)
|
||||
@@ -2732,6 +2931,8 @@ struct security_operations smack_ops = {
|
||||
.unix_may_send = smack_unix_may_send,
|
||||
|
||||
.socket_post_create = smack_socket_post_create,
|
||||
.socket_connect = smack_socket_connect,
|
||||
.socket_sendmsg = smack_socket_sendmsg,
|
||||
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
|
||||
.socket_getpeersec_stream = smack_socket_getpeersec_stream,
|
||||
.socket_getpeersec_dgram = smack_socket_getpeersec_dgram,
|
||||
@@ -2783,7 +2984,6 @@ static __init int smack_init(void)
|
||||
/*
|
||||
* Initialize locks
|
||||
*/
|
||||
spin_lock_init(&smack_known_unset.smk_cipsolock);
|
||||
spin_lock_init(&smack_known_huh.smk_cipsolock);
|
||||
spin_lock_init(&smack_known_hat.smk_cipsolock);
|
||||
spin_lock_init(&smack_known_star.smk_cipsolock);
|
||||
|
||||
+243
-126
@@ -20,6 +20,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <linux/seq_file.h>
|
||||
@@ -38,7 +39,7 @@ enum smk_inos {
|
||||
SMK_DOI = 5, /* CIPSO DOI */
|
||||
SMK_DIRECT = 6, /* CIPSO level indicating direct label */
|
||||
SMK_AMBIENT = 7, /* internet ambient label */
|
||||
SMK_NLTYPE = 8, /* label scheme to use by default */
|
||||
SMK_NETLBLADDR = 8, /* single label hosts */
|
||||
SMK_ONLYCAP = 9, /* the only "capable" label */
|
||||
};
|
||||
|
||||
@@ -48,6 +49,7 @@ enum smk_inos {
|
||||
static DEFINE_MUTEX(smack_list_lock);
|
||||
static DEFINE_MUTEX(smack_cipso_lock);
|
||||
static DEFINE_MUTEX(smack_ambient_lock);
|
||||
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
||||
|
||||
/*
|
||||
* This is the "ambient" label for network traffic.
|
||||
@@ -56,12 +58,6 @@ static DEFINE_MUTEX(smack_ambient_lock);
|
||||
*/
|
||||
char *smack_net_ambient = smack_known_floor.smk_known;
|
||||
|
||||
/*
|
||||
* This is the default packet marking scheme for network traffic.
|
||||
* It can be reset via smackfs/nltype
|
||||
*/
|
||||
int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
|
||||
|
||||
/*
|
||||
* This is the level in a CIPSO header that indicates a
|
||||
* smack label is contained directly in the category set.
|
||||
@@ -79,6 +75,13 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
|
||||
*/
|
||||
char *smack_onlycap;
|
||||
|
||||
/*
|
||||
* Certain IP addresses may be designated as single label hosts.
|
||||
* Packets are sent there unlabeled, but only from tasks that
|
||||
* can write to the specified label.
|
||||
*/
|
||||
struct smk_netlbladdr *smack_netlbladdrs;
|
||||
|
||||
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
||||
struct smk_list_entry *smack_list;
|
||||
|
||||
@@ -104,6 +107,24 @@ struct smk_list_entry *smack_list;
|
||||
#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
|
||||
#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
|
||||
|
||||
/**
|
||||
* smk_netlabel_audit_set - fill a netlbl_audit struct
|
||||
* @nap: structure to fill
|
||||
*/
|
||||
static void smk_netlabel_audit_set(struct netlbl_audit *nap)
|
||||
{
|
||||
nap->loginuid = audit_get_loginuid(current);
|
||||
nap->sessionid = audit_get_sessionid(current);
|
||||
nap->secid = smack_to_secid(current_security());
|
||||
}
|
||||
|
||||
/*
|
||||
* Values for parsing single label host rules
|
||||
* "1.2.3.4 X"
|
||||
* "192.168.138.129/32 abcdefghijklmnopqrstuvw"
|
||||
*/
|
||||
#define SMK_NETLBLADDRMIN 9
|
||||
#define SMK_NETLBLADDRMAX 42
|
||||
|
||||
/*
|
||||
* Seq_file read operations for /smack/load
|
||||
@@ -344,13 +365,11 @@ static void smk_cipso_doi(void)
|
||||
{
|
||||
int rc;
|
||||
struct cipso_v4_doi *doip;
|
||||
struct netlbl_audit audit_info;
|
||||
struct netlbl_audit nai;
|
||||
|
||||
audit_info.loginuid = audit_get_loginuid(current);
|
||||
audit_info.sessionid = audit_get_sessionid(current);
|
||||
audit_info.secid = smack_to_secid(current_security());
|
||||
smk_netlabel_audit_set(&nai);
|
||||
|
||||
rc = netlbl_cfg_map_del(NULL, &audit_info);
|
||||
rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "%s:%d remove rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
@@ -365,11 +384,19 @@ static void smk_cipso_doi(void)
|
||||
for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
|
||||
doip->tags[rc] = CIPSO_V4_TAG_INVALID;
|
||||
|
||||
rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
|
||||
rc = netlbl_cfg_cipsov4_add(doip, &nai);
|
||||
if (rc != 0) {
|
||||
printk(KERN_WARNING "%s:%d add rc = %d\n",
|
||||
printk(KERN_WARNING "%s:%d cipso add rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
kfree(doip);
|
||||
return;
|
||||
}
|
||||
rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai);
|
||||
if (rc != 0) {
|
||||
printk(KERN_WARNING "%s:%d map add rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
kfree(doip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,20 +406,19 @@ static void smk_cipso_doi(void)
|
||||
static void smk_unlbl_ambient(char *oldambient)
|
||||
{
|
||||
int rc;
|
||||
struct netlbl_audit audit_info;
|
||||
struct netlbl_audit nai;
|
||||
|
||||
audit_info.loginuid = audit_get_loginuid(current);
|
||||
audit_info.sessionid = audit_get_sessionid(current);
|
||||
audit_info.secid = smack_to_secid(current_security());
|
||||
smk_netlabel_audit_set(&nai);
|
||||
|
||||
if (oldambient != NULL) {
|
||||
rc = netlbl_cfg_map_del(oldambient, &audit_info);
|
||||
rc = netlbl_cfg_map_del(oldambient, PF_INET, NULL, NULL, &nai);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "%s:%d remove rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
}
|
||||
|
||||
rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info);
|
||||
rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET,
|
||||
NULL, NULL, &nai);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "%s:%d add rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
@@ -603,6 +629,201 @@ static const struct file_operations smk_cipso_ops = {
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Seq_file read operations for /smack/netlabel
|
||||
*/
|
||||
|
||||
static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
if (*pos == SEQ_READ_FINISHED)
|
||||
return NULL;
|
||||
|
||||
return smack_netlbladdrs;
|
||||
}
|
||||
|
||||
static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
|
||||
|
||||
if (skp == NULL)
|
||||
*pos = SEQ_READ_FINISHED;
|
||||
|
||||
return skp;
|
||||
}
|
||||
/*
|
||||
#define BEMASK 0x80000000
|
||||
*/
|
||||
#define BEMASK 0x00000001
|
||||
#define BEBITS (sizeof(__be32) * 8)
|
||||
|
||||
/*
|
||||
* Print host/label pairs
|
||||
*/
|
||||
static int netlbladdr_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
|
||||
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
|
||||
__be32 bebits;
|
||||
int maskn = 0;
|
||||
|
||||
for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1)
|
||||
if ((skp->smk_mask.s_addr & bebits) == 0)
|
||||
break;
|
||||
|
||||
seq_printf(s, "%u.%u.%u.%u/%d %s\n",
|
||||
hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void netlbladdr_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
/* No-op */
|
||||
}
|
||||
|
||||
static struct seq_operations netlbladdr_seq_ops = {
|
||||
.start = netlbladdr_seq_start,
|
||||
.stop = netlbladdr_seq_stop,
|
||||
.next = netlbladdr_seq_next,
|
||||
.show = netlbladdr_seq_show,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_open_netlbladdr - open() for /smack/netlabel
|
||||
* @inode: inode structure representing file
|
||||
* @file: "netlabel" file pointer
|
||||
*
|
||||
* Connect our netlbladdr_seq_* operations with /smack/netlabel
|
||||
* file_operations
|
||||
*/
|
||||
static int smk_open_netlbladdr(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &netlbladdr_seq_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_netlbladdr - write() for /smack/netlabel
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to get the data from
|
||||
* @count: bytes sent
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Accepts only one netlbladdr per write call.
|
||||
* Returns number of bytes written or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct smk_netlbladdr *skp;
|
||||
struct sockaddr_in newname;
|
||||
char smack[SMK_LABELLEN];
|
||||
char *sp;
|
||||
char data[SMK_NETLBLADDRMAX];
|
||||
char *host = (char *)&newname.sin_addr.s_addr;
|
||||
int rc;
|
||||
struct netlbl_audit audit_info;
|
||||
struct in_addr mask;
|
||||
unsigned int m;
|
||||
__be32 bebits = BEMASK;
|
||||
__be32 nsa;
|
||||
|
||||
/*
|
||||
* Must have privilege.
|
||||
* No partial writes.
|
||||
* Enough data must be present.
|
||||
* "<addr/mask, as a.b.c.d/e><space><label>"
|
||||
* "<addr, as a.b.c.d><space><label>"
|
||||
*/
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
if (*ppos != 0)
|
||||
return -EINVAL;
|
||||
if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(data, buf, count) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
data[count] = '\0';
|
||||
|
||||
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s",
|
||||
&host[0], &host[1], &host[2], &host[3], &m, smack);
|
||||
if (rc != 6) {
|
||||
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
|
||||
&host[0], &host[1], &host[2], &host[3], smack);
|
||||
if (rc != 5)
|
||||
return -EINVAL;
|
||||
m = BEBITS;
|
||||
}
|
||||
if (m > BEBITS)
|
||||
return -EINVAL;
|
||||
|
||||
sp = smk_import(smack, 0);
|
||||
if (sp == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
for (mask.s_addr = 0; m > 0; m--) {
|
||||
mask.s_addr |= bebits;
|
||||
bebits <<= 1;
|
||||
}
|
||||
/*
|
||||
* Only allow one writer at a time. Writes should be
|
||||
* quite rare and small in any case.
|
||||
*/
|
||||
mutex_lock(&smk_netlbladdr_lock);
|
||||
|
||||
nsa = newname.sin_addr.s_addr;
|
||||
for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
|
||||
if (skp->smk_host.sin_addr.s_addr == nsa &&
|
||||
skp->smk_mask.s_addr == mask.s_addr)
|
||||
break;
|
||||
|
||||
smk_netlabel_audit_set(&audit_info);
|
||||
|
||||
if (skp == NULL) {
|
||||
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
||||
if (skp == NULL)
|
||||
rc = -ENOMEM;
|
||||
else {
|
||||
rc = 0;
|
||||
skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
|
||||
skp->smk_mask.s_addr = mask.s_addr;
|
||||
skp->smk_next = smack_netlbladdrs;
|
||||
skp->smk_label = sp;
|
||||
smack_netlbladdrs = skp;
|
||||
}
|
||||
} else {
|
||||
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
|
||||
&skp->smk_host.sin_addr, &skp->smk_mask,
|
||||
PF_INET, &audit_info);
|
||||
skp->smk_label = sp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now tell netlabel about the single label nature of
|
||||
* this host so that incoming packets get labeled.
|
||||
*/
|
||||
|
||||
if (rc == 0)
|
||||
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
|
||||
&skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
|
||||
smack_to_secid(skp->smk_label), &audit_info);
|
||||
|
||||
if (rc == 0)
|
||||
rc = count;
|
||||
|
||||
mutex_unlock(&smk_netlbladdr_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations smk_netlbladdr_ops = {
|
||||
.open = smk_open_netlbladdr,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.write = smk_write_netlbladdr,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_read_doi - read() for /smack/doi
|
||||
* @filp: file pointer, not actually used
|
||||
@@ -891,110 +1112,6 @@ static const struct file_operations smk_onlycap_ops = {
|
||||
.write = smk_write_onlycap,
|
||||
};
|
||||
|
||||
struct option_names {
|
||||
int o_number;
|
||||
char *o_name;
|
||||
char *o_alias;
|
||||
};
|
||||
|
||||
static struct option_names netlbl_choices[] = {
|
||||
{ NETLBL_NLTYPE_RIPSO,
|
||||
NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
|
||||
{ NETLBL_NLTYPE_CIPSOV4,
|
||||
NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
|
||||
{ NETLBL_NLTYPE_CIPSOV4,
|
||||
NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
|
||||
{ NETLBL_NLTYPE_CIPSOV6,
|
||||
NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
|
||||
{ NETLBL_NLTYPE_UNLABELED,
|
||||
NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_read_nltype - read() for /smack/nltype
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to put the result
|
||||
* @count: maximum to send along
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Returns number of bytes read or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char bound[40];
|
||||
ssize_t rc;
|
||||
int i;
|
||||
|
||||
if (count < SMK_LABELLEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
sprintf(bound, "unknown");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
|
||||
if (smack_net_nltype == netlbl_choices[i].o_number) {
|
||||
sprintf(bound, "%s", netlbl_choices[i].o_name);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_nltype - write() for /smack/nltype
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to get the data from
|
||||
* @count: bytes sent
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Returns number of bytes written or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_write_nltype(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char bound[40];
|
||||
char *cp;
|
||||
int i;
|
||||
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (count >= 40)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(bound, buf, count) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
bound[count] = '\0';
|
||||
cp = strchr(bound, ' ');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
cp = strchr(bound, '\n');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
|
||||
if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
|
||||
strcmp(bound, netlbl_choices[i].o_alias) == 0) {
|
||||
smack_net_nltype = netlbl_choices[i].o_number;
|
||||
return count;
|
||||
}
|
||||
/*
|
||||
* Not a valid choice.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct file_operations smk_nltype_ops = {
|
||||
.read = smk_read_nltype,
|
||||
.write = smk_write_nltype,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_fill_super - fill the /smackfs superblock
|
||||
* @sb: the empty superblock
|
||||
@@ -1021,8 +1138,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_AMBIENT] =
|
||||
{"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_NLTYPE] =
|
||||
{"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_NETLBLADDR] =
|
||||
{"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_ONLYCAP] =
|
||||
{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
|
||||
/* last one */ {""}
|
||||
|
||||
Reference in New Issue
Block a user