[Lxc-users] [PATCH RFC][gross hack] containerized syslog

Serge E. Hallyn serue at us.ibm.com
Thu Feb 4 20:34:05 UTC 2010


Another reason this is bogus, confirmed by Jean-Marc's testing:
printk is called too often without valid 'current', i.e. when
network packets arrive and are processed.  So we should send output
of sys_syslog() to current's ring buffer, all printks to the
init_syslog_ns, and then we can use ns_printk(syslog_ns, fmt, ...)
for targeted printks.

And, as discussed on irc, we'll make syslog_ns a full namespace
in its own right, use the last remaining clone flag (if there is
one) or build on top of eclone().  It'd be nicer to have a 'real'
clone flag so we can also unshare(CLONE_NEWLOG).

-serge

Quoting Serge E. Hallyn (serue at us.ibm.com):
> Provide each user namespace with its own syslog ringbuffer.
> 
> So you can do
> 	ns_exec -cU /bin/bash
> 	dmesg
> and see nothing.  Root in a container (with private user namespace)
> cannot clear the host's ring buffer.
> 
> Since containers do not have a notion of consoles at present,
> only the initial user namespace deals with console output or
> with the console-related syslog commands.
> 
> This opens the door to targetting printk at certain syslog
> namespaces.  It's not safe to be applied - it's a quick-n-dirty
> hack and won't even compile for CONFIG_PRINTK=n.  Also I've not decided
> what to do about duplication of printks to init_user_ns so for
> now emit_one_char always duplicates to inti_user_ns.  We probably
> want to be smarter about this and output a prefix indicating the
> target.
> 
> But I figured discussions about the API would be more meaningful
> with a testable patch.
> 
> ---
>  fs/proc/kmsg.c                 |    5 +-
>  include/linux/user_namespace.h |    2 +
>  kernel/printk.c                |  225 ++++++++++++++++++++++++++--------------
>  kernel/user.c                  |    4 +
>  kernel/user_namespace.c        |   13 +++
>  5 files changed, 168 insertions(+), 81 deletions(-)
> 
> diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
> index 7ca7834..2746b70 100644
> --- a/fs/proc/kmsg.c
> +++ b/fs/proc/kmsg.c
> @@ -12,11 +12,12 @@
>  #include <linux/poll.h>
>  #include <linux/proc_fs.h>
>  #include <linux/fs.h>
> +#include <linux/syslog.h>
> 
>  #include <asm/uaccess.h>
>  #include <asm/io.h>
> 
> -extern wait_queue_head_t log_wait;
> +extern struct syslog_ns init_syslog_ns;
> 
>  extern int do_syslog(int type, char __user *bug, int count);
> 
> @@ -41,7 +42,7 @@ static ssize_t kmsg_read(struct file *file, char __user *buf,
> 
>  static unsigned int kmsg_poll(struct file *file, poll_table *wait)
>  {
> -	poll_wait(file, &log_wait, wait);
> +	poll_wait(file, &init_syslog_ns.wait, wait);
>  	if (do_syslog(9, NULL, 0))
>  		return POLLIN | POLLRDNORM;
>  	return 0;
> diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
> index cc4f453..3926c89 100644
> --- a/include/linux/user_namespace.h
> +++ b/include/linux/user_namespace.h
> @@ -5,6 +5,7 @@
>  #include <linux/nsproxy.h>
>  #include <linux/sched.h>
>  #include <linux/err.h>
> +#include <linux/syslog.h>
> 
>  #define UIDHASH_BITS	(CONFIG_BASE_SMALL ? 3 : 8)
>  #define UIDHASH_SZ	(1 << UIDHASH_BITS)
> @@ -14,6 +15,7 @@ struct user_namespace {
>  	struct hlist_head	uidhash_table[UIDHASH_SZ];
>  	struct user_struct	*creator;
>  	struct work_struct	destroyer;
> +	struct syslog_ns	*syslog;
>  };
> 
>  extern struct user_namespace init_user_ns;
> diff --git a/kernel/printk.c b/kernel/printk.c
> index 1751c45..5b93447 100644
> --- a/kernel/printk.c
> +++ b/kernel/printk.c
> @@ -35,9 +35,18 @@
>  #include <linux/kexec.h>
>  #include <linux/ratelimit.h>
>  #include <linux/kmsg_dump.h>
> +#include <linux/user_namespace.h>
> 
>  #include <asm/uaccess.h>
> 
> +struct syslog_ns init_syslog_ns;
> +#define g_log_wait (init_syslog_ns.wait)
> +#define g_log_start (init_syslog_ns.start)
> +#define g_log_end (init_syslog_ns.end)
> +#define g_log_buf_len (init_syslog_ns.buf_len)
> +#define g_logged_chars (init_syslog_ns.logged_chars)
> +#define g_log_buf (init_syslog_ns.buf)
> +
>  /*
>   * for_each_console() allows you to iterate on each console
>   */
> @@ -52,6 +61,7 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
>  }
> 
>  #define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
> +#define  CONTAINER_BUF_LEN 4096
> 
>  /* printk's without a loglevel use this.. */
>  #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
> @@ -60,8 +70,6 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
>  #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
>  #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
> 
> -DECLARE_WAIT_QUEUE_HEAD(log_wait);
> -
>  int console_printk[4] = {
>  	DEFAULT_CONSOLE_LOGLEVEL,	/* console_loglevel */
>  	DEFAULT_MESSAGE_LOGLEVEL,	/* default_message_loglevel */
> @@ -98,22 +106,20 @@ EXPORT_SYMBOL_GPL(console_drivers);
>  static int console_locked, console_suspended;
> 
>  /*
> - * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
> + * logbuf_lock protects g_log_buf, g_log_start, g_log_end, con_start and g_logged_chars
>   * It is also used in interesting ways to provide interlocking in
>   * release_console_sem().
>   */
>  static DEFINE_SPINLOCK(logbuf_lock);
> 
> -#define LOG_BUF_MASK (log_buf_len-1)
> -#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
> +#define LOG_BUF_MASK(ns) ((ns)->buf_len-1)
> +#define LOG_BUF(ns, idx) ((ns)->buf[(idx) & LOG_BUF_MASK(ns)])
> 
>  /*
> - * The indices into log_buf are not constrained to log_buf_len - they
> + * The indices into g_log_buf are not constrained to g_log_buf_len - they
>   * must be masked before subscripting
>   */
> -static unsigned log_start;	/* Index into log_buf: next char to be read by syslog() */
> -static unsigned con_start;	/* Index into log_buf: next char to be sent to consoles */
> -static unsigned log_end;	/* Index into log_buf: most-recently-written-char + 1 */
> +static unsigned con_start;	/* Index into g_log_buf: next char to be sent to consoles */
> 
>  /*
>   *	Array of consoles built from command line options (console=)
> @@ -142,9 +148,6 @@ static int console_may_schedule;
>  #ifdef CONFIG_PRINTK
> 
>  static char __log_buf[__LOG_BUF_LEN];
> -static char *log_buf = __log_buf;
> -static int log_buf_len = __LOG_BUF_LEN;
> -static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
> 
>  #ifdef CONFIG_KEXEC
>  /*
> @@ -157,10 +160,10 @@ static unsigned logged_chars; /* Number of chars produced since last read+clear
>   */
>  void log_buf_kexec_setup(void)
>  {
> -	VMCOREINFO_SYMBOL(log_buf);
> -	VMCOREINFO_SYMBOL(log_end);
> -	VMCOREINFO_SYMBOL(log_buf_len);
> -	VMCOREINFO_SYMBOL(logged_chars);
> +	VMCOREINFO_SYMBOL(g_log_buf);
> +	VMCOREINFO_SYMBOL(g_log_end);
> +	VMCOREINFO_SYMBOL(g_log_buf_len);
> +	VMCOREINFO_SYMBOL(g_logged_chars);
>  }
>  #endif
> 
> @@ -171,7 +174,7 @@ static int __init log_buf_len_setup(char *str)
> 
>  	if (size)
>  		size = roundup_pow_of_two(size);
> -	if (size > log_buf_len) {
> +	if (size > g_log_buf_len) {
>  		unsigned start, dest_idx, offset;
>  		char *new_log_buf;
> 
> @@ -182,22 +185,22 @@ static int __init log_buf_len_setup(char *str)
>  		}
> 
>  		spin_lock_irqsave(&logbuf_lock, flags);
> -		log_buf_len = size;
> -		log_buf = new_log_buf;
> +		g_log_buf_len = size;
> +		g_log_buf = new_log_buf;
> 
> -		offset = start = min(con_start, log_start);
> +		offset = start = min(con_start, g_log_start);
>  		dest_idx = 0;
> -		while (start != log_end) {
> -			log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
> +		while (start != g_log_end) {
> +			g_log_buf[dest_idx] = g_log_buf[start & (__LOG_BUF_LEN - 1)];
>  			start++;
>  			dest_idx++;
>  		}
> -		log_start -= offset;
> +		g_log_start -= offset;
>  		con_start -= offset;
> -		log_end -= offset;
> +		g_log_end -= offset;
>  		spin_unlock_irqrestore(&logbuf_lock, flags);
> 
> -		printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
> +		printk(KERN_NOTICE "log_buf_len: %d\n", g_log_buf_len);
>  	}
>  out:
>  	return 1;
> @@ -279,6 +282,7 @@ int do_syslog(int type, char __user *buf, int len)
>  	int do_clear = 0;
>  	char c;
>  	int error = 0;
> +	struct syslog_ns *syslog_ns = current_user_ns()->syslog;
> 
>  	error = security_syslog(type);
>  	if (error)
> @@ -300,15 +304,17 @@ int do_syslog(int type, char __user *buf, int len)
>  			error = -EFAULT;
>  			goto out;
>  		}
> -		error = wait_event_interruptible(log_wait,
> -							(log_start - log_end));
> +		error = wait_event_interruptible(syslog_ns->wait,
> +					(syslog_ns->start - syslog_ns->end));
>  		if (error)
>  			goto out;
>  		i = 0;
>  		spin_lock_irq(&logbuf_lock);
> -		while (!error && (log_start != log_end) && i < len) {
> -			c = LOG_BUF(log_start);
> -			log_start++;
> +		while (!error &&
> +				(syslog_ns->start != syslog_ns->end)
> +				&& i < len) {
> +			c = LOG_BUF(syslog_ns, syslog_ns->start);
> +			syslog_ns->start++;
>  			spin_unlock_irq(&logbuf_lock);
>  			error = __put_user(c,buf);
>  			buf++;
> @@ -335,14 +341,14 @@ int do_syslog(int type, char __user *buf, int len)
>  			goto out;
>  		}
>  		count = len;
> -		if (count > log_buf_len)
> -			count = log_buf_len;
> +		if (count > syslog_ns->buf_len)
> +			count = syslog_ns->buf_len;
>  		spin_lock_irq(&logbuf_lock);
> -		if (count > logged_chars)
> -			count = logged_chars;
> +		if (count > syslog_ns->logged_chars)
> +			count = syslog_ns->logged_chars;
>  		if (do_clear)
> -			logged_chars = 0;
> -		limit = log_end;
> +			syslog_ns->logged_chars = 0;
> +		limit = syslog_ns->end;
>  		/*
>  		 * __put_user() could sleep, and while we sleep
>  		 * printk() could overwrite the messages
> @@ -351,9 +357,9 @@ int do_syslog(int type, char __user *buf, int len)
>  		 */
>  		for (i = 0; i < count && !error; i++) {
>  			j = limit-1-i;
> -			if (j + log_buf_len < log_end)
> +			if (j + syslog_ns->buf_len < syslog_ns->end)
>  				break;
> -			c = LOG_BUF(j);
> +			c = LOG_BUF(syslog_ns, j);
>  			spin_unlock_irq(&logbuf_lock);
>  			error = __put_user(c,&buf[count-1-i]);
>  			cond_resched();
> @@ -377,20 +383,32 @@ int do_syslog(int type, char __user *buf, int len)
>  		}
>  		break;
>  	case 5:		/* Clear ring buffer */
> -		logged_chars = 0;
> +		syslog_ns->logged_chars = 0;
>  		break;
>  	case 6:		/* Disable logging to console */
> +		if (syslog_ns != &init_syslog_ns) {
> +			error = -EPERM;
> +			break;
> +		}
>  		if (saved_console_loglevel == -1)
>  			saved_console_loglevel = console_loglevel;
>  		console_loglevel = minimum_console_loglevel;
>  		break;
>  	case 7:		/* Enable logging to console */
> +		if (syslog_ns != &init_syslog_ns) {
> +			error = -EPERM;
> +			break;
> +		}
>  		if (saved_console_loglevel != -1) {
>  			console_loglevel = saved_console_loglevel;
>  			saved_console_loglevel = -1;
>  		}
>  		break;
>  	case 8:		/* Set level of messages printed to console */
> +		if (syslog_ns != &init_syslog_ns) {
> +			error = -EPERM;
> +			break;
> +		}
>  		error = -EINVAL;
>  		if (len < 1 || len > 8)
>  			goto out;
> @@ -402,10 +420,10 @@ int do_syslog(int type, char __user *buf, int len)
>  		error = 0;
>  		break;
>  	case 9:		/* Number of chars in the log buffer */
> -		error = log_end - log_start;
> +		error = syslog_ns->end - syslog_ns->start;
>  		break;
>  	case 10:	/* Size of the log buffer */
> -		error = log_buf_len;
> +		error = syslog_ns->buf_len;
>  		break;
>  	default:
>  		error = -EINVAL;
> @@ -421,7 +439,7 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
>  }
> 
>  /*
> - * Call the console drivers on a range of log_buf
> + * Call the console drivers on a range of g_log_buf
>   */
>  static void __call_console_drivers(unsigned start, unsigned end)
>  {
> @@ -431,7 +449,8 @@ static void __call_console_drivers(unsigned start, unsigned end)
>  		if ((con->flags & CON_ENABLED) && con->write &&
>  				(cpu_online(smp_processor_id()) ||
>  				(con->flags & CON_ANYTIME)))
> -			con->write(con, &LOG_BUF(start), end - start);
> +			con->write(con, &LOG_BUF(&init_syslog_ns, start),
> +					end - start);
>  	}
>  }
> 
> @@ -455,11 +474,14 @@ static void _call_console_drivers(unsigned start,
>  {
>  	if ((msg_log_level < console_loglevel || ignore_loglevel) &&
>  			console_drivers && start != end) {
> -		if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
> +		if ((start & LOG_BUF_MASK(&init_syslog_ns)) >
> +				(end & LOG_BUF_MASK(&init_syslog_ns))) {
>  			/* wrapped write */
> -			__call_console_drivers(start & LOG_BUF_MASK,
> -						log_buf_len);
> -			__call_console_drivers(0, end & LOG_BUF_MASK);
> +			__call_console_drivers(start &
> +						LOG_BUF_MASK(&init_syslog_ns),
> +						g_log_buf_len);
> +			__call_console_drivers(0,
> +				end & LOG_BUF_MASK(&init_syslog_ns));
>  		} else {
>  			__call_console_drivers(start, end);
>  		}
> @@ -468,13 +490,14 @@ static void _call_console_drivers(unsigned start,
> 
>  /*
>   * Call the console drivers, asking them to write out
> - * log_buf[start] to log_buf[end - 1].
> + * g_log_buf[start] to g_log_buf[end - 1].
>   * The console_sem must be held.
>   */
>  static void call_console_drivers(unsigned start, unsigned end)
>  {
>  	unsigned cur_index, start_print;
>  	static int msg_level = -1;
> +	static struct syslog_ns *ns = &init_syslog_ns;
> 
>  	BUG_ON(((int)(start - end)) > 0);
> 
> @@ -482,16 +505,16 @@ static void call_console_drivers(unsigned start, unsigned end)
>  	start_print = start;
>  	while (cur_index != end) {
>  		if (msg_level < 0 && ((end - cur_index) > 2) &&
> -				LOG_BUF(cur_index + 0) == '<' &&
> -				LOG_BUF(cur_index + 1) >= '0' &&
> -				LOG_BUF(cur_index + 1) <= '7' &&
> -				LOG_BUF(cur_index + 2) == '>') {
> -			msg_level = LOG_BUF(cur_index + 1) - '0';
> +				LOG_BUF(ns, cur_index + 0) == '<' &&
> +				LOG_BUF(ns, cur_index + 1) >= '0' &&
> +				LOG_BUF(ns, cur_index + 1) <= '7' &&
> +				LOG_BUF(ns, cur_index + 2) == '>') {
> +			msg_level = LOG_BUF(ns, cur_index + 1) - '0';
>  			cur_index += 3;
>  			start_print = cur_index;
>  		}
>  		while (cur_index != end) {
> -			char c = LOG_BUF(cur_index);
> +			char c = LOG_BUF(ns, cur_index);
> 
>  			cur_index++;
>  			if (c == '\n') {
> @@ -514,16 +537,26 @@ static void call_console_drivers(unsigned start, unsigned end)
>  	_call_console_drivers(start_print, end, msg_level);
>  }
> 
> +static void do_emit_log_char(struct syslog_ns *ns, char c)
> +{
> +	LOG_BUF(ns, ns->end) = c;
> +	ns->end++;
> +	if (ns->end - ns->start > ns->buf_len)
> +		ns->start = ns->end - ns->buf_len;
> +	if (ns == &init_syslog_ns) {
> +		if (g_log_end - con_start > g_log_buf_len)
> +			con_start = g_log_end - g_log_buf_len;
> +	}
> +	if (ns->logged_chars < ns->buf_len)
> +		ns->logged_chars++;
> +}
> +
>  static void emit_log_char(char c)
>  {
> -	LOG_BUF(log_end) = c;
> -	log_end++;
> -	if (log_end - log_start > log_buf_len)
> -		log_start = log_end - log_buf_len;
> -	if (log_end - con_start > log_buf_len)
> -		con_start = log_end - log_buf_len;
> -	if (logged_chars < log_buf_len)
> -		logged_chars++;
> +	struct syslog_ns *ns = current_user_ns()->syslog;
> +	if (ns != &init_syslog_ns)
> +		do_emit_log_char(ns,c);
> +	do_emit_log_char(&init_syslog_ns, c);
>  }
> 
>  /*
> @@ -669,6 +702,25 @@ static inline void printk_delay(void)
>  	}
>  }
> 
> +/* called from create_user_ns() */
> +struct syslog_ns * do_syslog_init(void)
> +{
> +	struct syslog_ns *ns;
> +
> +	ns = kzalloc(sizeof(*ns), GFP_KERNEL);
> +	if (!ns)
> +		return ERR_PTR(-ENOMEM);
> +	ns->buf = kzalloc(CONTAINER_BUF_LEN, GFP_KERNEL);
> +	if (!ns->buf) {
> +		kfree(ns);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +	init_waitqueue_head(&ns->wait);
> +	ns->buf_len = CONTAINER_BUF_LEN;
> +
> +	return ns;
> +}
> +
>  asmlinkage int vprintk(const char *fmt, va_list args)
>  {
>  	int printed_len = 0;
> @@ -676,6 +728,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
>  	unsigned long flags;
>  	int this_cpu;
>  	char *p;
> +	struct syslog_ns *syslog_ns;
> 
>  	boot_delay_msec();
>  	printk_delay();
> @@ -741,7 +794,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
>  	}
> 
>  	/*
> -	 * Copy the output into log_buf.  If the caller didn't provide
> +	 * Copy the output into g_log_buf.  If the caller didn't provide
>  	 * appropriate log level tags, we insert them here
>  	 */
>  	for ( ; *p; p++) {
> @@ -790,7 +843,13 @@ asmlinkage int vprintk(const char *fmt, va_list args)
>  	 * will release 'logbuf_lock' regardless of whether it
>  	 * actually gets the semaphore or not.
>  	 */
> -	if (acquire_console_semaphore_for_printk(this_cpu))
> +	syslog_ns = current_user_ns()->syslog;
> +	if (syslog_ns != &init_syslog_ns) {
> +		int need_wake = (syslog_ns->start != syslog_ns->end);
> +		spin_unlock_irqrestore(&logbuf_lock, flags);
> +		if (!oops_in_progress && need_wake)
> +			wake_up_interruptible(&syslog_ns->wait);
> +	} else if (acquire_console_semaphore_for_printk(this_cpu))
>  		release_console_sem();
> 
>  	lockdep_on();
> @@ -811,6 +870,14 @@ static void call_console_drivers(unsigned start, unsigned end)
> 
>  #endif
> 
> +/*  init_syslog_ns is part of init_user_ns */
> +/* note this does not work for !CONFIG_PRINTK */
> +struct syslog_ns init_syslog_ns = {
> +	.wait = __WAIT_QUEUE_HEAD_INITIALIZER(init_syslog_ns.wait),
> +	.buf_len = __LOG_BUF_LEN,
> +	.buf = __log_buf,
> +};
> +
>  static int __add_preferred_console(char *name, int idx, char *options,
>  				   char *brl_options)
>  {
> @@ -1010,7 +1077,7 @@ void printk_tick(void)
>  {
>  	if (__get_cpu_var(printk_pending)) {
>  		__get_cpu_var(printk_pending) = 0;
> -		wake_up_interruptible(&log_wait);
> +		wake_up_interruptible(&g_log_wait);
>  	}
>  }
> 
> @@ -1021,7 +1088,7 @@ int printk_needs_cpu(int cpu)
> 
>  void wake_up_klogd(void)
>  {
> -	if (waitqueue_active(&log_wait))
> +	if (waitqueue_active(&g_log_wait))
>  		__raw_get_cpu_var(printk_pending) = 1;
>  }
> 
> @@ -1054,12 +1121,12 @@ void release_console_sem(void)
> 
>  	for ( ; ; ) {
>  		spin_lock_irqsave(&logbuf_lock, flags);
> -		wake_klogd |= log_start - log_end;
> -		if (con_start == log_end)
> +		wake_klogd |= g_log_start - g_log_end;
> +		if (con_start == g_log_end)
>  			break;			/* Nothing to print */
>  		_con_start = con_start;
> -		_log_end = log_end;
> -		con_start = log_end;		/* Flush */
> +		_log_end = g_log_end;
> +		con_start = g_log_end;		/* Flush */
>  		spin_unlock(&logbuf_lock);
>  		stop_critical_timings();	/* don't trace print latency */
>  		call_console_drivers(_con_start, _log_end);
> @@ -1287,7 +1354,7 @@ void register_console(struct console *newcon)
>  		 * for us.
>  		 */
>  		spin_lock_irqsave(&logbuf_lock, flags);
> -		con_start = log_start;
> +		con_start = g_log_start;
>  		spin_unlock_irqrestore(&logbuf_lock, flags);
>  	}
>  	release_console_sem();
> @@ -1498,22 +1565,22 @@ void kmsg_dump(enum kmsg_dump_reason reason)
>  	   there's not a lot we can do about that. The new messages
>  	   will overwrite the start of what we dump. */
>  	spin_lock_irqsave(&logbuf_lock, flags);
> -	end = log_end & LOG_BUF_MASK;
> -	chars = logged_chars;
> +	end = g_log_end & LOG_BUF_MASK(&init_syslog_ns);
> +	chars = g_logged_chars;
>  	spin_unlock_irqrestore(&logbuf_lock, flags);
> 
> -	if (logged_chars > end) {
> -		s1 = log_buf + log_buf_len - logged_chars + end;
> -		l1 = logged_chars - end;
> +	if (g_logged_chars > end) {
> +		s1 = g_log_buf + g_log_buf_len - g_logged_chars + end;
> +		l1 = g_logged_chars - end;
> 
> -		s2 = log_buf;
> +		s2 = g_log_buf;
>  		l2 = end;
>  	} else {
>  		s1 = "";
>  		l1 = 0;
> 
> -		s2 = log_buf + end - logged_chars;
> -		l2 = logged_chars;
> +		s2 = g_log_buf + end - g_logged_chars;
> +		l2 = g_logged_chars;
>  	}
> 
>  	if (!spin_trylock_irqsave(&dump_list_lock, flags)) {
> diff --git a/kernel/user.c b/kernel/user.c
> index 46d0165..102c2ce 100644
> --- a/kernel/user.c
> +++ b/kernel/user.c
> @@ -18,11 +18,15 @@
>  #include <linux/user_namespace.h>
>  #include "cred-internals.h"
> 
> +/* defined in kernel/printk.c */
> +extern struct syslog_ns init_syslog_ns;
> +
>  struct user_namespace init_user_ns = {
>  	.kref = {
>  		.refcount	= ATOMIC_INIT(2),
>  	},
>  	.creator = &root_user,
> +	.syslog = &init_syslog_ns,
>  };
>  EXPORT_SYMBOL_GPL(init_user_ns);
> 
> diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
> index 076c7c8..43d46d1 100644
> --- a/kernel/user_namespace.c
> +++ b/kernel/user_namespace.c
> @@ -11,6 +11,9 @@
>  #include <linux/user_namespace.h>
>  #include <linux/cred.h>
> 
> +/* defined in kernel/printk.c */
> +extern struct syslog_ns *do_syslog_init(void);
> +
>  /*
>   * Create a new user namespace, deriving the creator from the user in the
>   * passed credentials, and replacing that user with the new root user for the
> @@ -34,9 +37,17 @@ int create_user_ns(struct cred *new)
>  	for (n = 0; n < UIDHASH_SZ; ++n)
>  		INIT_HLIST_HEAD(ns->uidhash_table + n);
> 
> +	ns->syslog = do_syslog_init();
> +	if (!ns->syslog) {
> +		kfree(ns);
> +		return -ENOMEM;
> +	}
> +
>  	/* Alloc new root user.  */
>  	root_user = alloc_uid(ns, 0);
>  	if (!root_user) {
> +		kfree(ns->syslog->buf);
> +		kfree(ns->syslog);
>  		kfree(ns);
>  		return -ENOMEM;
>  	}
> @@ -70,6 +81,8 @@ static void free_user_ns_work(struct work_struct *work)
>  	struct user_namespace *ns =
>  		container_of(work, struct user_namespace, destroyer);
>  	free_uid(ns->creator);
> +	kfree(ns->syslog->buf);
> +	kfree(ns->syslog);
>  	kfree(ns);
>  }
> 
> -- 
> 1.6.1
> 
> _______________________________________________
> Containers mailing list
> Containers at lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the lxc-users mailing list