diff options
Diffstat (limited to 'security/lsm_audit.c')
| -rw-r--r-- | security/lsm_audit.c | 196 |
1 files changed, 120 insertions, 76 deletions
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 8d8d97dbb389..7d623b00495c 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -1,14 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * common LSM auditing functions * * Based on code written for SELinux by : - * Stephen Smalley, <sds@epoch.ncsc.mil> + * Stephen Smalley * James Morris <jmorris@redhat.com> * Author : Etienne Basset, <etienne.basset@ensta.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. */ #include <linux/types.h> @@ -27,9 +24,9 @@ #include <net/ipv6.h> #include <linux/tcp.h> #include <linux/udp.h> -#include <linux/dccp.h> #include <linux/sctp.h> #include <linux/lsm_audit.h> +#include <linux/security.h> /** * ipv4_skb_to_auditdata : fill auditdata from skb @@ -46,9 +43,6 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb, struct iphdr *ih; ih = ip_hdr(skb); - if (ih == NULL) - return -EINVAL; - ad->u.net->v4info.saddr = ih->saddr; ad->u.net->v4info.daddr = ih->daddr; @@ -61,8 +55,6 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb, switch (ih->protocol) { case IPPROTO_TCP: { struct tcphdr *th = tcp_hdr(skb); - if (th == NULL) - break; ad->u.net->sport = th->source; ad->u.net->dport = th->dest; @@ -70,26 +62,14 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb, } case IPPROTO_UDP: { struct udphdr *uh = udp_hdr(skb); - if (uh == NULL) - break; ad->u.net->sport = uh->source; ad->u.net->dport = uh->dest; break; } - case IPPROTO_DCCP: { - struct dccp_hdr *dh = dccp_hdr(skb); - if (dh == NULL) - break; - - ad->u.net->sport = dh->dccph_sport; - ad->u.net->dport = dh->dccph_dport; - break; - } case IPPROTO_SCTP: { struct sctphdr *sh = sctp_hdr(skb); - if (sh == NULL) - break; + ad->u.net->sport = sh->source; ad->u.net->dport = sh->dest; break; @@ -99,7 +79,7 @@ int ipv4_skb_to_auditdata(struct sk_buff *skb, } return ret; } -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6) /** * ipv6_skb_to_auditdata : fill auditdata from skb * @skb : the skb @@ -117,11 +97,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb, __be16 frag_off; ip6 = ipv6_hdr(skb); - if (ip6 == NULL) - return -EINVAL; ad->u.net->v6info.saddr = ip6->saddr; ad->u.net->v6info.daddr = ip6->daddr; - ret = 0; /* IPv6 can have several extension header before the Transport header * skip them */ offset = skb_network_offset(skb); @@ -155,17 +132,6 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb, ad->u.net->dport = uh->dest; break; } - case IPPROTO_DCCP: { - struct dccp_hdr _dccph, *dh; - - dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); - if (dh == NULL) - break; - - ad->u.net->sport = dh->dccph_sport; - ad->u.net->dport = dh->dccph_dport; - break; - } case IPPROTO_SCTP: { struct sctphdr _sctph, *sh; @@ -185,8 +151,8 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb, static inline void print_ipv6_addr(struct audit_buffer *ab, - struct in6_addr *addr, __be16 port, - char *name1, char *name2) + const struct in6_addr *addr, __be16 port, + const char *name1, const char *name2) { if (!ipv6_addr_any(addr)) audit_log_format(ab, " %s=%pI6c", name1, addr); @@ -195,7 +161,7 @@ static inline void print_ipv6_addr(struct audit_buffer *ab, } static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, - __be16 port, char *name1, char *name2) + __be16 port, const char *name1, const char *name2) { if (addr) audit_log_format(ab, " %s=%pI4", name1, &addr); @@ -204,30 +170,25 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, } /** - * dump_common_audit_data - helper to dump common audit data + * audit_log_lsm_data - helper to log common LSM audit data + * @ab : the audit buffer * @a : common audit data - * */ -static void dump_common_audit_data(struct audit_buffer *ab, - struct common_audit_data *a) +void audit_log_lsm_data(struct audit_buffer *ab, + const struct common_audit_data *a) { - struct task_struct *tsk = current; - /* - * To keep stack sizes in check force programers to notice if they + * To keep stack sizes in check force programmers to notice if they * start making this union too large! See struct lsm_network_audit * as an example of how to deal with large data. */ BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2); - audit_log_format(ab, " pid=%d comm=", tsk->pid); - audit_log_untrustedstring(ab, tsk->comm); - switch (a->type) { case LSM_AUDIT_DATA_NONE: return; case LSM_AUDIT_DATA_IPC: - audit_log_format(ab, " key=%d ", a->u.ipc_id); + audit_log_format(ab, " ipc_key=%d ", a->u.ipc_id); break; case LSM_AUDIT_DATA_CAP: audit_log_format(ab, " capability=%d ", a->u.cap); @@ -237,21 +198,51 @@ static void dump_common_audit_data(struct audit_buffer *ab, audit_log_d_path(ab, " path=", &a->u.path); - inode = a->u.path.dentry->d_inode; + inode = d_backing_inode(a->u.path.dentry); + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } + break; + } + case LSM_AUDIT_DATA_FILE: { + struct inode *inode; + + audit_log_d_path(ab, " path=", &a->u.file->f_path); + + inode = file_inode(a->u.file); + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } + break; + } + case LSM_AUDIT_DATA_IOCTL_OP: { + struct inode *inode; + + audit_log_d_path(ab, " path=", &a->u.op->path); + + inode = a->u.op->path.dentry->d_inode; if (inode) { audit_log_format(ab, " dev="); audit_log_untrustedstring(ab, inode->i_sb->s_id); audit_log_format(ab, " ino=%lu", inode->i_ino); } + + audit_log_format(ab, " ioctlcmd=0x%hx", a->u.op->cmd); break; } case LSM_AUDIT_DATA_DENTRY: { struct inode *inode; audit_log_format(ab, " name="); + spin_lock(&a->u.dentry->d_lock); audit_log_untrustedstring(ab, a->u.dentry->d_name.name); + spin_unlock(&a->u.dentry->d_lock); - inode = a->u.dentry->d_inode; + inode = d_backing_inode(a->u.dentry); if (inode) { audit_log_format(ab, " dev="); audit_log_untrustedstring(ab, inode->i_sb->s_id); @@ -263,36 +254,45 @@ static void dump_common_audit_data(struct audit_buffer *ab, struct dentry *dentry; struct inode *inode; + rcu_read_lock(); inode = a->u.inode; - dentry = d_find_alias(inode); + dentry = d_find_alias_rcu(inode); if (dentry) { audit_log_format(ab, " name="); - audit_log_untrustedstring(ab, - dentry->d_name.name); - dput(dentry); + spin_lock(&dentry->d_lock); + audit_log_untrustedstring(ab, dentry->d_name.name); + spin_unlock(&dentry->d_lock); } audit_log_format(ab, " dev="); audit_log_untrustedstring(ab, inode->i_sb->s_id); audit_log_format(ab, " ino=%lu", inode->i_ino); + rcu_read_unlock(); break; } - case LSM_AUDIT_DATA_TASK: - tsk = a->u.tsk; - if (tsk && tsk->pid) { - audit_log_format(ab, " pid=%d comm=", tsk->pid); - audit_log_untrustedstring(ab, tsk->comm); + case LSM_AUDIT_DATA_TASK: { + struct task_struct *tsk = a->u.tsk; + if (tsk) { + pid_t pid = task_tgid_nr(tsk); + if (pid) { + char tskcomm[sizeof(tsk->comm)]; + audit_log_format(ab, " opid=%d ocomm=", pid); + audit_log_untrustedstring(ab, + get_task_comm(tskcomm, tsk)); + } } break; + } case LSM_AUDIT_DATA_NET: if (a->u.net->sk) { - struct sock *sk = a->u.net->sk; - struct unix_sock *u; + const struct sock *sk = a->u.net->sk; + const struct unix_sock *u; + struct unix_address *addr; int len = 0; char *p = NULL; switch (sk->sk_family) { case AF_INET: { - struct inet_sock *inet = inet_sk(sk); + const struct inet_sock *inet = inet_sk(sk); print_ipv4_addr(ab, inet->inet_rcv_saddr, inet->inet_sport, @@ -302,28 +302,30 @@ static void dump_common_audit_data(struct audit_buffer *ab, "faddr", "fport"); break; } +#if IS_ENABLED(CONFIG_IPV6) case AF_INET6: { - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *inet6 = inet6_sk(sk); + const struct inet_sock *inet = inet_sk(sk); - print_ipv6_addr(ab, &inet6->rcv_saddr, + print_ipv6_addr(ab, &sk->sk_v6_rcv_saddr, inet->inet_sport, "laddr", "lport"); - print_ipv6_addr(ab, &inet6->daddr, + print_ipv6_addr(ab, &sk->sk_v6_daddr, inet->inet_dport, "faddr", "fport"); break; } +#endif case AF_UNIX: u = unix_sk(sk); + addr = smp_load_acquire(&u->addr); + if (!addr) + break; if (u->path.dentry) { audit_log_d_path(ab, " path=", &u->path); break; } - if (!u->addr) - break; - len = u->addr->len-sizeof(short); - p = &u->addr->name->sun_path[0]; + len = addr->len-sizeof(short); + p = &addr->name->sun_path[0]; audit_log_format(ab, " path="); if (*p) audit_log_untrustedstring(ab, p); @@ -375,10 +377,51 @@ static void dump_common_audit_data(struct audit_buffer *ab, audit_log_format(ab, " kmod="); audit_log_untrustedstring(ab, a->u.kmod_name); break; + case LSM_AUDIT_DATA_IBPKEY: { + struct in6_addr sbn_pfx; + + memset(&sbn_pfx.s6_addr, 0, + sizeof(sbn_pfx.s6_addr)); + memcpy(&sbn_pfx.s6_addr, &a->u.ibpkey->subnet_prefix, + sizeof(a->u.ibpkey->subnet_prefix)); + audit_log_format(ab, " pkey=0x%x subnet_prefix=%pI6c", + a->u.ibpkey->pkey, &sbn_pfx); + break; + } + case LSM_AUDIT_DATA_IBENDPORT: + audit_log_format(ab, " device=%s port_num=%u", + a->u.ibendport->dev_name, + a->u.ibendport->port); + break; + case LSM_AUDIT_DATA_LOCKDOWN: + audit_log_format(ab, " lockdown_reason=\"%s\"", + lockdown_reasons[a->u.reason]); + break; + case LSM_AUDIT_DATA_ANONINODE: + audit_log_format(ab, " anonclass=%s", a->u.anonclass); + break; + case LSM_AUDIT_DATA_NLMSGTYPE: + audit_log_format(ab, " nl-msgtype=%hu", a->u.nlmsg_type); + break; } /* switch (a->type) */ } /** + * dump_common_audit_data - helper to dump common audit data + * @ab : the audit buffer + * @a : common audit data + */ +static void dump_common_audit_data(struct audit_buffer *ab, + const struct common_audit_data *a) +{ + char comm[sizeof(current->comm)]; + + audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current)); + audit_log_untrustedstring(ab, get_task_comm(comm, current)); + audit_log_lsm_data(ab, a); +} + +/** * common_lsm_audit - generic LSM auditing function * @a: auxiliary audit data * @pre_audit: lsm-specific pre-audit callback @@ -396,7 +439,8 @@ void common_lsm_audit(struct common_audit_data *a, if (a == NULL) return; /* we use GFP_ATOMIC so we won't sleep */ - ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); + ab = audit_log_start(audit_context(), GFP_ATOMIC | __GFP_NOWARN, + AUDIT_AVC); if (ab == NULL) return; |
