static void scan_children(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) { if (x->sk_state != TCP_LISTEN) scan_inflight(x, func, hitlist); else { struct sk_buff *skb; struct sk_buff *next; struct unix_sock *u; LIST_HEAD(embryos); /* * For a listening socket collect the queued embryos * and perform a scan on them as well. */ spin_lock(&x->sk_receive_queue.lock); receive_queue_for_each_skb(x, next, skb) { u = unix_sk(skb->sk); /* * An embryo cannot be in-flight, so it's safe * to use the list link. */ BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &embryos); } spin_unlock(&x->sk_receive_queue.lock); while (!list_empty(&embryos)) { u = list_entry(embryos.next, struct unix_sock, link); scan_inflight(&u->sk, func, hitlist); list_del_init(&u->link); } }
static int fixup_unix_address(struct socket *sock, struct cpt_sock_image *si, struct cpt_context *ctx) { struct sock *sk = sock->sk; cpt_object_t *obj; struct sock *parent; if (sk->sk_family != AF_UNIX || sk->sk_state == TCP_LISTEN) return 0; if (si->cpt_parent == -1) return bind_unix_socket(sock, si, ctx); obj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx); if (!obj) return 0; parent = obj->o_obj; if (unix_sk(parent)->addr) { if (unix_sk(sk)->addr && atomic_dec_and_test(&unix_sk(sk)->addr->refcnt)) kfree(unix_sk(sk)->addr); atomic_inc(&unix_sk(parent)->addr->refcnt); unix_sk(sk)->addr = unix_sk(parent)->addr; } return 0; }
static void audit_unix_sk_addr(struct audit_buffer *ab, const char *str, struct sock *sk) { struct unix_sock *u = unix_sk(sk); if (u && u->addr) audit_unix_addr(ab, str, u->addr->name, u->addr->len); else audit_unix_addr(ab, str, NULL, 0); }
void unix_notinflight(struct file *fp) { struct sock *s = unix_get_socket(fp); if (s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); BUG_ON(list_empty(&u->link)); if (atomic_long_dec_and_test(&u->inflight)) list_del_init(&u->link); unix_tot_inflight--; spin_unlock(&unix_gc_lock); } }
void unix_inflight(struct file *fp) { struct sock *s = unix_get_socket(fp); if (s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); if (atomic_long_inc_return(&u->inflight) == 1) { BUG_ON(!list_empty(&u->link)); list_add_tail(&u->link, &gc_inflight_list); } else { BUG_ON(list_empty(&u->link)); } unix_tot_inflight++; spin_unlock(&unix_gc_lock); } }
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) { struct sk_buff *skb; struct sk_buff *next; spin_lock(&x->sk_receive_queue.lock); receive_queue_for_each_skb(x, next, skb) { /* * Do we have file descriptors ? */ if (UNIXCB(skb).fp) { bool hit = false; /* * Process the descriptors of this socket */ int nfd = UNIXCB(skb).fp->count; struct file **fp = UNIXCB(skb).fp->fp; while (nfd--) { /* * Get the socket the fd matches * if it indeed does so */ struct sock *sk = unix_get_socket(*fp++); if (sk) { struct unix_sock *u = unix_sk(sk); /* * Ignore non-candidates, they could * have been added to the queues after * starting the garbage collection */ if (u->gc_candidate) { hit = true; func(u); } } } if (hit && hitlist != NULL) { __skb_unlink(skb, &x->sk_receive_queue); __skb_queue_tail(hitlist, skb); } } } spin_unlock(&x->sk_receive_queue.lock); }
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), struct sk_buff_head *hitlist) { struct sk_buff *skb; struct sk_buff *next; spin_lock(&x->sk_receive_queue.lock); receive_queue_for_each_skb(x, next, skb) { /* * Do we have file descriptors ? */ if (UNIXCB(skb).fp) { bool hit = false; /* * Process the descriptors of this socket */ int nfd = UNIXCB(skb).fp->count; struct file **fp = UNIXCB(skb).fp->fp; while (nfd--) { /* * Get the socket the fd matches * if it indeed does so */ struct sock *sk = unix_get_socket(*fp++); if (sk) { hit = true; func(unix_sk(sk)); } } if (hit && hitlist != NULL) { __skb_unlink(skb, &x->sk_receive_queue); __skb_queue_tail(hitlist, skb); } } } spin_unlock(&x->sk_receive_queue.lock); }
/** * dump_common_audit_data - helper to dump common audit data * @a : common audit data * */ static void dump_common_audit_data(struct audit_buffer *ab, struct common_audit_data *a) { struct task_struct *tsk = current; /* * To keep stack sizes in check force programers 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); audit_log_format(ab, " ppid=%d ppid_comm=", tsk->real_parent->pid); audit_log_untrustedstring(ab, tsk->real_parent->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); break; case LSM_AUDIT_DATA_CAP: audit_log_format(ab, " capability=%d ", a->u.cap); break; case LSM_AUDIT_DATA_PATH: { struct inode *inode; audit_log_d_path(ab, " path=", &a->u.path); inode = a->u.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); } 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=%hx", a->u.op->cmd); break; } case LSM_AUDIT_DATA_DENTRY: { struct inode *inode; audit_log_format(ab, " name="); audit_log_untrustedstring(ab, a->u.dentry->d_name.name); inode = a->u.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); } break; } case LSM_AUDIT_DATA_INODE: { struct dentry *dentry; struct inode *inode; inode = a->u.inode; dentry = d_find_alias(inode); if (dentry) { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, dentry->d_name.name); dput(dentry); } 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_TASK: tsk = a->u.tsk; if (tsk && tsk->pid) { audit_log_format(ab, " pid=%d comm=", tsk->pid); audit_log_untrustedstring(ab, tsk->comm); } break; case LSM_AUDIT_DATA_NET: if (a->u.net->sk) { struct sock *sk = a->u.net->sk; struct unix_sock *u; int len = 0; char *p = NULL; switch (sk->sk_family) { case AF_INET: { struct inet_sock *inet = inet_sk(sk); print_ipv4_addr(ab, inet->inet_rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv4_addr(ab, inet->inet_daddr, inet->inet_dport, "faddr", "fport"); break; } case AF_INET6: { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *inet6 = inet6_sk(sk); print_ipv6_addr(ab, &inet6->rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv6_addr(ab, &inet6->daddr, inet->inet_dport, "faddr", "fport"); break; } case AF_UNIX: u = unix_sk(sk); 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]; audit_log_format(ab, " path="); if (*p) audit_log_untrustedstring(ab, p); else audit_log_n_hex(ab, p, len); break; } } switch (a->u.net->family) { case AF_INET: print_ipv4_addr(ab, a->u.net->v4info.saddr, a->u.net->sport, "saddr", "src"); print_ipv4_addr(ab, a->u.net->v4info.daddr, a->u.net->dport, "daddr", "dest"); break; case AF_INET6: print_ipv6_addr(ab, &a->u.net->v6info.saddr, a->u.net->sport, "saddr", "src"); print_ipv6_addr(ab, &a->u.net->v6info.daddr, a->u.net->dport, "daddr", "dest"); break; } if (a->u.net->netif > 0) { struct net_device *dev; /* NOTE: we always use init's namespace */ dev = dev_get_by_index(&init_net, a->u.net->netif); if (dev) { audit_log_format(ab, " netif=%s", dev->name); dev_put(dev); } } break; #ifdef CONFIG_KEYS case LSM_AUDIT_DATA_KEY: audit_log_format(ab, " key_serial=%u", a->u.key_struct.key); if (a->u.key_struct.key_desc) { audit_log_format(ab, " key_desc="); audit_log_untrustedstring(ab, a->u.key_struct.key_desc); } break; #endif case LSM_AUDIT_DATA_KMOD: audit_log_format(ab, " kmod="); audit_log_untrustedstring(ab, a->u.kmod_name); break; } /* switch (a->type) */ }
/* * Convert a connection tuple into our tuple representation and copy it to * targetbuf */ u16 fd_to_socktuple(int fd, struct sockaddr *usrsockaddr, int ulen, bool use_userdata, bool is_inbound, char *targetbuf, u16 targetbufsize) { struct socket *sock; int err = 0; sa_family_t family; struct unix_sock *us; char *us_name; struct sock *speer; u32 sip; u32 dip; u8 *sip6; u8 *dip6; u16 sport; u16 dport; struct sockaddr_in *usrsockaddr_in; struct sockaddr_in6 *usrsockaddr_in6; struct sockaddr_un *usrsockaddr_un; u16 size; char *dest; struct sockaddr_storage sock_address; struct sockaddr_storage peer_address; int sock_address_len; int peer_address_len; /* * Get the socket from the fd * NOTE: sockfd_lookup() locks the socket, so we don't need to worry when we dig in it */ sock = sockfd_lookup(fd, &err); if (unlikely(!sock || !(sock->sk))) { /* * This usually happens if the call failed without being able to establish a connection, * i.e. if it didn't return something like SE_EINPROGRESS. */ if (sock) sockfd_put(sock); return 0; } err = sock->ops->getname(sock, (struct sockaddr *)&sock_address, &sock_address_len, 0); ASSERT(err == 0); family = sock->sk->sk_family; /* * Extract and pack the info, based on the family */ switch (family) { case AF_INET: if (!use_userdata) { err = sock->ops->getname(sock, (struct sockaddr *)&peer_address, &peer_address_len, 1); ASSERT(err == 0); if (is_inbound) { sip = ((struct sockaddr_in *) &peer_address)->sin_addr.s_addr; sport = ntohs(((struct sockaddr_in *) &peer_address)->sin_port); dip = ((struct sockaddr_in *) &sock_address)->sin_addr.s_addr; dport = ntohs(((struct sockaddr_in *) &sock_address)->sin_port); } else { sip = ((struct sockaddr_in *) &sock_address)->sin_addr.s_addr; sport = ntohs(((struct sockaddr_in *) &sock_address)->sin_port); dip = ((struct sockaddr_in *) &peer_address)->sin_addr.s_addr; dport = ntohs(((struct sockaddr_in *) &peer_address)->sin_port); } } else { /* * Map the user-provided address to a sockaddr_in */ usrsockaddr_in = (struct sockaddr_in *)usrsockaddr; if (is_inbound) { sip = usrsockaddr_in->sin_addr.s_addr; sport = ntohs(usrsockaddr_in->sin_port); dip = ((struct sockaddr_in *) &sock_address)->sin_addr.s_addr; dport = ntohs(((struct sockaddr_in *) &sock_address)->sin_port); } else { sip = ((struct sockaddr_in *) &sock_address)->sin_addr.s_addr; sport = ntohs(((struct sockaddr_in *) &sock_address)->sin_port); dip = usrsockaddr_in->sin_addr.s_addr; dport = ntohs(usrsockaddr_in->sin_port); } } /* * Pack the tuple info in the temporary buffer */ size = 1 + 4 + 4 + 2 + 2; /* family + sip + dip + sport + dport */ *targetbuf = socket_family_to_scap(family); *(u32 *)(targetbuf + 1) = sip; *(u16 *)(targetbuf + 5) = sport; *(u32 *)(targetbuf + 7) = dip; *(u16 *)(targetbuf + 11) = dport; break; case AF_INET6: if (!use_userdata) { err = sock->ops->getname(sock, (struct sockaddr *)&peer_address, &peer_address_len, 1); ASSERT(err == 0); if (is_inbound) { sip6 = ((struct sockaddr_in6 *) &peer_address)->sin6_addr.s6_addr; sport = ntohs(((struct sockaddr_in6 *) &peer_address)->sin6_port); dip6 = ((struct sockaddr_in6 *) &sock_address)->sin6_addr.s6_addr; dport = ntohs(((struct sockaddr_in6 *) &sock_address)->sin6_port); } else { sip6 = ((struct sockaddr_in6 *) &sock_address)->sin6_addr.s6_addr; sport = ntohs(((struct sockaddr_in6 *) &sock_address)->sin6_port); dip6 = ((struct sockaddr_in6 *) &peer_address)->sin6_addr.s6_addr; dport = ntohs(((struct sockaddr_in6 *) &peer_address)->sin6_port); } } else { /* * Map the user-provided address to a sockaddr_in6 */ usrsockaddr_in6 = (struct sockaddr_in6 *)usrsockaddr; if (is_inbound) { sip6 = usrsockaddr_in6->sin6_addr.s6_addr; sport = ntohs(usrsockaddr_in6->sin6_port); dip6 = ((struct sockaddr_in6 *) &sock_address)->sin6_addr.s6_addr; dport = ntohs(((struct sockaddr_in6 *) &sock_address)->sin6_port); } else { sip6 = ((struct sockaddr_in6 *) &sock_address)->sin6_addr.s6_addr; sport = ntohs(((struct sockaddr_in6 *) &sock_address)->sin6_port); dip6 = usrsockaddr_in6->sin6_addr.s6_addr; dport = ntohs(usrsockaddr_in6->sin6_port); } } /* * Pack the tuple info in the temporary buffer */ size = 1 + 16 + 16 + 2 + 2; /* family + sip + dip + sport + dport */ *targetbuf = socket_family_to_scap(family); memcpy(targetbuf + 1, sip6, 16); *(u16 *)(targetbuf + 17) = sport; memcpy(targetbuf + 19, dip6, 16); *(u16 *)(targetbuf + 35) = dport; break; case AF_UNIX: /* * Retrieve the addresses */ us = unix_sk(sock->sk); speer = us->peer; *targetbuf = socket_family_to_scap(family); if (is_inbound) { *(uint64_t *)(targetbuf + 1) = (uint64_t)(unsigned long)us; *(uint64_t *)(targetbuf + 1 + 8) = (uint64_t)(unsigned long)speer; } else { *(uint64_t *)(targetbuf + 1) = (uint64_t)(unsigned long)speer; *(uint64_t *)(targetbuf + 1 + 8) = (uint64_t)(unsigned long)us; } /* * Pack the data into the target buffer */ size = 1 + 8 + 8; if (!use_userdata) { if (is_inbound) { us_name = ((struct sockaddr_un *) &sock_address)->sun_path; } else { err = sock->ops->getname(sock, (struct sockaddr *)&peer_address, &peer_address_len, 1); ASSERT(err == 0); us_name = ((struct sockaddr_un *) &peer_address)->sun_path; } } else { /* * Map the user-provided address to a sockaddr_in */ usrsockaddr_un = (struct sockaddr_un *)usrsockaddr; /* * Put a 0 at the end of struct sockaddr_un because * the user might not have considered it in the length */ if (ulen == sizeof(struct sockaddr_storage)) *(((char *)usrsockaddr_un) + ulen - 1) = 0; else *(((char *)usrsockaddr_un) + ulen) = 0; if (is_inbound) us_name = ((struct sockaddr_un *) &sock_address)->sun_path; else us_name = usrsockaddr_un->sun_path; } ASSERT(us_name); dest = strncpy(targetbuf + 1 + 8 + 8, (char *)us_name, UNIX_PATH_MAX); /* we assume this will be smaller than (targetbufsize - (1 + 8 + 8)) */ dest[UNIX_PATH_MAX - 1] = 0; size += strlen(dest) + 1; break; default: size = 0; break; } /* * Digging finished. We can release the fd. */ sockfd_put(sock); return size; }
/** * dump_common_audit_data - helper to dump common audit data * @a : common audit data * */ static void dump_common_audit_data(struct audit_buffer *ab, struct common_audit_data *a) { struct task_struct *tsk = current; if (a->tsk) tsk = a->tsk; if (tsk && tsk->pid) { 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); break; case LSM_AUDIT_DATA_CAP: audit_log_format(ab, " capability=%d ", a->u.cap); break; case LSM_AUDIT_DATA_PATH: { struct inode *inode; audit_log_d_path(ab, " path=", &a->u.path); inode = a->u.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); } break; } case LSM_AUDIT_DATA_DENTRY: { struct inode *inode; audit_log_format(ab, " name="); audit_log_untrustedstring(ab, a->u.dentry->d_name.name); inode = a->u.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); } break; } case LSM_AUDIT_DATA_INODE: { struct dentry *dentry; struct inode *inode; inode = a->u.inode; dentry = d_find_alias(inode); if (dentry) { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, dentry->d_name.name); dput(dentry); } 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_TASK: tsk = a->u.tsk; if (tsk && tsk->pid) { audit_log_format(ab, " pid=%d comm=", tsk->pid); audit_log_untrustedstring(ab, tsk->comm); } break; case LSM_AUDIT_DATA_NET: if (a->u.net.sk) { struct sock *sk = a->u.net.sk; struct unix_sock *u; int len = 0; char *p = NULL; switch (sk->sk_family) { case AF_INET: { struct inet_sock *inet = inet_sk(sk); print_ipv4_addr(ab, inet->inet_rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv4_addr(ab, inet->inet_daddr, inet->inet_dport, "faddr", "fport"); break; } case AF_INET6: { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *inet6 = inet6_sk(sk); print_ipv6_addr(ab, &inet6->rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv6_addr(ab, &inet6->daddr, inet->inet_dport, "faddr", "fport"); break; } case AF_UNIX: u = unix_sk(sk); if (u->dentry) { struct path path = { .dentry = u->dentry, .mnt = u->mnt }; audit_log_d_path(ab, " path=", &path); break; } if (!u->addr) break; len = u->addr->len-sizeof(short); p = &u->addr->name->sun_path[0]; audit_log_format(ab, " path="); if (*p) audit_log_untrustedstring(ab, p); else audit_log_n_hex(ab, p, len); break; } } switch (a->u.net.family) { case AF_INET: print_ipv4_addr(ab, a->u.net.v4info.saddr, a->u.net.sport, "saddr", "src"); print_ipv4_addr(ab, a->u.net.v4info.daddr, a->u.net.dport, "daddr", "dest"); break; case AF_INET6: print_ipv6_addr(ab, &a->u.net.v6info.saddr, a->u.net.sport, "saddr", "src"); print_ipv6_addr(ab, &a->u.net.v6info.daddr, a->u.net.dport, "daddr", "dest"); break; } if (a->u.net.netif > 0) { struct net_device *dev; /* NOTE: we always use init's namespace */ dev = dev_get_by_index(&init_net, a->u.net.netif); if (dev) { audit_log_format(ab, " netif=%s", dev->name); dev_put(dev); } } break; #ifdef CONFIG_KEYS case LSM_AUDIT_DATA_KEY: audit_log_format(ab, " key_serial=%u", a->u.key_struct.key); if (a->u.key_struct.key_desc) { audit_log_format(ab, " key_desc="); audit_log_untrustedstring(ab, a->u.key_struct.key_desc); } break; #endif case LSM_AUDIT_DATA_KMOD: audit_log_format(ab, " kmod="); audit_log_untrustedstring(ab, a->u.kmod_name); break; } /* switch (a->type) */ } /** * common_lsm_audit - generic LSM auditing function * @a: auxiliary audit data * * setup the audit buffer for common security information * uses callback to print LSM specific information */ void common_lsm_audit(struct common_audit_data *a) { struct audit_buffer *ab; if (a == NULL) return; /* we use GFP_ATOMIC so we won't sleep */ ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); if (ab == NULL) return; if (a->lsm_pre_audit) a->lsm_pre_audit(ab, a); dump_common_audit_data(ab, a); if (a->lsm_post_audit) a->lsm_post_audit(ab, a); audit_log_end(ab); }
/** * dump_common_audit_data - helper to dump common audit data * @a : common audit data * */ static void dump_common_audit_data(struct audit_buffer *ab, struct common_audit_data *a) { char comm[sizeof(current->comm)]; /* * To keep stack sizes in check force programers 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=", task_tgid_nr(current)); audit_log_untrustedstring(ab, memcpy(comm, current->comm, sizeof(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); break; case LSM_AUDIT_DATA_CAP: audit_log_format(ab, " capability=%d ", a->u.cap); break; case LSM_AUDIT_DATA_PATH: { struct inode *inode; audit_log_d_path(ab, " path=", &a->u.path); 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="); audit_log_untrustedstring(ab, a->u.dentry->d_name.name); inode = d_backing_inode(a->u.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_INODE: { struct dentry *dentry; struct inode *inode; inode = a->u.inode; dentry = d_find_alias(inode); if (dentry) { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, dentry->d_name.name); dput(dentry); } 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_TASK: { struct task_struct *tsk = a->u.tsk; if (tsk) { pid_t pid = task_tgid_nr(tsk); if (pid) { char comm[sizeof(tsk->comm)]; audit_log_format(ab, " opid=%d ocomm=", pid); audit_log_untrustedstring(ab, memcpy(comm, tsk->comm, sizeof(comm))); } } break; } case LSM_AUDIT_DATA_NET: if (a->u.net->sk) { struct sock *sk = a->u.net->sk; 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); print_ipv4_addr(ab, inet->inet_rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv4_addr(ab, inet->inet_daddr, inet->inet_dport, "faddr", "fport"); break; } #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: { struct inet_sock *inet = inet_sk(sk); print_ipv6_addr(ab, &sk->sk_v6_rcv_saddr, inet->inet_sport, "laddr", "lport"); 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; } len = addr->len-sizeof(short); p = &addr->name->sun_path[0]; audit_log_format(ab, " path="); if (*p) audit_log_untrustedstring(ab, p); else audit_log_n_hex(ab, p, len); break; } } switch (a->u.net->family) { case AF_INET: print_ipv4_addr(ab, a->u.net->v4info.saddr, a->u.net->sport, "saddr", "src"); print_ipv4_addr(ab, a->u.net->v4info.daddr, a->u.net->dport, "daddr", "dest"); break; case AF_INET6: print_ipv6_addr(ab, &a->u.net->v6info.saddr, a->u.net->sport, "saddr", "src"); print_ipv6_addr(ab, &a->u.net->v6info.daddr, a->u.net->dport, "daddr", "dest"); break; } if (a->u.net->netif > 0) { struct net_device *dev; /* NOTE: we always use init's namespace */ dev = dev_get_by_index(&init_net, a->u.net->netif); if (dev) { audit_log_format(ab, " netif=%s", dev->name); dev_put(dev); } } break; #ifdef CONFIG_KEYS case LSM_AUDIT_DATA_KEY: audit_log_format(ab, " key_serial=%u", a->u.key_struct.key); if (a->u.key_struct.key_desc) { audit_log_format(ab, " key_desc="); audit_log_untrustedstring(ab, a->u.key_struct.key_desc); } break; #endif case LSM_AUDIT_DATA_KMOD: 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; } /* switch (a->type) */ }
static void dump_common_audit_data(struct audit_buffer *ab, struct common_audit_data *a) { struct task_struct *tsk = current; if (a->tsk) tsk = a->tsk; if (tsk && tsk->pid) { 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); break; case LSM_AUDIT_DATA_CAP: audit_log_format(ab, " capability=%d ", a->u.cap); break; case LSM_AUDIT_DATA_PATH: { struct inode *inode; audit_log_d_path(ab, " path=", &a->u.path); inode = a->u.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); } break; } case LSM_AUDIT_DATA_DENTRY: { struct inode *inode; audit_log_format(ab, " name="); audit_log_untrustedstring(ab, a->u.dentry->d_name.name); inode = a->u.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); } break; } case LSM_AUDIT_DATA_INODE: { struct dentry *dentry; struct inode *inode; inode = a->u.inode; dentry = d_find_alias(inode); if (dentry) { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, dentry->d_name.name); dput(dentry); } 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_TASK: tsk = a->u.tsk; if (tsk && tsk->pid) { audit_log_format(ab, " pid=%d comm=", tsk->pid); audit_log_untrustedstring(ab, tsk->comm); } break; case LSM_AUDIT_DATA_NET: if (a->u.net->sk) { struct sock *sk = a->u.net->sk; struct unix_sock *u; int len = 0; char *p = NULL; switch (sk->sk_family) { case AF_INET: { struct inet_sock *inet = inet_sk(sk); print_ipv4_addr(ab, inet->inet_rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv4_addr(ab, inet->inet_daddr, inet->inet_dport, "faddr", "fport"); break; } case AF_INET6: { struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *inet6 = inet6_sk(sk); print_ipv6_addr(ab, &inet6->rcv_saddr, inet->inet_sport, "laddr", "lport"); print_ipv6_addr(ab, &inet6->daddr, inet->inet_dport, "faddr", "fport"); break; } case AF_UNIX: u = unix_sk(sk); 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]; audit_log_format(ab, " path="); if (*p) audit_log_untrustedstring(ab, p); else audit_log_n_hex(ab, p, len); break; } } switch (a->u.net->family) { case AF_INET: print_ipv4_addr(ab, a->u.net->v4info.saddr, a->u.net->sport, "saddr", "src"); print_ipv4_addr(ab, a->u.net->v4info.daddr, a->u.net->dport, "daddr", "dest"); break; case AF_INET6: print_ipv6_addr(ab, &a->u.net->v6info.saddr, a->u.net->sport, "saddr", "src"); print_ipv6_addr(ab, &a->u.net->v6info.daddr, a->u.net->dport, "daddr", "dest"); break; } if (a->u.net->netif > 0) { struct net_device *dev; dev = dev_get_by_index(&init_net, a->u.net->netif); if (dev) { audit_log_format(ab, " netif=%s", dev->name); dev_put(dev); } } break; #ifdef CONFIG_KEYS case LSM_AUDIT_DATA_KEY: audit_log_format(ab, " key_serial=%u", a->u.key_struct.key); if (a->u.key_struct.key_desc) { audit_log_format(ab, " key_desc="); audit_log_untrustedstring(ab, a->u.key_struct.key_desc); } break; #endif case LSM_AUDIT_DATA_KMOD: audit_log_format(ab, " kmod="); audit_log_untrustedstring(ab, a->u.kmod_name); break; } }