@@ -1358,7 +1358,8 @@ int security_socket_shutdown(struct socket *sock, int how);
int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len);
-int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid);
+int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
+ struct lsmblob *blob);
int security_sk_alloc(struct sock *sk, int family, gfp_t priority);
void security_sk_free(struct sock *sk);
void security_sk_clone(const struct sock *sk, struct sock *newsk);
@@ -1496,7 +1497,9 @@ static inline int security_socket_getpeersec_stream(struct socket *sock, char __
return -ENOPROTOOPT;
}
-static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+static inline int security_socket_getpeersec_dgram(struct socket *sock,
+ struct sk_buff *skb,
+ struct lsmblob *blob)
{
return -ENOPROTOOPT;
}
@@ -36,7 +36,7 @@ struct unix_skb_parms {
kgid_t gid;
struct scm_fp_list *fp; /* Passed files */
#ifdef CONFIG_SECURITY_NETWORK
- u32 secid; /* Security ID */
+ struct lsmblob *lsmdata; /* Security LSM data */
#endif
u32 consumed;
} __randomize_layout;
@@ -33,7 +33,7 @@ struct scm_cookie {
struct scm_fp_list *fp; /* Passed files */
struct scm_creds creds; /* Skb credentials */
#ifdef CONFIG_SECURITY_NETWORK
- u32 secid; /* Passed security ID */
+ struct lsmblob lsmblob; /* Passed LSM data */
#endif
};
@@ -46,7 +46,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
#ifdef CONFIG_SECURITY_NETWORK
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
{
- security_socket_getpeersec_dgram(sock, NULL, &scm->secid);
+ security_socket_getpeersec_dgram(sock, NULL, &scm->lsmblob);
}
#else
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -97,7 +97,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
int err;
if (test_bit(SOCK_PASSSEC, &sock->flags)) {
- err = security_secid_to_secctx(scm->secid, &secdata, &seclen);
+ /* Scaffolding - it has to be element 0 for now */
+ err = security_secid_to_secctx(scm->lsmblob.secid[0],
+ &secdata, &seclen);
if (!err) {
put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata);
@@ -130,15 +130,17 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
{
+ struct lsmblob lb;
char *secdata;
- u32 seclen, secid;
+ u32 seclen;
int err;
- err = security_socket_getpeersec_dgram(NULL, skb, &secid);
+ err = security_socket_getpeersec_dgram(NULL, skb, &lb);
if (err)
return;
- err = security_secid_to_secctx(secid, &secdata, &seclen);
+ /* Scaffolding - it has to be element 0 */
+ err = security_secid_to_secctx(lb.secid[0], &secdata, &seclen);
if (err)
return;
@@ -138,17 +138,18 @@ static struct hlist_head *unix_sockets_unbound(void *addr)
#ifdef CONFIG_SECURITY_NETWORK
static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
{
- UNIXCB(skb).secid = scm->secid;
+ UNIXCB(skb).lsmdata = kmemdup(&scm->lsmblob, sizeof(scm->lsmblob),
+ GFP_KERNEL);
}
static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
{
- scm->secid = UNIXCB(skb).secid;
+ scm->lsmblob = *(UNIXCB(skb).lsmdata);
}
static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb)
{
- return (scm->secid == UNIXCB(skb).secid);
+ return lsmblob_equal(&scm->lsmblob, UNIXCB(skb).lsmdata);
}
#else
static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb)
@@ -142,6 +142,12 @@ void unix_destruct_scm(struct sk_buff *skb)
scm.pid = UNIXCB(skb).pid;
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
+#ifdef CONFIG_SECURITY_NETWORK
+ if (UNIXCB(skb).lsmdata) {
+ kfree(UNIXCB(skb).lsmdata);
+ UNIXCB(skb).lsmdata = NULL;
+ }
+#endif
/* Alas, it calls VFS */
/* So fscking what? fput() had been SMP-safe since the last Summer */
@@ -2140,10 +2140,22 @@ int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
optval, optlen, len);
}
-int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
+ struct lsmblob *blob)
{
- return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
- skb, secid);
+ struct security_hook_list *hp;
+ int rc = -ENOPROTOOPT;
+
+ hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram,
+ list) {
+ if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+ continue;
+ rc = hp->hook.socket_getpeersec_dgram(sock, skb,
+ &blob->secid[hp->lsmid->slot]);
+ if (rc != 0)
+ break;
+ }
+ return rc;
}
EXPORT_SYMBOL(security_socket_getpeersec_dgram);
Change the data used in UDS SO_PEERSEC processing from a secid to a more general struct lsmblob. Update the security_socket_getpeersec_dgram() interface to use the lsmblob. There is a small amount of scaffolding code that will come out when the security_secid_to_secctx() code is brought in line with the lsmblob. The secid field of the unix_skb_parms structure has been replaced with a pointer to an lsmblob structure, and the lsmblob is allocated as needed. This is similar to how the list of passed files is managed. While an lsmblob structure will fit in the available space today, there is no guarantee that the addition of other data to the unix_skb_parms or support for additional security modules wouldn't exceed what is available. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> cc: netdev@vger.kernel.org --- include/linux/security.h | 7 +++++-- include/net/af_unix.h | 2 +- include/net/scm.h | 8 +++++--- net/ipv4/ip_sockglue.c | 8 +++++--- net/unix/af_unix.c | 7 ++++--- net/unix/scm.c | 6 ++++++ security/security.c | 18 +++++++++++++++--- 7 files changed, 41 insertions(+), 15 deletions(-)