2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation, version 2 of the
8 * Jean-Marc Pigeon <jmp@safe.ca>
10 * Purpose is to regroup all procedure involved
12 * System log need to be containerized to avoid
13 * crossing over critical data between physical host layer
14 * and container layer.
16 * The principle is to keep a containerized ring buffer
17 * where container kernel data are redirected, kept and
20 * Containerized syslog is activated if CLONE_SYSLOG
25 #include <linux/module.h>
26 #include <linux/bootmem.h>
27 #include <linux/slab.h>
28 #include <linux/cred.h>
29 #include <linux/kref.h>
30 #include <linux/user_namespace.h>
31 #include <linux/syslog.h>
34 * Static memory definition, used to assign a syslog
35 * to the init process itself
38 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
39 static char __log_buf[__LOG_BUF_LEN];
41 struct syslog_ns init_syslog_ns = {
43 .refcount = ATOMIC_INIT(2),
45 .handle = 1, /*kernel INIT process pid */
46 .logbuf_lock = __SPIN_LOCK_INITIALIZER(logbuf_lock),
47 .buf_len = __LOG_BUF_LEN,
52 * List of all syslog ns currently allocated
53 * first member of this list (kernel syslog)
57 spinlock_t list_lock; /*make sure about list access */
58 struct log_list *next; /*next syslog_ns in the list */
59 struct syslog_ns *syslog_ns;
61 .list_lock = __SPIN_LOCK_INITIALIZER(list_lock),
62 .next = (struct log_list *)0,
63 .syslog_ns = &init_syslog_ns
66 * removing a syslog reference from the list
69 static void removing_syslog_ns(struct syslog_ns *syslog_ns)
73 struct log_list *start;
77 while (start->next != (struct log_list *)0) {
78 struct log_list *check;
81 spin_lock_irqsave(&(start->next->list_lock), flags);
83 if (check->syslog_ns == syslog_ns) {
84 start->next = check->next;
87 spin_unlock_irqrestore(&(check->list_lock), flags);
97 * adding a syslog_ns to the list of known syslog
100 static void adding_syslog_ns(struct syslog_ns *syslog_ns)
104 struct log_list *start;
108 while ((done == false) && (start != (struct log_list *)0)) {
111 spin_lock_irqsave(&(start->list_lock), flags);
112 if (start->next == (struct log_list *)0) {
113 struct log_list *next;
115 next = kzalloc(sizeof(struct log_list), GFP_KERNEL);
117 spin_lock_init(&(next->list_lock));
118 next->syslog_ns = syslog_ns;
122 spin_unlock_irqrestore(&(start->list_lock), flags);
127 * Procedure to free all ressources tied to syslog
130 static struct syslog_ns *free_all_syslog_ns(struct syslog_ns *syslog_ns)
133 if (syslog_ns != (struct syslog_ns *)0) {
134 (void) removing_syslog_ns(syslog_ns);
135 (void) kfree(syslog_ns->buf);
136 (void) kfree(syslog_ns);
137 syslog_ns = (struct syslog_ns *)0;
143 * Procedure to assign memory for syslog area
146 static struct syslog_ns *malloc_syslog_ns(unsigned container_buf_len)
148 struct syslog_ns *ns;
151 ns = (struct syslog_ns *)0;
155 ns = kzalloc(sizeof(*ns), GFP_KERNEL);
156 buf = kzalloc(container_buf_len, GFP_KERNEL);
157 if ((!ns) || (!buf)) {
163 kref_init(&(ns->kref));
164 spin_lock_init(&(ns->logbuf_lock));
165 ns->handle = current->pid;
166 ns->buf_len = container_buf_len;
168 (void) adding_syslog_ns(ns);
172 * Procedure to locate and return a syslog_ns with same handle as pid submitted.
173 * return a NULL pointer if not found;
176 static struct syslog_ns *find_its_syslog_ns(pid_t pid)
179 struct log_list *start;
182 while (start != (struct log_list *)0) {
183 if (start->syslog_ns->handle == pid)
184 return start->syslog_ns;
190 * Procedure to ONLY increase syslog buffer size
191 * If syslog_ns is NULL, assign a brand new syslog_ns
194 struct syslog_ns *resize_syslog_ns(struct syslog_ns *syslog_ns,
195 unsigned container_buf_len)
198 if ((syslog_ns == &init_syslog_ns) &&
199 (container_buf_len > syslog_ns->buf_len)) {
205 old_buf_len = syslog_ns->buf_len;
206 old_buf = syslog_ns->buf;
207 new_buf = alloc_bootmem(container_buf_len);
209 (void) printk(KERN_WARNING
210 "log_buf_len: allocation failed\n");
211 return ERR_PTR(-ENOMEM);
213 spin_lock_irqsave(&(syslog_ns->logbuf_lock), flags);
214 (void) memmove(new_buf, old_buf, old_buf_len);
215 syslog_ns->buf = new_buf;
216 syslog_ns->buf_len = container_buf_len;
217 spin_unlock_irqrestore(&(syslog_ns->logbuf_lock), flags);
218 if (old_buf != __log_buf)
219 (void) free_bootmem((unsigned long)old_buf,
223 return malloc_syslog_ns(container_buf_len);
224 if (syslog_ns->buf_len > container_buf_len) {
225 (void) printk(KERN_WARNING "log_buf_len: Not allowed "
226 "to decrease syslog buffer\n");
227 return ERR_PTR(-EINVAL);
229 if (syslog_ns->buf_len < container_buf_len) {
234 old_buf = syslog_ns->buf;
235 new_buf = kzalloc(container_buf_len, GFP_KERNEL);
237 return ERR_PTR(-ENOMEM);
238 spin_lock_irqsave(&(syslog_ns->logbuf_lock), flags);
239 (void) memmove(new_buf, old_buf, syslog_ns->buf_len);
240 syslog_ns->buf = new_buf;
241 syslog_ns->buf_len = container_buf_len;
242 spin_unlock_irqrestore(&(syslog_ns->logbuf_lock), flags);
243 (void) kfree(old_buf);
245 (void) printk(KERN_NOTICE "log_buf_len: %u\n", syslog_ns->buf_len);
250 * Procedure to use current syslog unless a CLONE_SYSLOG is set
251 * such a new syslog area is defined and used
254 struct syslog_ns *copy_syslog_ns(unsigned long flags,
255 struct syslog_ns *current_syslog_ns)
258 /*4096 should be enough for container syslog */
259 #define CONTAINER_BUF_LEN 4096
261 BUG_ON(!current_syslog_ns);
262 if ((flags & CLONE_SYSLOG) == CLONE_SYSLOG)
263 current_syslog_ns = malloc_syslog_ns(CONTAINER_BUF_LEN);
265 /*incrementing usage ref count */
266 (void) kref_get(&(current_syslog_ns->kref));
267 return current_syslog_ns;
271 * Procedure to decrement syslog usage count and free memory
272 * if syslog usage count reach zero.
275 void free_syslog_ns(struct kref *kref)
278 struct syslog_ns *sl;
280 sl = container_of(kref, struct syslog_ns, kref);
281 sl = free_all_syslog_ns(sl);
285 * Procedure to get the current syslog area linked to a
286 * container (by CLONE_SYSLOG).
287 * if trouble, report host kernel own syslog_ns.
290 struct syslog_ns *current_syslog_ns(void)
294 struct syslog_ns *ns;
296 ns = (struct syslog_ns *)0;
297 if (current->nsproxy)
298 ns = current->nsproxy->syslog_ns;
299 if (!ns) /*lets try to cover log anyway! */
300 ns = &init_syslog_ns;
304 * Procedure to replace current syslog namespace with another.
305 * Return the original current syslog_ns.
308 struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns)
312 struct syslog_ns *old;
314 spin_lock_irqsave(&(current_syslog_ns()->logbuf_lock), flags);
315 old = current_syslog_ns();
317 current->nsproxy->syslog_ns = syslog_ns;
318 spin_unlock_irqrestore(&(old->logbuf_lock), flags);
323 * Procedure to locate the syslog handle own by a given
324 * pid or one of its parents lineage.
327 struct syslog_ns *find_syslog_ns_bypid(pid_t pid)
331 struct syslog_ns *its_ns;
332 struct task_struct *ns_task;
334 its_ns = find_its_syslog_ns(pid);
337 ns_task = find_task_by_vpid(pid);
338 if ((ns_task) && (ns_task->real_parent))
339 pid = ns_task->real_parent->pid;
343 return log_list.syslog_ns;
347 * Procedure to dereference syslog_ns usage, if no reference
348 * anymore, memory is freed.
351 void put_syslog_ns(struct syslog_ns *ns)
354 kref_put(&ns->kref, free_syslog_ns);