Capability to redirect iptable log, in the right containerized syslog_ns, is now fully working. Tried my best to have a very minimal foot-print. BEWARE: patch not done for IPV6 (I can't test it), you are welcome to do it. Signed-off-by: Jean-Marc Pigeon <jmp@xxxxxxx> --- include/linux/netdevice.h | 2 + include/linux/syslog.h | 8 +++ kernel/syslog.c | 140 +++++++++++++++++++++++++++++++++++++++--- net/core/rtnetlink.c | 3 + net/ipv4/netfilter/ipt_LOG.c | 11 +++ 5 files changed, 154 insertions(+), 10 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a3fccc8..c323463 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -918,6 +918,8 @@ struct net_device { /* Network namespace this network device is inside */ struct net *nd_net; #endif + /* to assign a syslog chanel according device ownership */ + pid_t syslog_ns_pid; /* mid-layer private */ void *ml_priv; diff --git a/include/linux/syslog.h b/include/linux/syslog.h index 9fbe190..2188f09 100644 --- a/include/linux/syslog.h +++ b/include/linux/syslog.h @@ -44,15 +44,23 @@ static inline void put_syslog_ns(struct syslog_ns *ns) #ifdef CONFIG_PRINTK extern struct syslog_ns *current_syslog_ns(void); extern struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns); +extern struct syslog_ns *find_syslog_ns_bypid(pid_t pid); #else static inline syslog_ns *current_syslog_ns(void) { return 0; } + static inline struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns) { return syslog_ns; } + +static inline syslog_ns *find_syslog_ns_bypid(pid_t pid) + +{ + return 0; +} #endif #endif /* _LINUX_SYSLOG_H */ diff --git a/kernel/syslog.c b/kernel/syslog.c index 9873c06..1ab9bdc 100644 --- a/kernel/syslog.c +++ b/kernel/syslog.c @@ -18,7 +18,8 @@ * where container kernel data are redirected, kept and * managed. * - * Containerized syslog is activated by CLONE_SYSLOG + * Containerized syslog is activated if CLONE_SYSLOG + * condition is true. * */ @@ -47,23 +48,99 @@ struct syslog_ns init_kernel_syslog_ns = { .buf_len = __LOG_BUF_LEN, .buf = __log_buf }; - struct syslog_ns init_kernel_syslog_ns; EXPORT_SYMBOL_GPL(init_kernel_syslog_ns); /* + * List of all syslog ns currently allocated + * first member of this list (kernel syslog) + * can't be removed. + */ +struct log_list { + spinlock_t list_lock; /*make sure about list access */ + struct log_list *next; /*next syslog_ns in the list */ + struct syslog_ns *syslog_ns; + } log_list = { + .list_lock = __SPIN_LOCK_INITIALIZER(list_lock), + .next = (struct log_list *)0, + .syslog_ns = &init_kernel_syslog_ns + }; +/* + * removing a syslog reference from the list + * + */ +static void removing_syslog_ns(struct syslog_ns *syslog_ns) + +{ + int done; + struct log_list *start; + + done = false; + start = &log_list; + while (start->next != (struct log_list *)0) { + struct log_list *check; + unsigned long flags; + + spin_lock_irqsave(&(start->next->list_lock), flags); + check = start->next; + if (check->syslog_ns == syslog_ns) { + start->next = check->next; + done = true; + } + spin_unlock_irqrestore(&(check->list_lock), flags); + if (done == true) { + kfree(check); + break; + } + start = start->next; + } +} + +/* + * adding a syslog_ns to the list of known syslog + * + */ +static void adding_syslog_ns(struct syslog_ns *syslog_ns) + +{ + int done; + struct log_list *start; + + done = false; + start = &log_list; + while ((done == false) && (start != (struct log_list *)0)) { + unsigned long flags; + + spin_lock_irqsave(&(start->list_lock), flags); + if (start->next == (struct log_list *)0) { + struct log_list *next; + + next = kzalloc(sizeof(struct log_list), GFP_KERNEL); + BUG_ON(!next); + spin_lock_init(&(next->list_lock)); + next->syslog_ns = syslog_ns; + start->next = next; + done = true; + } + spin_unlock_irqrestore(&(start->list_lock), flags); + start = start->next; + } +} + +/* * Procedure to free all ressources tied to syslog * */ -static struct syslog_ns *free_all_syslog_ns(struct syslog_ns *syslog) +static struct syslog_ns *free_all_syslog_ns(struct syslog_ns *syslog_ns) { - if (syslog != (struct syslog_ns *)0) { - (void) kfree(syslog->buf); - (void) kfree(syslog); - syslog = (struct syslog_ns *)0; + if (syslog_ns != (struct syslog_ns *)0) { + (void) removing_syslog_ns(syslog_ns); + (void) kfree(syslog_ns->buf); + (void) kfree(syslog_ns); + syslog_ns = (struct syslog_ns *)0; } - return syslog; + return syslog_ns; } /* @@ -93,9 +170,28 @@ static struct syslog_ns *malloc_syslog_ns(unsigned container_buf_len) ns->handle = current->pid; ns->buf_len = container_buf_len; ns->buf = buf; + (void) adding_syslog_ns(ns); return ns; } /* + * Procedure to locate and return a syslog_ns with same handle as pid submitted. + * return a NULL pointer if not found; + * + */ +static struct syslog_ns *find_its_syslog_ns(pid_t pid) + +{ + struct log_list *start; + + start = &log_list; + while (start != (struct log_list *)0) { + if (start->syslog_ns->handle == pid) + return start->syslog_ns; + start = start->next; + } + return 0; +} +/* * Procedure to ONLY increase syslog buffer size * If syslog_ns is NULL, assign a brand new syslog_ns * @@ -193,7 +289,7 @@ void free_syslog_ns(struct kref *kref) /* * Procedure to get the current syslog area linked to a * container (by CLONE_SYSLOG). - * if trouble, pin down the problem before it propagate. + * if trouble, report host kernel own syslog_ns. * */ struct syslog_ns *current_syslog_ns(void) @@ -222,7 +318,31 @@ struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns) spin_lock_irqsave(&(current_syslog_ns()->logbuf_lock), flags); old = current_syslog_ns(); - current->nsproxy->syslog_ns = syslog_ns; + if (syslog_ns) + current->nsproxy->syslog_ns = syslog_ns; spin_unlock_irqrestore(&(old->logbuf_lock), flags); return old; } +/* + * Procedure to locate the syslog handle own by a given + * pid or one of its parents lineage. + * + */ +struct syslog_ns *find_syslog_ns_bypid(pid_t pid) + +{ + while (pid > 1) { + struct syslog_ns *its_ns; + struct task_struct *ns_task; + + its_ns = find_its_syslog_ns(pid); + if (its_ns) + return its_ns; + ns_task = find_task_by_vpid(pid); + if ((ns_task) && (ns_task->real_parent)) + pid = ns_task->real_parent->pid; + else + break; + } + return log_list.syslog_ns; +} diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 794bcb8..e41bc93 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -775,6 +775,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, err = PTR_ERR(net); goto errout; } + if (dev) + dev->syslog_ns_pid = nla_get_u32(tb[IFLA_NET_NS_PID]); + err = dev_change_net_namespace(dev, net, ifname); put_net(net); if (err) diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index ee128ef..7e1467d 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -14,6 +14,7 @@ #include <linux/spinlock.h> #include <linux/skbuff.h> #include <linux/ip.h> +#include <linux/syslog.h> #include <net/icmp.h> #include <net/udp.h> #include <net/tcp.h> @@ -382,6 +383,15 @@ ipt_log_packet(u_int8_t pf, const struct nf_loginfo *loginfo, const char *prefix) { + + struct syslog_ns *syslog_ns; + + + syslog_ns = (struct syslog_ns *)0; + if (skb->dev) /*another syslog_ns possible? */ + syslog_ns = find_syslog_ns_bypid(skb->dev->syslog_ns_pid); + syslog_ns = switch_syslog_ns(syslog_ns); + if (!loginfo) loginfo = &default_loginfo; @@ -422,6 +432,7 @@ ipt_log_packet(u_int8_t pf, dump_packet(loginfo, skb, 0); printk("\n"); spin_unlock_bh(&log_lock); + (void) switch_syslog_ns(syslog_ns); } static unsigned int -- 1.6.6 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers