linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] vsprintf: ignore %n again
@ 2013-09-16  7:43 Kees Cook
  2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
                   ` (2 more replies)
  0 siblings, 3 replies; 46+ messages in thread
From: Kees Cook @ 2013-09-16  7:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: joe, George Spelvin, dan.carpenter, viro, Jan Beulich,
	KOSAKI Motohiro, Tetsuo Handa, akpm

Whether seq_printf should return void or error, %n still needs to be removed.
As such, instead of changing the seq_file structure and adding instructions
to all callers of seq_printf, just examine seq->count for the callers that
care about how many characters were put into the buffer, as suggested by
George Spelvin. First patch removes all %n usage in favor of checking
seq->count before/after. Second patch makes %n ignore its argument.

Testing shows this all works happily, and everything is still getting
padded correctly:

/proc/consoles:
ttyS0                -W- (EC   a)    4:64
netcon0              -W- (E     )

/proc/self/maps:
...
01ee7000-01f08000 rw-p 00000000 00:00 0                                  [heap]
7fdc79bd4000-7fdc79bf6000 r-xp 00000000 fd:01 394247                     /lib/x86_64-linux-gnu/libtinfo.so.5.9
...

/proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 2239 1 ffff88007bfd0000 100 0 0 10 0
...

/proc/net/udp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops
   12: 0DAAA8C0:D9D1 0100000A:0035 01 00000000:00000000 00:00000000 00000000     0        0 7534 2 ffff880078048000 0


And a test with a %n in a format string shows the warning:

[   10.693638] ------------[ cut here ]------------
[   10.693657] WARNING: CPU: 0 PID: 2048 at lib/vsprintf.c:1693 vsnprintf+0x5c1/0x600()
[   10.693660] Please remove ignored %n in '%n
[   10.693663] '
...

Fixing the other callers of seq_printf to do the right thing (void or not)
can be separate from this series.

-Kees


^ permalink raw reply	[flat|nested] 46+ messages in thread

* [PATCH 1/2] remove all uses of printf's %n
  2013-09-16  7:43 [PATCH 0/2] vsprintf: ignore %n again Kees Cook
@ 2013-09-16  7:43 ` Kees Cook
  2013-09-16  8:09   ` Geert Uytterhoeven
                     ` (2 more replies)
  2013-09-16  7:43 ` [PATCH 2/2] vsprintf: ignore %n again Kees Cook
  2013-09-16 15:55 ` [PATCH 0/2] " Al Viro
  2 siblings, 3 replies; 46+ messages in thread
From: Kees Cook @ 2013-09-16  7:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: joe, George Spelvin, dan.carpenter, viro, Jan Beulich,
	KOSAKI Motohiro, Tetsuo Handa, akpm, Kees Cook

All users of %n are calculating padding size when using seq_file, so
instead use the new last_len member for discovering the length of the
written strings.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 fs/proc/consoles.c   |    5 +++--
 fs/proc/nommu.c      |    6 ++++--
 fs/proc/task_mmu.c   |    6 ++++--
 fs/proc/task_nommu.c |    6 ++++--
 net/ipv4/fib_trie.c  |   10 ++++++----
 net/ipv4/ping.c      |   10 ++++++----
 net/ipv4/tcp_ipv4.c  |   28 ++++++++++++++--------------
 net/ipv4/udp.c       |   10 ++++++----
 net/phonet/socket.c  |   18 +++++++++++-------
 net/sctp/objcnt.c    |    6 ++++--
 10 files changed, 62 insertions(+), 43 deletions(-)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index b701eaa..08cd2ee 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -47,8 +47,9 @@ static int show_console_dev(struct seq_file *m, void *v)
 			con_flags[a].name : ' ';
 	flags[a] = 0;
 
-	seq_printf(m, "%s%d%n", con->name, con->index, &len);
-	len = 21 - len;
+	len = m->count;
+	seq_printf(m, "%s%d", con->name, con->index);
+	len = 21 - (m->count - len);
 	if (len < 1)
 		len = 1;
 	seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index ccfd99b..db0700d 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -50,8 +50,9 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 		ino = inode->i_ino;
 	}
 
+	len = m->count;
 	seq_printf(m,
-		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 		   region->vm_start,
 		   region->vm_end,
 		   flags & VM_READ ? 'r' : '-',
@@ -59,7 +60,8 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 		   flags & VM_EXEC ? 'x' : '-',
 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
 		   ((loff_t)region->vm_pgoff) << PAGE_SHIFT,
-		   MAJOR(dev), MINOR(dev), ino, &len);
+		   MAJOR(dev), MINOR(dev), ino);
+	len = m->count - len;
 
 	if (file) {
 		len = 25 + sizeof(void *) * 6 - len;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7366e9d..eaca69c 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -286,7 +286,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 	if (stack_guard_page_end(vma, end))
 		end -= PAGE_SIZE;
 
-	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+	len = m->count;
+	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 			start,
 			end,
 			flags & VM_READ ? 'r' : '-',
@@ -294,7 +295,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 			flags & VM_EXEC ? 'x' : '-',
 			flags & VM_MAYSHARE ? 's' : 'p',
 			pgoff,
-			MAJOR(dev), MINOR(dev), ino, &len);
+			MAJOR(dev), MINOR(dev), ino);
+	len = m->count - len;
 
 	/*
 	 * Print the dentry name for named mappings, and a
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 56123a6..04c8246 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -155,8 +155,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 		pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
 	}
 
+	len = m->count;
 	seq_printf(m,
-		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 		   vma->vm_start,
 		   vma->vm_end,
 		   flags & VM_READ ? 'r' : '-',
@@ -164,7 +165,8 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 		   flags & VM_EXEC ? 'x' : '-',
 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
 		   pgoff,
-		   MAJOR(dev), MINOR(dev), ino, &len);
+		   MAJOR(dev), MINOR(dev), ino);
+	len = m->count - len;
 
 	if (file) {
 		pad_len_spaces(m, len);
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 3df6d3e..9537a95 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2536,10 +2536,11 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 			    || fa->fa_type == RTN_MULTICAST)
 				continue;
 
+			len = seq->count;
 			if (fi)
 				seq_printf(seq,
 					 "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
-					 "%d\t%08X\t%d\t%u\t%u%n",
+					 "%d\t%08X\t%d\t%u\t%u",
 					 fi->fib_dev ? fi->fib_dev->name : "*",
 					 prefix,
 					 fi->fib_nh->nh_gw, flags, 0, 0,
@@ -2548,13 +2549,14 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 					 (fi->fib_advmss ?
 					  fi->fib_advmss + 40 : 0),
 					 fi->fib_window,
-					 fi->fib_rtt >> 3, &len);
+					 fi->fib_rtt >> 3);
 			else
 				seq_printf(seq,
 					 "*\t%08X\t%08X\t%04X\t%d\t%u\t"
-					 "%d\t%08X\t%d\t%u\t%u%n",
+					 "%d\t%08X\t%d\t%u\t%u",
 					 prefix, 0, flags, 0, 0, 0,
-					 mask, 0, 0, 0, &len);
+					 mask, 0, 0, 0);
+			len = seq->count - len;
 
 			seq_printf(seq, "%*s\n", 127 - len, "");
 		}
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index d7d9882..c87d062 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -1073,7 +1073,7 @@ void ping_seq_stop(struct seq_file *seq, void *v)
 EXPORT_SYMBOL_GPL(ping_seq_stop);
 
 static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
-		int bucket, int *len)
+		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->inet_daddr;
@@ -1082,7 +1082,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
 	__u16 srcp = ntohs(inet->inet_sport);
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
@@ -1090,7 +1090,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
 		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
 		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
-		atomic_read(&sp->sk_drops), len);
+		atomic_read(&sp->sk_drops));
 }
 
 static int ping_v4_seq_show(struct seq_file *seq, void *v)
@@ -1104,7 +1104,9 @@ static int ping_v4_seq_show(struct seq_file *seq, void *v)
 		struct ping_iter_state *state = seq->private;
 		int len;
 
-		ping_v4_format_sock(v, seq, state->bucket, &len);
+		len = seq->count;
+		ping_v4_format_sock(v, seq, state->bucket);
+		len = seq->count - len;
 		seq_printf(seq, "%*s\n", 127 - len, "");
 	}
 	return 0;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b14266b..cdded47 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2598,13 +2598,13 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 EXPORT_SYMBOL(tcp_proc_unregister);
 
 static void get_openreq4(const struct sock *sk, const struct request_sock *req,
-			 struct seq_file *f, int i, kuid_t uid, int *len)
+			 struct seq_file *f, int i, kuid_t uid)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	long delta = req->expires - jiffies;
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK",
 		i,
 		ireq->loc_addr,
 		ntohs(inet_sk(sk)->inet_sport),
@@ -2619,11 +2619,10 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
 		0,  /* non standard timer */
 		0, /* open_requests have no inode */
 		atomic_read(&sk->sk_refcnt),
-		req,
-		len);
+		req);
 }
 
-static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
+static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
 {
 	int timer_active;
 	unsigned long timer_expires;
@@ -2662,7 +2661,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d%n",
+			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
 		i, src, srcp, dest, destp, sk->sk_state,
 		tp->write_seq - tp->snd_una,
 		rx_queue,
@@ -2679,12 +2678,11 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		tp->snd_cwnd,
 		sk->sk_state == TCP_LISTEN ?
 		    (fastopenq ? fastopenq->max_qlen : 0) :
-		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh),
-		len);
+		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));
 }
 
 static void get_timewait4_sock(const struct inet_timewait_sock *tw,
-			       struct seq_file *f, int i, int *len)
+			       struct seq_file *f, int i)
 {
 	__be32 dest, src;
 	__u16 destp, srcp;
@@ -2696,10 +2694,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 	srcp  = ntohs(tw->tw_sport);
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
 		i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
 		3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
-		atomic_read(&tw->tw_refcnt), tw, len);
+		atomic_read(&tw->tw_refcnt), tw);
 }
 
 #define TMPSZ 150
@@ -2718,18 +2716,20 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
 	}
 	st = seq->private;
 
+	len = seq->count;
 	switch (st->state) {
 	case TCP_SEQ_STATE_LISTENING:
 	case TCP_SEQ_STATE_ESTABLISHED:
-		get_tcp4_sock(v, seq, st->num, &len);
+		get_tcp4_sock(v, seq, st->num);
 		break;
 	case TCP_SEQ_STATE_OPENREQ:
-		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
+		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid);
 		break;
 	case TCP_SEQ_STATE_TIME_WAIT:
-		get_timewait4_sock(v, seq, st->num, &len);
+		get_timewait4_sock(v, seq, st->num);
 		break;
 	}
+	len = seq->count - len;
 	seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
 out:
 	return 0;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 74d2c95..5460ab9 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2150,7 +2150,7 @@ EXPORT_SYMBOL(udp_proc_unregister);
 
 /* ------------------------------------------------------------------------ */
 static void udp4_format_sock(struct sock *sp, struct seq_file *f,
-		int bucket, int *len)
+		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->inet_daddr;
@@ -2159,7 +2159,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 	__u16 srcp	  = ntohs(inet->inet_sport);
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
@@ -2167,7 +2167,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
 		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
-		atomic_read(&sp->sk_drops), len);
+		atomic_read(&sp->sk_drops));
 }
 
 int udp4_seq_show(struct seq_file *seq, void *v)
@@ -2181,7 +2181,9 @@ int udp4_seq_show(struct seq_file *seq, void *v)
 		struct udp_iter_state *state = seq->private;
 		int len;
 
-		udp4_format_sock(v, seq, state->bucket, &len);
+		len = seq->count;
+		udp4_format_sock(v, seq, state->bucket);
+		len = seq->count - len;
 		seq_printf(seq, "%*s\n", 127 - len, "");
 	}
 	return 0;
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 77e38f7..b8712ad 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -597,23 +597,25 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
 {
 	int len;
 
+	len = seq->count;
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
-			"  uid inode ref pointer drops", &len);
+		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
+			"  uid inode ref pointer drops");
 	else {
 		struct sock *sk = v;
 		struct pn_sock *pn = pn_sk(sk);
 
 		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
-			"%d %pK %d%n",
+			"%d %pK %d",
 			sk->sk_protocol, pn->sobject, pn->dobject,
 			pn->resource, sk->sk_state,
 			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
 			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 			sock_i_ino(sk),
 			atomic_read(&sk->sk_refcnt), sk,
-			atomic_read(&sk->sk_drops), &len);
+			atomic_read(&sk->sk_drops));
 	}
+	len = seq->count - len;
 	seq_printf(seq, "%*s\n", 127 - len, "");
 	return 0;
 }
@@ -787,17 +789,19 @@ static int pn_res_seq_show(struct seq_file *seq, void *v)
 {
 	int len;
 
+	len = seq->count;
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%s%n", "rs   uid inode", &len);
+		seq_puts(seq, "rs   uid inode");
 	else {
 		struct sock **psk = v;
 		struct sock *sk = *psk;
 
-		seq_printf(seq, "%02X %5u %lu%n",
+		seq_printf(seq, "%02X %5u %lu",
 			   (int) (psk - pnres.sk),
 			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
-			   sock_i_ino(sk), &len);
+			   sock_i_ino(sk));
 	}
+	len = seq->count - len;
 	seq_printf(seq, "%*s\n", 63 - len, "");
 	return 0;
 }
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index 5ea573b..b3f4a3c 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -82,8 +82,10 @@ static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
 	int i, len;
 
 	i = (int)*(loff_t *)v;
-	seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
-				atomic_read(sctp_dbg_objcnt[i].counter), &len);
+	len = seq->count;
+	seq_printf(seq, "%s: %d", sctp_dbg_objcnt[i].label,
+				atomic_read(sctp_dbg_objcnt[i].counter));
+	len = seq->count - len;
 	seq_printf(seq, "%*s\n", 127 - len, "");
 	return 0;
 }
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* [PATCH 2/2] vsprintf: ignore %n again
  2013-09-16  7:43 [PATCH 0/2] vsprintf: ignore %n again Kees Cook
  2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
@ 2013-09-16  7:43 ` Kees Cook
  2013-09-16 15:55 ` [PATCH 0/2] " Al Viro
  2 siblings, 0 replies; 46+ messages in thread
From: Kees Cook @ 2013-09-16  7:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: joe, George Spelvin, dan.carpenter, viro, Jan Beulich,
	KOSAKI Motohiro, Tetsuo Handa, akpm, Kees Cook

This ignores %n in printf again, as was originally documented. Implementing
%n poses a greater security risk than utility, so it should stay ignored.
To help anyone attempting to use %n, a warning will be emitted if it is
encountered.

Based on earlier patch by Joe Perches.

Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Joe Perches <joe@perches.com>
---
 lib/vsprintf.c |   20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 26559bd..478c30e 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1683,18 +1683,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 			break;
 
 		case FORMAT_TYPE_NRCHARS: {
-			u8 qualifier = spec.qualifier;
+			/*
+			 * Since %n poses a greater security risk than
+			 * utility, ignore %n and skip its argument.
+			 */
+			void *skip_arg;
 
-			if (qualifier == 'l') {
-				long *ip = va_arg(args, long *);
-				*ip = (str - buf);
-			} else if (_tolower(qualifier) == 'z') {
-				size_t *ip = va_arg(args, size_t *);
-				*ip = (str - buf);
-			} else {
-				int *ip = va_arg(args, int *);
-				*ip = (str - buf);
-			}
+			WARN_ONCE(1, "Please remove ignored %%n in '%s'\n",
+					old_fmt);
+
+			skip_arg = va_arg(args, void *);
 			break;
 		}
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
@ 2013-09-16  8:09   ` Geert Uytterhoeven
  2013-09-16 15:00     ` Kees Cook
  2013-09-16 11:41   ` Tetsuo Handa
  2013-09-16 16:07   ` George Spelvin
  2 siblings, 1 reply; 46+ messages in thread
From: Geert Uytterhoeven @ 2013-09-16  8:09 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, Joe Perches, George Spelvin, Dan Carpenter,
	Al Viro, Jan Beulich, KOSAKI Motohiro, Tetsuo Handa,
	Andrew Morton

On Mon, Sep 16, 2013 at 9:43 AM, Kees Cook <keescook@chromium.org> wrote:
> All users of %n are calculating padding size when using seq_file, so
> instead use the new last_len member for discovering the length of the
> written strings.

Would it make sense to provide a seq_pad(...) function instead, to avoid
exposing more seq_file internals to its callers?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
  2013-09-16  8:09   ` Geert Uytterhoeven
@ 2013-09-16 11:41   ` Tetsuo Handa
  2013-09-16 14:59     ` Kees Cook
  2013-09-16 16:07   ` George Spelvin
  2 siblings, 1 reply; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-16 11:41 UTC (permalink / raw)
  To: keescook, linux-kernel
  Cc: joe, linux, dan.carpenter, viro, JBeulich, kosaki.motohiro, akpm

Kees Cook wrote:
> -	seq_printf(m, "%s%d%n", con->name, con->index, &len);
> -	len = 21 - len;
> +	len = m->count;
> +	seq_printf(m, "%s%d", con->name, con->index);
> +	len = 21 - (m->count - len);

Why not to create a new function which returns bytes written?
The new function does not need to return negative value for indicating errors.
---------- patch start ----------
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 4e32edc..c889cf1 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -91,6 +91,7 @@ int seq_write(struct seq_file *seq, const void *data, size_t len);
 
 __printf(2, 3) int seq_printf(struct seq_file *, const char *, ...);
 __printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args);
+__printf(2, 3) int seq_new_printf(struct seq_file *m, const char *f, ...);
 
 int seq_path(struct seq_file *, const struct path *, const char *);
 int seq_dentry(struct seq_file *, struct dentry *, const char *);
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 3135c25..7af75ec 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -419,6 +419,27 @@ int seq_printf(struct seq_file *m, const char *f, ...)
 EXPORT_SYMBOL(seq_printf);
 
 /**
+ *	seq_new_printf - seq_printf() which returns bytes written.
+ *	@m:	target buffer
+ *	@f:	format
+ *
+ *      Returns bytes written to @m.
+ */
+int seq_new_printf(struct seq_file *m, const char *f, ...)
+{
+	const int count = m->count;
+	int ret;
+	va_list args;
+
+	va_start(args, f);
+	ret = seq_vprintf(m, f, args);
+	va_end(args);
+
+	return ret ? 0 : m->count - count;
+}
+EXPORT_SYMBOL(seq_new_printf);
+
+/**
  *	mangle_path -	mangle and copy path to buffer beginning
  *	@s: buffer start
  *	@p: beginning of path in above buffer
---------- patch end ----------
With new function, we can do:

-	len = m->count;
-	seq_printf(m, "%s%d", con->name, con->index);
-	len = 21 - (m->count - len);
+	len = 21 - seq_new_printf(m, "%s%d", con->name, con->index);

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 11:41   ` Tetsuo Handa
@ 2013-09-16 14:59     ` Kees Cook
  2013-09-16 15:09       ` Joe Perches
  0 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-16 14:59 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: LKML, Joe Perches, George Spelvin, Dan Carpenter, Al Viro,
	Jan Beulich, Motohiro KOSAKI, Andrew Morton

On Mon, Sep 16, 2013 at 4:41 AM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> Kees Cook wrote:
>> -     seq_printf(m, "%s%d%n", con->name, con->index, &len);
>> -     len = 21 - len;
>> +     len = m->count;
>> +     seq_printf(m, "%s%d", con->name, con->index);
>> +     len = 21 - (m->count - len);
>
> Why not to create a new function which returns bytes written?
> The new function does not need to return negative value for indicating errors.

I think it's not worth it for two reasons:

- there are very few callers that need this logic
- it would require a new function for each type of function used
(right now both seq_printf and seq_puts are used).

Perhaps instead of seq->count, there should be an access function?
seq_get_count(seq) or something?

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16  8:09   ` Geert Uytterhoeven
@ 2013-09-16 15:00     ` Kees Cook
  2013-09-17 13:06       ` Tetsuo Handa
  0 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-16 15:00 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-kernel, Joe Perches, George Spelvin, Dan Carpenter,
	Al Viro, Jan Beulich, KOSAKI Motohiro, Tetsuo Handa,
	Andrew Morton

On Mon, Sep 16, 2013 at 1:09 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> On Mon, Sep 16, 2013 at 9:43 AM, Kees Cook <keescook@chromium.org> wrote:
>> All users of %n are calculating padding size when using seq_file, so
>> instead use the new last_len member for discovering the length of the
>> written strings.
>
> Would it make sense to provide a seq_pad(...) function instead, to avoid
> exposing more seq_file internals to its callers?

We'd still need to track how much to pad.

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 14:59     ` Kees Cook
@ 2013-09-16 15:09       ` Joe Perches
  2013-09-16 15:25         ` Kees Cook
  2013-09-16 17:21         ` George Spelvin
  0 siblings, 2 replies; 46+ messages in thread
From: Joe Perches @ 2013-09-16 15:09 UTC (permalink / raw)
  To: Kees Cook
  Cc: Tetsuo Handa, LKML, George Spelvin, Dan Carpenter, Al Viro,
	Jan Beulich, Motohiro KOSAKI, Andrew Morton

On Mon, 2013-09-16 at 07:59 -0700, Kees Cook wrote:
> Perhaps instead of seq->count, there should be an access function?
> seq_get_count(seq) or something?

My thought was to add a seq_last_len()




^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 15:09       ` Joe Perches
@ 2013-09-16 15:25         ` Kees Cook
  2013-09-16 15:44           ` Joe Perches
  2013-09-16 17:21         ` George Spelvin
  1 sibling, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-16 15:25 UTC (permalink / raw)
  To: Joe Perches
  Cc: Tetsuo Handa, LKML, George Spelvin, Dan Carpenter, Al Viro,
	Jan Beulich, Motohiro KOSAKI, Andrew Morton

On Mon, Sep 16, 2013 at 8:09 AM, Joe Perches <joe@perches.com> wrote:
> On Mon, 2013-09-16 at 07:59 -0700, Kees Cook wrote:
>> Perhaps instead of seq->count, there should be an access function?
>> seq_get_count(seq) or something?
>
> My thought was to add a seq_last_len()

That would mean growing the size of the seq_file structure and adding
instructions for all users. While I personally have no problem with
that, I worry others might. If we just use seq->count (or equivalent
function), then only those that want length will use it. I actually
think this uses fewer instructions than %n. Especially in the case
where seq_printf got replaced by seq_puts. :)

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 15:25         ` Kees Cook
@ 2013-09-16 15:44           ` Joe Perches
  0 siblings, 0 replies; 46+ messages in thread
From: Joe Perches @ 2013-09-16 15:44 UTC (permalink / raw)
  To: Kees Cook
  Cc: Tetsuo Handa, LKML, George Spelvin, Dan Carpenter, Al Viro,
	Jan Beulich, Motohiro KOSAKI, Andrew Morton

On Mon, 2013-09-16 at 08:25 -0700, Kees Cook wrote:
> On Mon, Sep 16, 2013 at 8:09 AM, Joe Perches <joe@perches.com> wrote:
> > On Mon, 2013-09-16 at 07:59 -0700, Kees Cook wrote:
> >> Perhaps instead of seq->count, there should be an access function?
> >> seq_get_count(seq) or something?
> >
> > My thought was to add a seq_last_len()
> 
> That would mean growing the size of the seq_file structure and adding
> instructions for all users. While I personally have no problem with
> that, I worry others might.

I don't think adding an int and a size_t is a big deal.

I'm still hoping to hear from Al if expanding the struct
is OK and race-free.

> If we just use seq->count (or equivalent
> function), then only those that want length will use it. I actually
> think this uses fewer instructions than %n. Especially in the case
> where seq_printf got replaced by seq_puts. :)

Shrug.  None of these are inline uses so the overall
code size doesn't change much.

I have patches that make seq_overflow public and replace
the current uses of the seq_printf/seq_puts/seq_putc
returns where appropriate.

Given that I was already touching a lot of the
seq_<foo> calls, I also have patches that convert all
the seq_printf(fmt) (no additional args) to seq_puts()
and all the seq_puts("[single char]") to seq_putc() as
separate patches.



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-16  7:43 [PATCH 0/2] vsprintf: ignore %n again Kees Cook
  2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
  2013-09-16  7:43 ` [PATCH 2/2] vsprintf: ignore %n again Kees Cook
@ 2013-09-16 15:55 ` Al Viro
  2013-09-16 16:15   ` Lars-Peter Clausen
                     ` (2 more replies)
  2 siblings, 3 replies; 46+ messages in thread
From: Al Viro @ 2013-09-16 15:55 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, joe, George Spelvin, dan.carpenter, Jan Beulich,
	KOSAKI Motohiro, Tetsuo Handa, akpm

On Mon, Sep 16, 2013 at 12:43:55AM -0700, Kees Cook wrote:
> Whether seq_printf should return void or error, %n still needs to be removed.
> As such, instead of changing the seq_file structure and adding instructions
> to all callers of seq_printf, just examine seq->count for the callers that
> care about how many characters were put into the buffer, as suggested by
> George Spelvin. First patch removes all %n usage in favor of checking
> seq->count before/after. Second patch makes %n ignore its argument.

This is completely pointless.  *ANY* untrusted format string kernel-side
is pretty much it.  Blocking %n is not "defense in depth", it's security
theater.  Again, if attacker can feed an arbitrary format string to
vsnprintf(), it's over - you've lost.  It's not just about information
leaks vs. ability to store a value of attacker's choosing at the address
of attacker's choosing as it was in userland.  Kernel-side an ability to
trigger read from an arbitrary address is much nastier than information
leak risk; consider iomem, for starters.

What we ought to do is prevention of _that_.  AFAICS, we have reasonably
few call chains that might transmit format string; most of the calls
are with plain and simple string literal.  I wonder if could get away
with reasonable amount of annotations to catch such crap...

Consider, e.g. introducing __vsnprint(), with vsnprintf(s, n, fmt, ...)
expanding to __vsnprintf(1, s, n, fmt, ...) if fmt is a string literal
and __vsnprintf(0, s, n, fmt, ...) otherwise.  Now,
int __sprintf(int safe, char *buf, const char *fmt, ...)
{
        va_list args;
        int i;

        va_start(args, fmt);
        i = __vsnprintf(safe, buf, INT_MAX, fmt, args);
        va_end(args);

        return i;
}
and #define for sprintf (expanding it to either __sprintf(1, ...)
or __sprintf(0, ...)).  That plus similar for snprintf and seq_printf
will already take care of most of the call chains leading to __vsnprintf() -
relatively few calls with have 0 passed to it.  Add WARN_ON(!safe) to
__vsnprintf and we probably won't drown in warnings.  Now, we can start
adding things like that to remaining call chains *and* do things like
replacing
                        snd_iprintf(buffer, fields[i].format,
                                *get_dummy_ll_ptr(dummy, fields[i].offset));
with
			/* fields[i].format is known to be a valid format */
                        __snd_iprintf(1, buffer, fields[i].format,
                                *get_dummy_ll_ptr(dummy, fields[i].offset));
to deal with the places where the origin of format string is provably safe,
but not a string literal (actually, s/1/__FORMAT_IS_SAFE/, to make it
greppable).

Comments?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
  2013-09-16  8:09   ` Geert Uytterhoeven
  2013-09-16 11:41   ` Tetsuo Handa
@ 2013-09-16 16:07   ` George Spelvin
  2013-09-16 16:13     ` Joe Perches
  2 siblings, 1 reply; 46+ messages in thread
From: George Spelvin @ 2013-09-16 16:07 UTC (permalink / raw)
  To: keescook, linux-kernel
  Cc: akpm, dan.carpenter, JBeulich, joe, kosaki.motohiro, linux,
	penguin-kernel, viro

> All users of %n are calculating padding size when using seq_file, so
> instead use the new last_len member for discovering the length of the
> written strings.

Obviously, this comment needs to be updated, but once that is done,
Acked-by: George Spelvin <linux@horizon.com>.

I actually reviewed all the users and checked that things work
properly.  In the various VMA map and tcp state lists, the line
width (128 or the now-misnamed TMPSZ=150) is greatly in excess of
what's required, presumably to facilitate computing the iteration
index from the file position in pre-seqfile days.

If the line were to ever get longer than that, the semantics of
printf("%*s", -5, "") would give strange results, but that's
a pre-existing problem that is unlikely to occur, would probably
be harmless (as would deleting the trailing whitespace!), and
isn't made any worse by this.


HOWEVER, it gave me an idea.  We could put this padding logic straight
into vsprintf and clean up all the callers.

I'm currently thinking that a precision specifier in %c (%.*c) is
currently meaningless and ignored.  What if we usurped it and defined
it to mean "pad with this character until the total width so far this
rint reaches the specified precision"?

That would DTRT for all the callers.

Oh, bugger, gcc -Wformat warns about doing that.  And %#127c.  And
everything else I can think of.  The only way to sneak it past gcc
would be to usurp the rarely-used %-127c format.

Since the only pad character currently used is space, we could omit the
argument and use something like %127%, but gcc gets even more confused
by that.

The code is easy enough.  But any suggestions for ways to represent it
in the format string would be appreciated.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 16:07   ` George Spelvin
@ 2013-09-16 16:13     ` Joe Perches
  2013-09-16 16:39       ` George Spelvin
  0 siblings, 1 reply; 46+ messages in thread
From: Joe Perches @ 2013-09-16 16:13 UTC (permalink / raw)
  To: George Spelvin
  Cc: keescook, linux-kernel, akpm, dan.carpenter, JBeulich,
	kosaki.motohiro, penguin-kernel, viro

On Mon, 2013-09-16 at 12:07 -0400, George Spelvin wrote:
> it gave me an idea.  We could put this padding logic straight
> into vsprintf and clean up all the callers.
[]
> Since the only pad character currently used is space, we could omit the
> argument and use something like %127%, but gcc gets even more confused
> by that.
> 
> The code is easy enough.  But any suggestions for ways to represent it
> in the format string would be appreciated.

%*p<new_type><pad_char> (space assumed if not existing)


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-16 15:55 ` [PATCH 0/2] " Al Viro
@ 2013-09-16 16:15   ` Lars-Peter Clausen
  2013-09-16 16:30   ` George Spelvin
  2013-09-16 18:20   ` Kees Cook
  2 siblings, 0 replies; 46+ messages in thread
From: Lars-Peter Clausen @ 2013-09-16 16:15 UTC (permalink / raw)
  To: Al Viro
  Cc: Kees Cook, linux-kernel, joe, George Spelvin, dan.carpenter,
	Jan Beulich, KOSAKI Motohiro, Tetsuo Handa, akpm

On 09/16/2013 05:55 PM, Al Viro wrote:
> On Mon, Sep 16, 2013 at 12:43:55AM -0700, Kees Cook wrote:
>> Whether seq_printf should return void or error, %n still needs to be removed.
>> As such, instead of changing the seq_file structure and adding instructions
>> to all callers of seq_printf, just examine seq->count for the callers that
>> care about how many characters were put into the buffer, as suggested by
>> George Spelvin. First patch removes all %n usage in favor of checking
>> seq->count before/after. Second patch makes %n ignore its argument.
> 
> This is completely pointless.  *ANY* untrusted format string kernel-side
> is pretty much it.  Blocking %n is not "defense in depth", it's security
> theater.  Again, if attacker can feed an arbitrary format string to
> vsnprintf(), it's over - you've lost.  It's not just about information
> leaks vs. ability to store a value of attacker's choosing at the address
> of attacker's choosing as it was in userland.  Kernel-side an ability to
> trigger read from an arbitrary address is much nastier than information
> leak risk; consider iomem, for starters.
> 
> What we ought to do is prevention of _that_.  AFAICS, we have reasonably
> few call chains that might transmit format string; most of the calls
> are with plain and simple string literal.  I wonder if could get away
> with reasonable amount of annotations to catch such crap...
> 
> Consider, e.g. introducing __vsnprint(), with vsnprintf(s, n, fmt, ...)
> expanding to __vsnprintf(1, s, n, fmt, ...) if fmt is a string literal
> and __vsnprintf(0, s, n, fmt, ...) otherwise.  Now,
> int __sprintf(int safe, char *buf, const char *fmt, ...)
> {
>         va_list args;
>         int i;
> 
>         va_start(args, fmt);
>         i = __vsnprintf(safe, buf, INT_MAX, fmt, args);
>         va_end(args);
> 
>         return i;
> }
> and #define for sprintf (expanding it to either __sprintf(1, ...)
> or __sprintf(0, ...)).  That plus similar for snprintf and seq_printf
> will already take care of most of the call chains leading to __vsnprintf() -
> relatively few calls with have 0 passed to it.  Add WARN_ON(!safe) to
> __vsnprintf and we probably won't drown in warnings.  Now, we can start
> adding things like that to remaining call chains *and* do things like
> replacing
>                         snd_iprintf(buffer, fields[i].format,
>                                 *get_dummy_ll_ptr(dummy, fields[i].offset));
> with
> 			/* fields[i].format is known to be a valid format */
>                         __snd_iprintf(1, buffer, fields[i].format,
>                                 *get_dummy_ll_ptr(dummy, fields[i].offset));
> to deal with the places where the origin of format string is provably safe,
> but not a string literal (actually, s/1/__FORMAT_IS_SAFE/, to make it
> greppable).
> 
> Comments?

I wrote a script the other day, which first recursively collects functions
that somehow end up passing a format string to vsnprintf. And then as a
second step finds all invocations of these functions with a non-const
string. As far as I can tell callers of vsnprintf and friends usually get it
right, it's rather functions that call a function that calls a function that
calls vsnprintf that get misused (There is one subsystem which seems to be
Swiss cheese in regard to this). So doing this just for a few functions
won't help you'd have to do this for all functions that take format strings.

- Lars


^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-16 15:55 ` [PATCH 0/2] " Al Viro
  2013-09-16 16:15   ` Lars-Peter Clausen
@ 2013-09-16 16:30   ` George Spelvin
  2013-09-16 18:20   ` Kees Cook
  2 siblings, 0 replies; 46+ messages in thread
From: George Spelvin @ 2013-09-16 16:30 UTC (permalink / raw)
  To: keescook, viro
  Cc: akpm, dan.carpenter, JBeulich, joe, kosaki.motohiro,
	linux-kernel, linux, penguin-kernel

> This is completely pointless.  *ANY* untrusted format string kernel-side
> is pretty much it.  Blocking %n is not "defense in depth", it's security
> theater.  Again, if attacker can feed an arbitrary format string to
> vsnprintf(), it's over - you've lost.  It's not just about information
> leaks vs. ability to store a value of attacker's choosing at the address
> of attacker's choosing as it was in userland.  Kernel-side an ability to
> trigger read from an arbitrary address is much nastier than information
> leak risk; consider iomem, for starters.

You've got to be kidding.  Yes, sometimes a read can have effects, but
such addresses are rare, not present in the main kernel memory mapping,
and you'd have to find a pointer to such an address (or a preceding
address with no nul bytes in between) on the stack at a known offset when
designing the printf string.  That's tricky, and not always possible.
Even for hardware devices, read side effects have gone out of style,
other than forcing PCI posted writes through.

And just because a hardware read has side effects doesn't mean it's
exploitable.  Being able to drop characters from a serial port is only
a DoS.

On the other hand, the ability to write an arbitrary, attacker-controlled
small integer to any address findable on the stack is very powerful and
easy to exploit.

Those two risks aren't remotely equivalent.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 16:13     ` Joe Perches
@ 2013-09-16 16:39       ` George Spelvin
  2013-09-16 17:53         ` Joe Perches
  0 siblings, 1 reply; 46+ messages in thread
From: George Spelvin @ 2013-09-16 16:39 UTC (permalink / raw)
  To: joe, linux
  Cc: akpm, dan.carpenter, JBeulich, keescook, kosaki.motohiro,
	linux-kernel, penguin-kernel, viro

> %*p<new_type><pad_char> (space assumed if not existing)

Yes, that's the fallback, but it requires an ugly dummy pointer argument.
And some extra kludgery in the code because pointer() doesn't have access
to the start-of-buffer address.

I'd prefer something that could be detected with the information available
in the switch(spec.type) in vsnprintf() itself.

It is, however, available as a last resort.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 15:09       ` Joe Perches
  2013-09-16 15:25         ` Kees Cook
@ 2013-09-16 17:21         ` George Spelvin
  2013-09-16 18:03           ` Joe Perches
  1 sibling, 1 reply; 46+ messages in thread
From: George Spelvin @ 2013-09-16 17:21 UTC (permalink / raw)
  To: joe, keescook
  Cc: akpm, dan.carpenter, JBeulich, kosaki.motohiro, linux-kernel,
	linux, penguin-kernel, viro

> My thought was to add a seq_last_len()

In addition to adding per-call overhead to support a rarely-used feature
(while ->pos comes for free), this has the downside that it matters how
many separate calls are used to generate the string.

The advantage of the "read ->pos before and after" technique is that
you can have an arbitrary number of output calls in between.
Including things like seq_path(), seq_bitmap(), etc.

If you have the printing done in a subroutine (as in the net/ipv4
directory), it would be annoyingly subtle if seq_puts("foobar")
were not equivalent to seq_puts("foo"); seq_puts("bar").


I agree that exposing the internals via ->pos is a bit ugly, but too
many levels of abstraction makes code hard to read, too, and it's very
straightforward to find and fix the dozen or so places where it's accessed
in the unlikely case that the internals of seq_file change significantly.

My take on it is "not worth fixing".

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 16:39       ` George Spelvin
@ 2013-09-16 17:53         ` Joe Perches
  2013-09-16 19:15           ` George Spelvin
  0 siblings, 1 reply; 46+ messages in thread
From: Joe Perches @ 2013-09-16 17:53 UTC (permalink / raw)
  To: George Spelvin
  Cc: akpm, dan.carpenter, JBeulich, keescook, kosaki.motohiro,
	linux-kernel, penguin-kernel, viro

On Mon, 2013-09-16 at 12:39 -0400, George Spelvin wrote:
> > %*p<new_type><pad_char> (space assumed if not existing)
> 
> Yes, that's the fallback, but it requires an ugly dummy pointer argument.
> And some extra kludgery in the code because pointer() doesn't have access
> to the start-of-buffer address.
>
> I'd prefer something that could be detected with the information available
> in the switch(spec.type) in vsnprintf() itself.

Bad argument I think.

It'd be consistent with all the other %p<foo> types.

vsnprintf is already weird enough with %p uses,
there's absolutely no reason to stretch it further
with yet another odd access/format style.



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 17:21         ` George Spelvin
@ 2013-09-16 18:03           ` Joe Perches
  0 siblings, 0 replies; 46+ messages in thread
From: Joe Perches @ 2013-09-16 18:03 UTC (permalink / raw)
  To: George Spelvin
  Cc: keescook, akpm, dan.carpenter, JBeulich, kosaki.motohiro,
	linux-kernel, penguin-kernel, viro

On Mon, 2013-09-16 at 13:21 -0400, George Spelvin wrote:
> > My thought was to add a seq_last_len()
> 
> In addition to adding per-call overhead to support a rarely-used feature
> (while ->pos comes for free), this has the downside that it matters how
> many separate calls are used to generate the string.
> 
> The advantage of the "read ->pos before and after" technique is that
> you can have an arbitrary number of output calls in between.
> Including things like seq_path(), seq_bitmap(), etc.
> 
> If you have the printing done in a subroutine (as in the net/ipv4
> directory), it would be annoyingly subtle if seq_puts("foobar")
> were not equivalent to seq_puts("foo"); seq_puts("bar").

It's already true that those aren't equivalent.
	seq_puts(seq, "short ");
	set_puts(seq, "string");
may fit the first bit into the output buffer but not the last
where
	setq_puts(seq, "short string");
would not fit at all.

btw: who are you?  Is your name really George Spelvin?




^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-16 15:55 ` [PATCH 0/2] " Al Viro
  2013-09-16 16:15   ` Lars-Peter Clausen
  2013-09-16 16:30   ` George Spelvin
@ 2013-09-16 18:20   ` Kees Cook
  2013-09-18 13:14     ` Tetsuo Handa
  2 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-16 18:20 UTC (permalink / raw)
  To: Al Viro
  Cc: LKML, Joe Perches, George Spelvin, Dan Carpenter, Jan Beulich,
	KOSAKI Motohiro, Tetsuo Handa, Andrew Morton

On Mon, Sep 16, 2013 at 8:55 AM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Mon, Sep 16, 2013 at 12:43:55AM -0700, Kees Cook wrote:
>> Whether seq_printf should return void or error, %n still needs to be removed.
>> As such, instead of changing the seq_file structure and adding instructions
>> to all callers of seq_printf, just examine seq->count for the callers that
>> care about how many characters were put into the buffer, as suggested by
>> George Spelvin. First patch removes all %n usage in favor of checking
>> seq->count before/after. Second patch makes %n ignore its argument.
>
> This is completely pointless.  *ANY* untrusted format string kernel-side
> is pretty much it.  Blocking %n is not "defense in depth", it's security
> theater.  Again, if attacker can feed an arbitrary format string to
> vsnprintf(), it's over - you've lost.  It's not just about information
> leaks vs. ability to store a value of attacker's choosing at the address
> of attacker's choosing as it was in userland.  Kernel-side an ability to
> trigger read from an arbitrary address is much nastier than information
> leak risk; consider iomem, for starters.

I completely disagree. (Surprise!) Eliminating %n _does_ change
things. Why have the risk when solutions for getting the same behavior
take fewer instructions and are safer? Yes, I agree that arbitrary
format strings are still a very very bad thing, but %n makes it an
order of magnitude worse. Attacking format strings with %n is very
well understood by exploiters, so why give them this primitive for no
sensible reason?

> What we ought to do is prevention of _that_.  AFAICS, we have reasonably
> few call chains that might transmit format string; most of the calls
> are with plain and simple string literal.  I wonder if could get away
> with reasonable amount of annotations to catch such crap...

Yes. And if gcc would ignore const char arguments, we could do this:

diff --git a/Makefile b/Makefile
index e73f758..2bc680b 100644
--- a/Makefile
+++ b/Makefile
@@ -372,7 +372,6 @@ KBUILD_CPPFLAGS := -D__KERNEL__
 KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
                   -fno-strict-aliasing -fno-common \
                   -Werror-implicit-function-declaration \
-                  -Wno-format-security \
                   -fno-delete-null-pointer-checks
 KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
@@ -659,6 +658,11 @@ KBUILD_CFLAGS      += $(call cc-option,-fno-strict-overflow
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)

+# Enable format-security when it can stop the build, otherwise disable.
+KBUILD_CFLAGS  += $(call cc-option,\
+                       -Wformat -Wformat-security -Werror=format-security,\
+                       -Wno-format-security)
+
 # use the deterministic mode of AR if available
 KBUILD_ARFLAGS := $(call ar-option,D)

I have a patch series that fixes all the warnings produced by gcc in
this state. All of our printf uses are already marked up in the
kernel, so this checks them all.

> Consider, e.g. introducing __vsnprint(), with vsnprintf(s, n, fmt, ...)
> expanding to __vsnprintf(1, s, n, fmt, ...) if fmt is a string literal
> and __vsnprintf(0, s, n, fmt, ...) otherwise.  Now,
> int __sprintf(int safe, char *buf, const char *fmt, ...)
> {
>         va_list args;
>         int i;
>
>         va_start(args, fmt);
>         i = __vsnprintf(safe, buf, INT_MAX, fmt, args);
>         va_end(args);
>
>         return i;
> }
> and #define for sprintf (expanding it to either __sprintf(1, ...)
> or __sprintf(0, ...)).  That plus similar for snprintf and seq_printf
> will already take care of most of the call chains leading to __vsnprintf() -
> relatively few calls with have 0 passed to it.  Add WARN_ON(!safe) to
> __vsnprintf and we probably won't drown in warnings.  Now, we can start
> adding things like that to remaining call chains *and* do things like
> replacing
>                         snd_iprintf(buffer, fields[i].format,
>                                 *get_dummy_ll_ptr(dummy, fields[i].offset));
> with
>                         /* fields[i].format is known to be a valid format */
>                         __snd_iprintf(1, buffer, fields[i].format,
>                                 *get_dummy_ll_ptr(dummy, fields[i].offset));
> to deal with the places where the origin of format string is provably safe,
> but not a string literal (actually, s/1/__FORMAT_IS_SAFE/, to make it
> greppable).

Unless I've misunderstood, I think we'd already get very close to this
with the gcc options instead. This patch set is what I've been using
to generate the format string fixes over the last few months, with 7
sent this last round:

http://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/log/?h=format-security

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 17:53         ` Joe Perches
@ 2013-09-16 19:15           ` George Spelvin
  2013-09-16 19:25             ` Joe Perches
  0 siblings, 1 reply; 46+ messages in thread
From: George Spelvin @ 2013-09-16 19:15 UTC (permalink / raw)
  To: joe, linux
  Cc: akpm, dan.carpenter, JBeulich, keescook, kosaki.motohiro,
	linux-kernel, penguin-kernel, viro

> It'd be consistent with all the other %p<foo> types.
>
> vsnprintf is already weird enough with %p uses,
> there's absolutely no reason to stretch it further
> with yet another odd access/format style.

Well, all the other %p<foo> types actually *use* the void * argument.
They print the thing pointed to, just in different ways.

What I'm proposing is fundamentally different, and much more
"printf internals" specific.

I hate creating an interface that requires a dummy pointer argument.

This would already be quite different in , and I hate creating a
new interface that requires a dummy pointer argument.


One nonsensical combination that gcc does *not* complain about
is "%0-c".  (It does bitch about "%-0c", however.)

Is "%0-127c" too ugly to live?

Note that I could generalize it, and allow "%0-<width>" to mean
"left-align, with trailing padding to column <width>" for ANY format
specifier if that would help.  It's easy in the printf code to compute
the field width necessary to make that work.
ANSI C says that %0- is permitted and means the same thing as %-
(- overrides 0), but that could be bent.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 19:15           ` George Spelvin
@ 2013-09-16 19:25             ` Joe Perches
  0 siblings, 0 replies; 46+ messages in thread
From: Joe Perches @ 2013-09-16 19:25 UTC (permalink / raw)
  To: George Spelvin
  Cc: akpm, dan.carpenter, JBeulich, keescook, kosaki.motohiro,
	linux-kernel, penguin-kernel, viro

On Mon, 2013-09-16 at 15:15 -0400, George Spelvin wrote:
> > It'd be consistent with all the other %p<foo> types.
> >
> > vsnprintf is already weird enough with %p uses,
> > there's absolutely no reason to stretch it further
> > with yet another odd access/format style.
> 
> Well, all the other %p<foo> types actually *use* the void * argument.
> They print the thing pointed to, just in different ways.
> 
> What I'm proposing is fundamentally different, and much more
> "printf internals" specific.
> 
> I hate creating an interface that requires a dummy pointer argument.
[]
> Is "%0-127c" too ugly to live?

Yes.

I suppose you use "%[-]*pV" if you really want funky/fugly.



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-16 15:00     ` Kees Cook
@ 2013-09-17 13:06       ` Tetsuo Handa
  2013-09-17 14:34         ` Kees Cook
  0 siblings, 1 reply; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-17 13:06 UTC (permalink / raw)
  To: keescook, geert
  Cc: linux-kernel, joe, linux, dan.carpenter, viro, JBeulich,
	kosaki.motohiro, akpm

Kees Cook wrote:
> On Mon, Sep 16, 2013 at 1:09 AM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
> > On Mon, Sep 16, 2013 at 9:43 AM, Kees Cook <keescook@chromium.org> wrote:
> >> All users of %n are calculating padding size when using seq_file, so
> >> instead use the new last_len member for discovering the length of the
> >> written strings.
> >
> > Would it make sense to provide a seq_pad(...) function instead, to avoid
> > exposing more seq_file internals to its callers?
> 
> We'd still need to track how much to pad.

If we add "size_t pad_until;" to "struct seq_file", we can do

void seq_setwidth(struct seq_file *m, size_t size)
{
	m->pad_until = m->count + size;
}

void seq_pad(struct seq_file *m, char c)
{
	int size = m->pad_until - m->count;
	if (size > 0)
		seq_printf(m, "%*s", size, "");
	if (c)
		seq_putc(m, c);
}

and use like

  seq_setwidth(m, 21);
  seq_printf(m, "%s%d", con->name, con->index);
  seq_pad(m, '\n');

.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-17 13:06       ` Tetsuo Handa
@ 2013-09-17 14:34         ` Kees Cook
  2013-09-17 20:57           ` George Spelvin
  0 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-17 14:34 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Geert Uytterhoeven, LKML, Joe Perches, George Spelvin,
	Dan Carpenter, Al Viro, Jan Beulich, Motohiro KOSAKI,
	Andrew Morton

On Tue, Sep 17, 2013 at 6:06 AM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> Kees Cook wrote:
>> On Mon, Sep 16, 2013 at 1:09 AM, Geert Uytterhoeven
>> <geert@linux-m68k.org> wrote:
>> > On Mon, Sep 16, 2013 at 9:43 AM, Kees Cook <keescook@chromium.org> wrote:
>> >> All users of %n are calculating padding size when using seq_file, so
>> >> instead use the new last_len member for discovering the length of the
>> >> written strings.
>> >
>> > Would it make sense to provide a seq_pad(...) function instead, to avoid
>> > exposing more seq_file internals to its callers?
>>
>> We'd still need to track how much to pad.
>
> If we add "size_t pad_until;" to "struct seq_file", we can do
>
> void seq_setwidth(struct seq_file *m, size_t size)
> {
>         m->pad_until = m->count + size;
> }
>
> void seq_pad(struct seq_file *m, char c)
> {
>         int size = m->pad_until - m->count;
>         if (size > 0)
>                 seq_printf(m, "%*s", size, "");
>         if (c)
>                 seq_putc(m, c);
> }
>
> and use like
>
>   seq_setwidth(m, 21);
>   seq_printf(m, "%s%d", con->name, con->index);
>   seq_pad(m, '\n');

Ooh, I like this a lot! Much cleaner.

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-17 14:34         ` Kees Cook
@ 2013-09-17 20:57           ` George Spelvin
  2013-09-19  8:56             ` Tetsuo Handa
  0 siblings, 1 reply; 46+ messages in thread
From: George Spelvin @ 2013-09-17 20:57 UTC (permalink / raw)
  To: keescook, penguin-kernel
  Cc: akpm, dan.carpenter, geert, JBeulich, joe, kosaki.motohiro,
	linux-kernel, linux, viro

>>   seq_setwidth(m, 21);
>>   seq_printf(m, "%s%d", con->name, con->index);
>>   seq_pad(m, '\n');

> Ooh, I like this a lot! Much cleaner.

That's certainly a good way to do it, too.
My "general principles" filter thinks it should be in a local variable
if it can, but if hiding it in the struct seq_file is fine if people
find that cleaner.

seq_pad could also reset the field to some null value and warn if
it's found in that state.  Not a strong preference, though; the error is
fairly harmless and you might not feel it's worth the code size.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-16 18:20   ` Kees Cook
@ 2013-09-18 13:14     ` Tetsuo Handa
  2013-09-18 14:11       ` Dan Carpenter
                         ` (2 more replies)
  0 siblings, 3 replies; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-18 13:14 UTC (permalink / raw)
  To: keescook, viro
  Cc: linux-kernel, joe, linux, dan.carpenter, JBeulich, kosaki.motohiro, akpm

Kees Cook wrote:
> > Consider, e.g. introducing __vsnprint(), with vsnprintf(s, n, fmt, ...)
> > expanding to __vsnprintf(1, s, n, fmt, ...) if fmt is a string literal
> > and __vsnprintf(0, s, n, fmt, ...) otherwise.  Now,
> > int __sprintf(int safe, char *buf, const char *fmt, ...)
> > {
> >         va_list args;
> >         int i;
> >
> >         va_start(args, fmt);
> >         i = __vsnprintf(safe, buf, INT_MAX, fmt, args);
> >         va_end(args);
> >
> >         return i;
> > }
> 
> Unless I've misunderstood, I think we'd already get very close to this
> with the gcc options instead. This patch set is what I've been using
> to generate the format string fixes over the last few months, with 7
> sent this last round:

Can we utilize __builtin_constant_p() ?

---------- source start ----------
#include <stdio.h>

#define func(fmt)                                       \
        if (__builtin_constant_p(fmt))                  \
                printf("const : %s\n", fmt);            \
        else                                            \
                printf("not const : %s\n", fmt);        \


int main(int argc, char *argv[])
{
        const char *fmt1 = "const char *";
        const char fmt2[] = "const char []";
        const char * const fmt3 = "const char * const";
        func("literal");
        func(fmt1);
        func(fmt2);
        func(fmt3);
        return 0;
}
---------- source end ----------

---------- output start ----------
const : literal
not const : const char *
not const : const char []
const : const char * const
---------- output end ----------

__builtin_constant_p() seems to enforce use of either "literal" or "* const".

An example change

---------- patch start ----------
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -120,8 +120,9 @@ asmlinkage int printk_emit(int facility, int level,
                           const char *dict, size_t dictlen,
                           const char *fmt, ...);
 
-asmlinkage __printf(1, 2) __cold
-int printk(const char *fmt, ...);
+//asmlinkage __printf(1, 2) __cold
+//int printk(const char *fmt, ...);
+#define printk(fmt, ...) compiletime_assert(__builtin_constant_p(fmt), "Non-c  onstant format string")
 
 /*
  * Special printk facility for scheduler use only, _DO_NOT_USE_ !
---------- patch end ----------

caught errors like below.

  CC [M]  drivers/scsi/esas2r/esas2r_log.o
drivers/scsi/esas2r/esas2r_log.c: In function 'esas2r_log_master':
drivers/scsi/esas2r/esas2r_log.c:174: error: call to '__compiletime_assert_174' declared with attribute error: Non-constant format string

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-18 13:14     ` Tetsuo Handa
@ 2013-09-18 14:11       ` Dan Carpenter
  2013-09-18 14:28         ` Dan Carpenter
  2013-09-18 15:22         ` George Spelvin
  2013-09-18 14:32       ` Kees Cook
  2013-09-18 14:47       ` Kees Cook
  2 siblings, 2 replies; 46+ messages in thread
From: Dan Carpenter @ 2013-09-18 14:11 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: keescook, viro, linux-kernel, joe, linux, JBeulich,
	kosaki.motohiro, akpm

Sure.  There are a lot of non-const strings though.

diff --git a/include/linux/printk.h b/include/linux/printk.h
index e6131a78..317587b 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -122,6 +122,11 @@ asmlinkage int printk_emit(int facility, int level,
 
 asmlinkage __printf(1, 2) __cold
 int printk(const char *fmt, ...);
+#define printk(fmt, ...) do {				  \
+	compiletime_assert(__builtin_constant_p(fmt),     \
+			   "Non-constant format string"); \
+	printk(fmt, ##__VA_ARGS__);			  \
+} while (0)
 
 /*
  * Special printk facility for scheduler use only, _DO_NOT_USE_ !

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-18 14:11       ` Dan Carpenter
@ 2013-09-18 14:28         ` Dan Carpenter
  2013-09-18 15:22         ` George Spelvin
  1 sibling, 0 replies; 46+ messages in thread
From: Dan Carpenter @ 2013-09-18 14:28 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: keescook, viro, linux-kernel, joe, linux, JBeulich,
	kosaki.motohiro, akpm

On Wed, Sep 18, 2013 at 05:11:04PM +0300, Dan Carpenter wrote:
>  asmlinkage __printf(1, 2) __cold
>  int printk(const char *fmt, ...);
> +#define printk(fmt, ...) do {				  \
> +	compiletime_assert(__builtin_constant_p(fmt),     \
> +			   "Non-constant format string"); \
> +	printk(fmt, ##__VA_ARGS__);			  \
> +} while (0)

Oops...  That breaks the compile for printk.c.

Also don't we want 'const char fmt[] = "foo %s";' to be a valid format
string?

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-18 13:14     ` Tetsuo Handa
  2013-09-18 14:11       ` Dan Carpenter
@ 2013-09-18 14:32       ` Kees Cook
  2013-09-19  2:11         ` Tetsuo Handa
  2013-09-18 14:47       ` Kees Cook
  2 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-18 14:32 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Al Viro, LKML, Joe Perches, George Spelvin, Dan Carpenter,
	Jan Beulich, Motohiro KOSAKI, Andrew Morton

On Wed, Sep 18, 2013 at 6:14 AM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> Kees Cook wrote:
>> > Consider, e.g. introducing __vsnprint(), with vsnprintf(s, n, fmt, ...)
>> > expanding to __vsnprintf(1, s, n, fmt, ...) if fmt is a string literal
>> > and __vsnprintf(0, s, n, fmt, ...) otherwise.  Now,
>> > int __sprintf(int safe, char *buf, const char *fmt, ...)
>> > {
>> >         va_list args;
>> >         int i;
>> >
>> >         va_start(args, fmt);
>> >         i = __vsnprintf(safe, buf, INT_MAX, fmt, args);
>> >         va_end(args);
>> >
>> >         return i;
>> > }
>>
>> Unless I've misunderstood, I think we'd already get very close to this
>> with the gcc options instead. This patch set is what I've been using
>> to generate the format string fixes over the last few months, with 7
>> sent this last round:
>
> Can we utilize __builtin_constant_p() ?

This seems promising.

>
> ---------- source start ----------
> #include <stdio.h>
>
> #define func(fmt)                                       \
>         if (__builtin_constant_p(fmt))                  \
>                 printf("const : %s\n", fmt);            \
>         else                                            \
>                 printf("not const : %s\n", fmt);        \
>
>
> int main(int argc, char *argv[])
> {
>         const char *fmt1 = "const char *";
>         const char fmt2[] = "const char []";
>         const char * const fmt3 = "const char * const";
>         func("literal");
>         func(fmt1);
>         func(fmt2);
>         func(fmt3);
>         return 0;
> }
> ---------- source end ----------
>
> ---------- output start ----------
> const : literal
> not const : const char *
> not const : const char []
> const : const char * const

What version of gcc did you use? I don't get the last as const, for
some reason. And as Dan mentions, shouldn't const char[] be detected
as const too?

-Kees

> ---------- output end ----------
>
> __builtin_constant_p() seems to enforce use of either "literal" or "* const".
>
> An example change
>
> ---------- patch start ----------
> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -120,8 +120,9 @@ asmlinkage int printk_emit(int facility, int level,
>                            const char *dict, size_t dictlen,
>                            const char *fmt, ...);
>
> -asmlinkage __printf(1, 2) __cold
> -int printk(const char *fmt, ...);
> +//asmlinkage __printf(1, 2) __cold
> +//int printk(const char *fmt, ...);
> +#define printk(fmt, ...) compiletime_assert(__builtin_constant_p(fmt), "Non-c  onstant format string")
>
>  /*
>   * Special printk facility for scheduler use only, _DO_NOT_USE_ !
> ---------- patch end ----------
>
> caught errors like below.
>
>   CC [M]  drivers/scsi/esas2r/esas2r_log.o
> drivers/scsi/esas2r/esas2r_log.c: In function 'esas2r_log_master':
> drivers/scsi/esas2r/esas2r_log.c:174: error: call to '__compiletime_assert_174' declared with attribute error: Non-constant format string



-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-18 13:14     ` Tetsuo Handa
  2013-09-18 14:11       ` Dan Carpenter
  2013-09-18 14:32       ` Kees Cook
@ 2013-09-18 14:47       ` Kees Cook
  2 siblings, 0 replies; 46+ messages in thread
From: Kees Cook @ 2013-09-18 14:47 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Al Viro, LKML, Joe Perches, George Spelvin, Dan Carpenter,
	Jan Beulich, Motohiro KOSAKI, Andrew Morton

On Wed, Sep 18, 2013 at 6:14 AM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> Kees Cook wrote:
>> > Consider, e.g. introducing __vsnprint(), with vsnprintf(s, n, fmt, ...)
>> > expanding to __vsnprintf(1, s, n, fmt, ...) if fmt is a string literal
>> > and __vsnprintf(0, s, n, fmt, ...) otherwise.  Now,
>> > int __sprintf(int safe, char *buf, const char *fmt, ...)
>> > {
>> >         va_list args;
>> >         int i;
>> >
>> >         va_start(args, fmt);
>> >         i = __vsnprintf(safe, buf, INT_MAX, fmt, args);
>> >         va_end(args);
>> >
>> >         return i;
>> > }
>>
>> Unless I've misunderstood, I think we'd already get very close to this
>> with the gcc options instead. This patch set is what I've been using
>> to generate the format string fixes over the last few months, with 7
>> sent this last round:
>
> Can we utilize __builtin_constant_p() ?
>
> ---------- source start ----------
> #include <stdio.h>
>
> #define func(fmt)                                       \
>         if (__builtin_constant_p(fmt))                  \
>                 printf("const : %s\n", fmt);            \
>         else                                            \
>                 printf("not const : %s\n", fmt);        \
>
>
> int main(int argc, char *argv[])
> {
>         const char *fmt1 = "const char *";
>         const char fmt2[] = "const char []";
>         const char * const fmt3 = "const char * const";
>         func("literal");
>         func(fmt1);
>         func(fmt2);
>         func(fmt3);

I wonder if we can get at the read-only knowledge. Doing this shows
that gcc knows they're read-only:

fmt1[2] = 'A';
fmt2[2] = 'A';
fmt3[2] = 'A';

/tmp/const.c:27:5: error: assignment of read-only location ‘*(fmt1 + 2u)’
/tmp/const.c:29:5: error: assignment of read-only location ‘fmt2[2]’
/tmp/const.c:31:5: error: assignment of read-only location ‘*(fmt3 + 2u)’

I didn't see a builtin for this in the gcc documentation I've been reading.

-Kees

>         return 0;
> }
> ---------- source end ----------
>
> ---------- output start ----------
> const : literal
> not const : const char *
> not const : const char []
> const : const char * const
> ---------- output end ----------
>
> __builtin_constant_p() seems to enforce use of either "literal" or "* const".
>
> An example change
>
> ---------- patch start ----------
> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -120,8 +120,9 @@ asmlinkage int printk_emit(int facility, int level,
>                            const char *dict, size_t dictlen,
>                            const char *fmt, ...);
>
> -asmlinkage __printf(1, 2) __cold
> -int printk(const char *fmt, ...);
> +//asmlinkage __printf(1, 2) __cold
> +//int printk(const char *fmt, ...);
> +#define printk(fmt, ...) compiletime_assert(__builtin_constant_p(fmt), "Non-c  onstant format string")
>
>  /*
>   * Special printk facility for scheduler use only, _DO_NOT_USE_ !
> ---------- patch end ----------
>
> caught errors like below.
>
>   CC [M]  drivers/scsi/esas2r/esas2r_log.o
> drivers/scsi/esas2r/esas2r_log.c: In function 'esas2r_log_master':
> drivers/scsi/esas2r/esas2r_log.c:174: error: call to '__compiletime_assert_174' declared with attribute error: Non-constant format string



-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-18 14:11       ` Dan Carpenter
  2013-09-18 14:28         ` Dan Carpenter
@ 2013-09-18 15:22         ` George Spelvin
  1 sibling, 0 replies; 46+ messages in thread
From: George Spelvin @ 2013-09-18 15:22 UTC (permalink / raw)
  To: dan.carpenter, penguin-kernel
  Cc: akpm, JBeulich, joe, keescook, kosaki.motohiro, linux-kernel,
	linux, viro

> +#define printk(fmt, ...) do {				  \
> +	compiletime_assert(__builtin_constant_p(fmt),     \
> +			   "Non-constant format string"); \
> +	printk(fmt, ##__VA_ARGS__);			  \
> +} while (0)

May I recommend __builtin_constant_p(*fmt).  Since:

char buf[OVERFLOW_VULNERABILITY];
strcpy(buf, malicious_format);
printk(buf, args)

has __builtin_constant_p(buf), but it's not a constant format string.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-18 14:32       ` Kees Cook
@ 2013-09-19  2:11         ` Tetsuo Handa
  2013-09-19  7:08           ` Tetsuo Handa
  0 siblings, 1 reply; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-19  2:11 UTC (permalink / raw)
  To: keescook
  Cc: viro, linux-kernel, joe, linux, dan.carpenter, JBeulich,
	kosaki.motohiro, akpm

Kees Cook wrote:
> > ---------- output start ----------
> > const : literal
> > not const : const char *
> > not const : const char []
> > const : const char * const
> 
> What version of gcc did you use? I don't get the last as const, for
> some reason. And as Dan mentions, shouldn't const char[] be detected
> as const too?

This worked on

  gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)
  gcc (GCC) 3.3.5 (Debian 1:3.3.5-13)

with -On (where n != 0), but didn't work on

  gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

. Oops...

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 0/2] vsprintf: ignore %n again
  2013-09-19  2:11         ` Tetsuo Handa
@ 2013-09-19  7:08           ` Tetsuo Handa
  0 siblings, 0 replies; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-19  7:08 UTC (permalink / raw)
  To: keescook
  Cc: viro, linux-kernel, joe, linux, dan.carpenter, JBeulich,
	kosaki.motohiro, akpm

If the code to test is built into vmlinux, we could use run-time checking like

----------
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1601,6 +1601,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 	if (WARN_ON_ONCE((int) size < 0))
 		return 0;
 
+	if (!(__start_rodata <= fmt && fmt < __end_rodata)) {
+		static unsigned char warn = 100;
+		WARN(warn && warn--, "Format string is not in RODATA section.");
+	}
+
 	str = buf;
 	end = buf + size;
 
----------

which reports errors like below.

[    0.814121] ------------[ cut here ]------------
[    0.814985] WARNING: CPU: 0 PID: 1 at lib/vsprintf.c:1606 vsnprintf+0xb4/0x3f0()
[    0.816036] Format string is not in RODATA section.
[    0.816883] Modules linked in:
[    0.817490] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.12.0-rc1-00046-g9baa505-dirty #180
[    0.818974] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007
[    0.820040]  00000646 00000000 df079dc0 c02eae66 df079dcc c02eaead c02f3684 df079df8
[    0.821538]  c01422a9 c061bc40 df079e28 00000001 c061bc31 00000646 c02f3684 df079e08
[    0.822995]  00000646 c061bc40 df079e14 c0142301 00000009 df079e08 c061bc40 df079e28
[    0.824676] Call Trace:
[    0.825124]  [<c02eae66>] __dump_stack+0x16/0x20
[    0.825922]  [<c02eaead>] dump_stack+0x3d/0x60
[    0.826691]  [<c02f3684>] ? vsnprintf+0xb4/0x3f0
[    0.827478]  [<c01422a9>] warn_slowpath_common+0x79/0xa0
[    0.828040]  [<c02f3684>] ? vsnprintf+0xb4/0x3f0
[    0.828917]  [<c0142301>] warn_slowpath_fmt+0x31/0x40
[    0.829798]  [<c02f3684>] vsnprintf+0xb4/0x3f0
[    0.830584]  [<c0199d2b>] ? trace_hardirqs_on+0xb/0x10
[    0.832050]  [<c02f70f4>] kvasprintf+0x24/0x60
[    0.832831]  [<c02ed1c1>] kobject_set_name_vargs+0x21/0x60
[    0.833850]  [<c02ed2c1>] kobject_add_varg+0x21/0x50
[    0.834750]  [<c02ed379>] kobject_init_and_add+0x29/0x30
[    0.835699]  [<c01f9fd3>] sysfs_slab_add+0x63/0xe0
[    0.836055]  [<c06ec630>] ? kmem_cache_init_late+0x10/0x10
[    0.837054]  [<c06ec6a7>] slab_sysfs_init+0x77/0x110
[    0.838025]  [<c06ec251>] ? procswaps_init+0x21/0x30
[    0.838958]  [<c0100472>] do_one_initcall+0x32/0xd0
[    0.840046]  [<c015fb60>] ? parse_one+0xc0/0xe0
[    0.840852]  [<c015fd0a>] ? parse_args+0x7a/0x170
[    0.841676]  [<c06cf410>] ? loglevel+0x30/0x30
[    0.842443]  [<c06cfb6a>] do_initcall_level+0x7a/0x90
[    0.843338]  [<c06cf410>] ? loglevel+0x30/0x30
[    0.844038]  [<c06cfb98>] do_initcalls+0x18/0x20
[    0.844960]  [<c06cfbc8>] do_basic_setup+0x28/0x30
[    0.845894]  [<c06cfc7f>] kernel_init_freeable+0x5f/0xf0
[    0.846907]  [<c04c523b>] kernel_init+0xb/0xe0
[    0.848045]  [<c04cc718>] ret_from_kernel_thread+0x1c/0x2c
[    0.849070]  [<c04c5230>] ? rest_init+0x140/0x140
[    0.849987] ---[ end trace c57fc7b42d34a992 ]---

----------
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -5136,7 +5136,7 @@ static int sysfs_slab_add(struct kmem_cache *s)
 	}
 
 	s->kobj.kset = slab_kset;
-	err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, name);
+	err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, "%s", name);
 	if (err) {
 		kobject_put(&s->kobj);
 		return err;
----------

But tools like sparse might find such bugs better?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-17 20:57           ` George Spelvin
@ 2013-09-19  8:56             ` Tetsuo Handa
  2013-09-19 14:28               ` Kees Cook
  0 siblings, 1 reply; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-19  8:56 UTC (permalink / raw)
  To: linux, keescook
  Cc: akpm, dan.carpenter, geert, JBeulich, joe, kosaki.motohiro,
	linux-kernel, viro

George Spelvin wrote:
> >>   seq_setwidth(m, 21);
> >>   seq_printf(m, "%s%d", con->name, con->index);
> >>   seq_pad(m, '\n');
> 
> > Ooh, I like this a lot! Much cleaner.
> 
> That's certainly a good way to do it, too.
> My "general principles" filter thinks it should be in a local variable
> if it can, but if hiding it in the struct seq_file is fine if people
> find that cleaner.

I think the good point of seq_file is that users don't need to worry about
length calculation for overflow detection. This patch helps users to simplify
length calculation for alignment. I think this approach is better if adding
a size_t to the seq_file is acceptable.

So, the patch follows.
----------------------------------------
>From 02b28fd709971f71e5de9a5b595ff4fd059028b3 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Date: Thu, 19 Sep 2013 17:23:17 +0900
Subject: [PATCH] seq_file: Introduce seq_setwidth() and seq_pad()

There are several users who want to know bytes written by seq_*() for alignment
purpose. Currently they are using %n format for knowing it because seq_*()
returns 0 on success.

This patch introduces seq_setwidth() and seq_pad() for allowing them to align
without using %n format.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 fs/seq_file.c            |   15 +++++++++++++++
 include/linux/seq_file.h |   15 +++++++++++++++
 2 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/fs/seq_file.c b/fs/seq_file.c
index 3135c25..40e471e 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -764,6 +764,21 @@ int seq_write(struct seq_file *seq, const void *data, size_t len)
 }
 EXPORT_SYMBOL(seq_write);
 
+/**
+ * seq_pad - write padding spaces to buffer
+ * @m: seq_file identifying the buffer to which data should be written
+ * @c: the byte to append after padding if non-zero
+ */
+void seq_pad(struct seq_file *m, char c)
+{
+	int size = m->pad_until - m->count;
+	if (size > 0)
+		seq_printf(m, "%*s", size, "");
+	if (c)
+		seq_putc(m, c);
+}
+EXPORT_SYMBOL(seq_pad);
+
 struct list_head *seq_list_start(struct list_head *head, loff_t pos)
 {
 	struct list_head *lh;
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 4e32edc..52e0097 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -20,6 +20,7 @@ struct seq_file {
 	size_t size;
 	size_t from;
 	size_t count;
+	size_t pad_until;
 	loff_t index;
 	loff_t read_pos;
 	u64 version;
@@ -79,6 +80,20 @@ static inline void seq_commit(struct seq_file *m, int num)
 	}
 }
 
+/**
+ * seq_setwidth - set padding width
+ * @m: the seq_file handle
+ * @size: the max number of bytes to pad.
+ *
+ * Call seq_setwidth() for setting max width, then call seq_printf() etc. and
+ * finally call seq_pad() to pad the remaining bytes.
+ */
+static inline void seq_setwidth(struct seq_file *m, size_t size)
+{
+	m->pad_until = m->count + size;
+}
+void seq_pad(struct seq_file *m, char c);
+
 char *mangle_path(char *s, const char *p, const char *esc);
 int seq_open(struct file *, const struct seq_operations *);
 ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-19  8:56             ` Tetsuo Handa
@ 2013-09-19 14:28               ` Kees Cook
  2013-09-20  4:09                 ` Tetsuo Handa
  0 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-19 14:28 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: George Spelvin, Andrew Morton, Dan Carpenter, Geert Uytterhoeven,
	Jan Beulich, Joe Perches, Motohiro KOSAKI, LKML, Al Viro

On Thu, Sep 19, 2013 at 1:56 AM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> George Spelvin wrote:
>> >>   seq_setwidth(m, 21);
>> >>   seq_printf(m, "%s%d", con->name, con->index);
>> >>   seq_pad(m, '\n');
>>
>> > Ooh, I like this a lot! Much cleaner.
>>
>> That's certainly a good way to do it, too.
>> My "general principles" filter thinks it should be in a local variable
>> if it can, but if hiding it in the struct seq_file is fine if people
>> find that cleaner.
>
> I think the good point of seq_file is that users don't need to worry about
> length calculation for overflow detection. This patch helps users to simplify
> length calculation for alignment. I think this approach is better if adding
> a size_t to the seq_file is acceptable.
>
> So, the patch follows.
> ----------------------------------------
> >From 02b28fd709971f71e5de9a5b595ff4fd059028b3 Mon Sep 17 00:00:00 2001
> From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> Date: Thu, 19 Sep 2013 17:23:17 +0900
> Subject: [PATCH] seq_file: Introduce seq_setwidth() and seq_pad()
>
> There are several users who want to know bytes written by seq_*() for alignment
> purpose. Currently they are using %n format for knowing it because seq_*()
> returns 0 on success.
>
> This patch introduces seq_setwidth() and seq_pad() for allowing them to align
> without using %n format.
>
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>

This really feels like a clean solution to me.

Acked-by: Kees Cook <keescook@chromium.org>

-Kees

> ---
>  fs/seq_file.c            |   15 +++++++++++++++
>  include/linux/seq_file.h |   15 +++++++++++++++
>  2 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/fs/seq_file.c b/fs/seq_file.c
> index 3135c25..40e471e 100644
> --- a/fs/seq_file.c
> +++ b/fs/seq_file.c
> @@ -764,6 +764,21 @@ int seq_write(struct seq_file *seq, const void *data, size_t len)
>  }
>  EXPORT_SYMBOL(seq_write);
>
> +/**
> + * seq_pad - write padding spaces to buffer
> + * @m: seq_file identifying the buffer to which data should be written
> + * @c: the byte to append after padding if non-zero
> + */
> +void seq_pad(struct seq_file *m, char c)
> +{
> +       int size = m->pad_until - m->count;
> +       if (size > 0)
> +               seq_printf(m, "%*s", size, "");
> +       if (c)
> +               seq_putc(m, c);
> +}
> +EXPORT_SYMBOL(seq_pad);
> +
>  struct list_head *seq_list_start(struct list_head *head, loff_t pos)
>  {
>         struct list_head *lh;
> diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
> index 4e32edc..52e0097 100644
> --- a/include/linux/seq_file.h
> +++ b/include/linux/seq_file.h
> @@ -20,6 +20,7 @@ struct seq_file {
>         size_t size;
>         size_t from;
>         size_t count;
> +       size_t pad_until;
>         loff_t index;
>         loff_t read_pos;
>         u64 version;
> @@ -79,6 +80,20 @@ static inline void seq_commit(struct seq_file *m, int num)
>         }
>  }
>
> +/**
> + * seq_setwidth - set padding width
> + * @m: the seq_file handle
> + * @size: the max number of bytes to pad.
> + *
> + * Call seq_setwidth() for setting max width, then call seq_printf() etc. and
> + * finally call seq_pad() to pad the remaining bytes.
> + */
> +static inline void seq_setwidth(struct seq_file *m, size_t size)
> +{
> +       m->pad_until = m->count + size;
> +}
> +void seq_pad(struct seq_file *m, char c);
> +
>  char *mangle_path(char *s, const char *p, const char *esc);
>  int seq_open(struct file *, const struct seq_operations *);
>  ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
> --
> 1.7.1



-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-19 14:28               ` Kees Cook
@ 2013-09-20  4:09                 ` Tetsuo Handa
  2013-09-20  4:23                   ` Joe Perches
                                     ` (2 more replies)
  0 siblings, 3 replies; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-20  4:09 UTC (permalink / raw)
  To: jslaby, viro, xemul, remi.denis-courmont
  Cc: keescook, linux-kernel, netdev, linux-sctp, linux, akpm,
	dan.carpenter, geert, JBeulich, joe, kosaki.motohiro

Hello.

We are discussing about removal of %n support from vsnprintf() at
https://lkml.org/lkml/2013/9/16/52 , and you are using %n in seq_printf().

I posted https://lkml.org/lkml/diff/2013/9/19/53/1 which introduces
seq_setwidth() / seq_pad() which can avoid use of %n in seq_printf().
Assuming that this patch is merged, would you confirm that I didn't break
your code with below patch?

Regards.
----------------------------------------
>From f8b60ebe3971901b93dedb8eee0f85b60d0fdc5f Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Date: Fri, 20 Sep 2013 12:01:07 +0900
Subject: [PATCH] Remove "%n" usage from seq_file users.

All seq_printf() users are using "%n" for calculating padding size, convert
them to use seq_setwidth() / seq_pad() pair.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 fs/proc/consoles.c   |   10 ++++------
 fs/proc/nommu.c      |   12 +++++-------
 fs/proc/task_mmu.c   |   20 ++++++--------------
 fs/proc/task_nommu.c |   19 ++++++-------------
 net/ipv4/fib_trie.c  |   13 +++++++------
 net/ipv4/ping.c      |   15 +++++++--------
 net/ipv4/tcp_ipv4.c  |   33 +++++++++++++++------------------
 net/ipv4/udp.c       |   15 +++++++--------
 net/phonet/socket.c  |   24 +++++++++++-------------
 net/sctp/objcnt.c    |    9 +++++----
 10 files changed, 73 insertions(+), 97 deletions(-)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index b701eaa..51942d5 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -29,7 +29,6 @@ static int show_console_dev(struct seq_file *m, void *v)
 	char flags[ARRAY_SIZE(con_flags) + 1];
 	struct console *con = v;
 	unsigned int a;
-	int len;
 	dev_t dev = 0;
 
 	if (con->device) {
@@ -47,11 +46,10 @@ static int show_console_dev(struct seq_file *m, void *v)
 			con_flags[a].name : ' ';
 	flags[a] = 0;
 
-	seq_printf(m, "%s%d%n", con->name, con->index, &len);
-	len = 21 - len;
-	if (len < 1)
-		len = 1;
-	seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
+	seq_setwidth(m, 21 - 1);
+	seq_printf(m, "%s%d", con->name, con->index);
+	seq_pad(m, ' ');
+	seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
 			con->write ? 'W' : '-', con->unblank ? 'U' : '-',
 			flags);
 	if (dev)
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index ccfd99b..5f9bc8a 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -39,7 +39,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 	unsigned long ino = 0;
 	struct file *file;
 	dev_t dev = 0;
-	int flags, len;
+	int flags;
 
 	flags = region->vm_flags;
 	file = region->vm_file;
@@ -50,8 +50,9 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 		ino = inode->i_ino;
 	}
 
+	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
 	seq_printf(m,
-		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 		   region->vm_start,
 		   region->vm_end,
 		   flags & VM_READ ? 'r' : '-',
@@ -59,13 +60,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 		   flags & VM_EXEC ? 'x' : '-',
 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
 		   ((loff_t)region->vm_pgoff) << PAGE_SHIFT,
-		   MAJOR(dev), MINOR(dev), ino, &len);
+		   MAJOR(dev), MINOR(dev), ino);
 
 	if (file) {
-		len = 25 + sizeof(void *) * 6 - len;
-		if (len < 1)
-			len = 1;
-		seq_printf(m, "%*c", len, ' ');
+		seq_pad(m, ' ');
 		seq_path(m, &file->f_path, "");
 	}
 
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7366e9d..cc24165 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -83,14 +83,6 @@ unsigned long task_statm(struct mm_struct *mm,
 	return mm->total_vm;
 }
 
-static void pad_len_spaces(struct seq_file *m, int len)
-{
-	len = 25 + sizeof(void*) * 6 - len;
-	if (len < 1)
-		len = 1;
-	seq_printf(m, "%*c", len, ' ');
-}
-
 #ifdef CONFIG_NUMA
 /*
  * These functions are for numa_maps but called in generic **maps seq_file
@@ -268,7 +260,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 	unsigned long long pgoff = 0;
 	unsigned long start, end;
 	dev_t dev = 0;
-	int len;
 	const char *name = NULL;
 
 	if (file) {
@@ -286,7 +277,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 	if (stack_guard_page_end(vma, end))
 		end -= PAGE_SIZE;
 
-	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
+	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 			start,
 			end,
 			flags & VM_READ ? 'r' : '-',
@@ -294,14 +286,14 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 			flags & VM_EXEC ? 'x' : '-',
 			flags & VM_MAYSHARE ? 's' : 'p',
 			pgoff,
-			MAJOR(dev), MINOR(dev), ino, &len);
+			MAJOR(dev), MINOR(dev), ino);
 
 	/*
 	 * Print the dentry name for named mappings, and a
 	 * special [heap] marker for the heap:
 	 */
 	if (file) {
-		pad_len_spaces(m, len);
+		seq_pad(m, ' ');
 		seq_path(m, &file->f_path, "\n");
 		goto done;
 	}
@@ -333,7 +325,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 				name = "[stack]";
 			} else {
 				/* Thread stack in /proc/PID/maps */
-				pad_len_spaces(m, len);
+				seq_pad(m, ' ');
 				seq_printf(m, "[stack:%d]", tid);
 			}
 		}
@@ -341,7 +333,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 
 done:
 	if (name) {
-		pad_len_spaces(m, len);
+		seq_pad(m, ' ');
 		seq_puts(m, name);
 	}
 	seq_putc(m, '\n');
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 56123a6..678455d 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -123,14 +123,6 @@ unsigned long task_statm(struct mm_struct *mm,
 	return size;
 }
 
-static void pad_len_spaces(struct seq_file *m, int len)
-{
-	len = 25 + sizeof(void*) * 6 - len;
-	if (len < 1)
-		len = 1;
-	seq_printf(m, "%*c", len, ' ');
-}
-
 /*
  * display a single VMA to a sequenced file
  */
@@ -142,7 +134,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 	unsigned long ino = 0;
 	struct file *file;
 	dev_t dev = 0;
-	int flags, len;
+	int flags;
 	unsigned long long pgoff = 0;
 
 	flags = vma->vm_flags;
@@ -155,8 +147,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 		pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
 	}
 
+	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
 	seq_printf(m,
-		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 		   vma->vm_start,
 		   vma->vm_end,
 		   flags & VM_READ ? 'r' : '-',
@@ -164,16 +157,16 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 		   flags & VM_EXEC ? 'x' : '-',
 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
 		   pgoff,
-		   MAJOR(dev), MINOR(dev), ino, &len);
+		   MAJOR(dev), MINOR(dev), ino);
 
 	if (file) {
-		pad_len_spaces(m, len);
+		seq_pad(m, ' ');
 		seq_path(m, &file->f_path, "");
 	} else if (mm) {
 		pid_t tid = vm_is_stack(priv->task, vma, is_pid);
 
 		if (tid != 0) {
-			pad_len_spaces(m, len);
+			seq_pad(m, ' ');
 			/*
 			 * Thread stack in /proc/PID/task/TID/maps or
 			 * the main process stack.
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 3df6d3e..b1af50e 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2530,16 +2530,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 		list_for_each_entry_rcu(fa, &li->falh, fa_list) {
 			const struct fib_info *fi = fa->fa_info;
 			unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
-			int len;
 
 			if (fa->fa_type == RTN_BROADCAST
 			    || fa->fa_type == RTN_MULTICAST)
 				continue;
 
+			seq_setwidth(seq, 127);
+
 			if (fi)
 				seq_printf(seq,
 					 "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
-					 "%d\t%08X\t%d\t%u\t%u%n",
+					 "%d\t%08X\t%d\t%u\t%u",
 					 fi->fib_dev ? fi->fib_dev->name : "*",
 					 prefix,
 					 fi->fib_nh->nh_gw, flags, 0, 0,
@@ -2548,15 +2549,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 					 (fi->fib_advmss ?
 					  fi->fib_advmss + 40 : 0),
 					 fi->fib_window,
-					 fi->fib_rtt >> 3, &len);
+					 fi->fib_rtt >> 3);
 			else
 				seq_printf(seq,
 					 "*\t%08X\t%08X\t%04X\t%d\t%u\t"
-					 "%d\t%08X\t%d\t%u\t%u%n",
+					 "%d\t%08X\t%d\t%u\t%u",
 					 prefix, 0, flags, 0, 0, 0,
-					 mask, 0, 0, 0, &len);
+					 mask, 0, 0, 0);
 
-			seq_printf(seq, "%*s\n", 127 - len, "");
+			seq_pad(seq, '\n');
 		}
 	}
 
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index d7d9882..94cc685 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -1073,7 +1073,7 @@ void ping_seq_stop(struct seq_file *seq, void *v)
 EXPORT_SYMBOL_GPL(ping_seq_stop);
 
 static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
-		int bucket, int *len)
+		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->inet_daddr;
@@ -1082,7 +1082,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
 	__u16 srcp = ntohs(inet->inet_sport);
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
@@ -1090,23 +1090,22 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
 		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
 		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
-		atomic_read(&sp->sk_drops), len);
+		atomic_read(&sp->sk_drops));
 }
 
 static int ping_v4_seq_show(struct seq_file *seq, void *v)
 {
+	seq_setwidth(seq, 127);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%-127s\n",
-			   "  sl  local_address rem_address   st tx_queue "
+		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode ref pointer drops");
 	else {
 		struct ping_iter_state *state = seq->private;
-		int len;
 
-		ping_v4_format_sock(v, seq, state->bucket, &len);
-		seq_printf(seq, "%*s\n", 127 - len, "");
+		ping_v4_format_sock(v, seq, state->bucket);
 	}
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b14266b..2948b76 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2598,13 +2598,13 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 EXPORT_SYMBOL(tcp_proc_unregister);
 
 static void get_openreq4(const struct sock *sk, const struct request_sock *req,
-			 struct seq_file *f, int i, kuid_t uid, int *len)
+			 struct seq_file *f, int i, kuid_t uid)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	long delta = req->expires - jiffies;
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK",
 		i,
 		ireq->loc_addr,
 		ntohs(inet_sk(sk)->inet_sport),
@@ -2619,11 +2619,10 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
 		0,  /* non standard timer */
 		0, /* open_requests have no inode */
 		atomic_read(&sk->sk_refcnt),
-		req,
-		len);
+		req);
 }
 
-static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
+static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
 {
 	int timer_active;
 	unsigned long timer_expires;
@@ -2662,7 +2661,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d%n",
+			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
 		i, src, srcp, dest, destp, sk->sk_state,
 		tp->write_seq - tp->snd_una,
 		rx_queue,
@@ -2679,12 +2678,11 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		tp->snd_cwnd,
 		sk->sk_state == TCP_LISTEN ?
 		    (fastopenq ? fastopenq->max_qlen : 0) :
-		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh),
-		len);
+		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));
 }
 
 static void get_timewait4_sock(const struct inet_timewait_sock *tw,
-			       struct seq_file *f, int i, int *len)
+			       struct seq_file *f, int i)
 {
 	__be32 dest, src;
 	__u16 destp, srcp;
@@ -2696,10 +2694,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 	srcp  = ntohs(tw->tw_sport);
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
 		i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
 		3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
-		atomic_read(&tw->tw_refcnt), tw, len);
+		atomic_read(&tw->tw_refcnt), tw);
 }
 
 #define TMPSZ 150
@@ -2707,11 +2705,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 static int tcp4_seq_show(struct seq_file *seq, void *v)
 {
 	struct tcp_iter_state *st;
-	int len;
 
+	seq_setwidth(seq, TMPSZ - 1);
 	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq, "%-*s\n", TMPSZ - 1,
-			   "  sl  local_address rem_address   st tx_queue "
+		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode");
 		goto out;
@@ -2721,17 +2718,17 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
 	switch (st->state) {
 	case TCP_SEQ_STATE_LISTENING:
 	case TCP_SEQ_STATE_ESTABLISHED:
-		get_tcp4_sock(v, seq, st->num, &len);
+		get_tcp4_sock(v, seq, st->num);
 		break;
 	case TCP_SEQ_STATE_OPENREQ:
-		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
+		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid);
 		break;
 	case TCP_SEQ_STATE_TIME_WAIT:
-		get_timewait4_sock(v, seq, st->num, &len);
+		get_timewait4_sock(v, seq, st->num);
 		break;
 	}
-	seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
 out:
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 74d2c95..31c132c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2150,7 +2150,7 @@ EXPORT_SYMBOL(udp_proc_unregister);
 
 /* ------------------------------------------------------------------------ */
 static void udp4_format_sock(struct sock *sp, struct seq_file *f,
-		int bucket, int *len)
+		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->inet_daddr;
@@ -2159,7 +2159,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 	__u16 srcp	  = ntohs(inet->inet_sport);
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
@@ -2167,23 +2167,22 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
 		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
-		atomic_read(&sp->sk_drops), len);
+		atomic_read(&sp->sk_drops));
 }
 
 int udp4_seq_show(struct seq_file *seq, void *v)
 {
+	seq_setwidth(seq, 127);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%-127s\n",
-			   "  sl  local_address rem_address   st tx_queue "
+		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode ref pointer drops");
 	else {
 		struct udp_iter_state *state = seq->private;
-		int len;
 
-		udp4_format_sock(v, seq, state->bucket, &len);
-		seq_printf(seq, "%*s\n", 127 - len, "");
+		udp4_format_sock(v, seq, state->bucket);
 	}
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 77e38f7..008214a 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -595,26 +595,25 @@ static void pn_sock_seq_stop(struct seq_file *seq, void *v)
 
 static int pn_sock_seq_show(struct seq_file *seq, void *v)
 {
-	int len;
-
+	seq_setwidth(seq, 127);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
-			"  uid inode ref pointer drops", &len);
+		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
+			"  uid inode ref pointer drops");
 	else {
 		struct sock *sk = v;
 		struct pn_sock *pn = pn_sk(sk);
 
 		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
-			"%d %pK %d%n",
+			"%d %pK %d",
 			sk->sk_protocol, pn->sobject, pn->dobject,
 			pn->resource, sk->sk_state,
 			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
 			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 			sock_i_ino(sk),
 			atomic_read(&sk->sk_refcnt), sk,
-			atomic_read(&sk->sk_drops), &len);
+			atomic_read(&sk->sk_drops));
 	}
-	seq_printf(seq, "%*s\n", 127 - len, "");
+	seq_pad(seq, '\n');
 	return 0;
 }
 
@@ -785,20 +784,19 @@ static void pn_res_seq_stop(struct seq_file *seq, void *v)
 
 static int pn_res_seq_show(struct seq_file *seq, void *v)
 {
-	int len;
-
+	seq_setwidth(seq, 63);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%s%n", "rs   uid inode", &len);
+		seq_puts(seq, "rs   uid inode");
 	else {
 		struct sock **psk = v;
 		struct sock *sk = *psk;
 
-		seq_printf(seq, "%02X %5u %lu%n",
+		seq_printf(seq, "%02X %5u %lu",
 			   (int) (psk - pnres.sk),
 			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
-			   sock_i_ino(sk), &len);
+			   sock_i_ino(sk));
 	}
-	seq_printf(seq, "%*s\n", 63 - len, "");
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index 5ea573b..647396b 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -79,12 +79,13 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
  */
 static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
 {
-	int i, len;
+	int i;
 
 	i = (int)*(loff_t *)v;
-	seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
-				atomic_read(sctp_dbg_objcnt[i].counter), &len);
-	seq_printf(seq, "%*s\n", 127 - len, "");
+	seq_setwidth(seq, 127);
+	seq_printf(seq, "%s: %d", sctp_dbg_objcnt[i].label,
+				atomic_read(sctp_dbg_objcnt[i].counter));
+	seq_pad(seq, '\n');
 	return 0;
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20  4:09                 ` Tetsuo Handa
@ 2013-09-20  4:23                   ` Joe Perches
  2013-09-20  4:53                     ` Kees Cook
  2013-09-20  8:08                   ` Jiri Slaby
  2013-09-23 21:24                   ` Kees Cook
  2 siblings, 1 reply; 46+ messages in thread
From: Joe Perches @ 2013-09-20  4:23 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: jslaby, viro, xemul, remi.denis-courmont, keescook, linux-kernel,
	netdev, linux-sctp, linux, akpm, dan.carpenter, geert, JBeulich,
	kosaki.motohiro

On Fri, 2013-09-20 at 13:09 +0900, Tetsuo Handa wrote:
> Hello.

Tetsuo-san:

> We are discussing about removal of %n support from vsnprintf() at
> https://lkml.org/lkml/2013/9/16/52 , and you are using %n in seq_printf().

Well, I'm not using (mere alcohol isn't using, right?)
but I still have the same question for Al.

Are there any races here?

> I posted https://lkml.org/lkml/diff/2013/9/19/53/1 which introduces
> seq_setwidth() / seq_pad() which can avoid use of %n in seq_printf().

I still think adding last_len, last_rtn
is sensible.



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20  4:23                   ` Joe Perches
@ 2013-09-20  4:53                     ` Kees Cook
  0 siblings, 0 replies; 46+ messages in thread
From: Kees Cook @ 2013-09-20  4:53 UTC (permalink / raw)
  To: Joe Perches
  Cc: Tetsuo Handa, Jiri Slaby, Al Viro, Pavel Emelyanov,
	remi.denis-courmont, LKML, netdev, linux-sctp, George Spelvin,
	Andrew Morton, Dan Carpenter, Geert Uytterhoeven, Jan Beulich,
	Motohiro KOSAKI

On Thu, Sep 19, 2013 at 9:23 PM, Joe Perches <joe@perches.com> wrote:
> On Fri, 2013-09-20 at 13:09 +0900, Tetsuo Handa wrote:
>> Hello.
>
> Tetsuo-san:
>
>> We are discussing about removal of %n support from vsnprintf() at
>> https://lkml.org/lkml/2013/9/16/52 , and you are using %n in seq_printf().
>
> Well, I'm not using (mere alcohol isn't using, right?)
> but I still have the same question for Al.
>
> Are there any races here?

All the call sites I examined were linear. FWIW, I didn't see any races.

-Kees

>
>> I posted https://lkml.org/lkml/diff/2013/9/19/53/1 which introduces
>> seq_setwidth() / seq_pad() which can avoid use of %n in seq_printf().
>
> I still think adding last_len, last_rtn
> is sensible.
>
>



-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20  4:09                 ` Tetsuo Handa
  2013-09-20  4:23                   ` Joe Perches
@ 2013-09-20  8:08                   ` Jiri Slaby
  2013-09-20 19:24                     ` Kees Cook
  2013-09-23 21:24                   ` Kees Cook
  2 siblings, 1 reply; 46+ messages in thread
From: Jiri Slaby @ 2013-09-20  8:08 UTC (permalink / raw)
  To: Tetsuo Handa, viro, xemul, remi.denis-courmont
  Cc: keescook, linux-kernel, netdev, linux-sctp, linux, akpm,
	dan.carpenter, geert, JBeulich, joe, kosaki.motohiro

On 09/20/2013 06:09 AM, Tetsuo Handa wrote:
> --- a/fs/proc/consoles.c
> +++ b/fs/proc/consoles.c
...
> @@ -47,11 +46,10 @@ static int show_console_dev(struct seq_file *m, void *v)
>  			con_flags[a].name : ' ';
>  	flags[a] = 0;
>  
> -	seq_printf(m, "%s%d%n", con->name, con->index, &len);
> -	len = 21 - len;
> -	if (len < 1)
> -		len = 1;
> -	seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
> +	seq_setwidth(m, 21 - 1);
> +	seq_printf(m, "%s%d", con->name, con->index);
> +	seq_pad(m, ' ');
> +	seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
>  			con->write ? 'W' : '-', con->unblank ? 'U' : '-',
>  			flags);

Hello, do you really need seq_setwidth? It makes it really ugly...

Or do we need that all? Couldn't we simply have seq_printf_padded? Or
maybe some % modifier in seq_printf to pad the string?

> --- a/net/ipv4/fib_trie.c
> +++ b/net/ipv4/fib_trie.c
...
> @@ -2548,15 +2549,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
>  					 (fi->fib_advmss ?
>  					  fi->fib_advmss + 40 : 0),
>  					 fi->fib_window,
> -					 fi->fib_rtt >> 3, &len);
> +					 fi->fib_rtt >> 3);
>  			else
>  				seq_printf(seq,
>  					 "*\t%08X\t%08X\t%04X\t%d\t%u\t"
> -					 "%d\t%08X\t%d\t%u\t%u%n",
> +					 "%d\t%08X\t%d\t%u\t%u",
>  					 prefix, 0, flags, 0, 0, 0,
> -					 mask, 0, 0, 0, &len);
> +					 mask, 0, 0, 0);
>  
> -			seq_printf(seq, "%*s\n", 127 - len, "");
> +			seq_pad(seq, '\n');

Hmm, seq_pad is unintuitive. I would say it pads the string by '\n'. Of
course it does not, but...

thanks,
-- 
js
suse labs

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20  8:08                   ` Jiri Slaby
@ 2013-09-20 19:24                     ` Kees Cook
  2013-09-20 19:33                       ` Joe Perches
  2013-09-21  0:28                       ` Tetsuo Handa
  0 siblings, 2 replies; 46+ messages in thread
From: Kees Cook @ 2013-09-20 19:24 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Tetsuo Handa, Al Viro, Pavel Emelyanov, Rémi Denis-Courmont,
	LKML, netdev, linux-sctp, George Spelvin, Andrew Morton,
	Dan Carpenter, Geert Uytterhoeven, Jan Beulich, Joe Perches,
	Motohiro KOSAKI

On Fri, Sep 20, 2013 at 1:08 AM, Jiri Slaby <jslaby@suse.cz> wrote:
> On 09/20/2013 06:09 AM, Tetsuo Handa wrote:
>> --- a/fs/proc/consoles.c
>> +++ b/fs/proc/consoles.c
> ...
>> @@ -47,11 +46,10 @@ static int show_console_dev(struct seq_file *m, void *v)
>>                       con_flags[a].name : ' ';
>>       flags[a] = 0;
>>
>> -     seq_printf(m, "%s%d%n", con->name, con->index, &len);
>> -     len = 21 - len;
>> -     if (len < 1)
>> -             len = 1;
>> -     seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
>> +     seq_setwidth(m, 21 - 1);
>> +     seq_printf(m, "%s%d", con->name, con->index);
>> +     seq_pad(m, ' ');
>> +     seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
>>                       con->write ? 'W' : '-', con->unblank ? 'U' : '-',
>>                       flags);
>
> Hello, do you really need seq_setwidth? It makes it really ugly...

There are a few problems that have been discussed on the various
threads. Namely, we want to minimize the changes to the seq_file
structure and to not add additional work to all the seq_file users
that don't care about padding. If the seq_file calls always track how
far they're written across each call, we add unneeded work to all the
users. To avoid this, we must identify to the seq_file subsystem where
we want to start tracking the length written. To allow this to be
spread across multiple calls (something the %n can't do), we must
record seq->count at some point, and then compare against it at the
point where we want to perform padding.

> Or do we need that all? Couldn't we simply have seq_printf_padded? Or
> maybe some % modifier in seq_printf to pad the string?

Adding a _padding version of things means we'd have to add it to all
seq_* function that print things (like printing paths, etc). Using
this method, the output doesn't matter. We declare the starting point,
output whatever we need, then perform padding, and continue writing.

I think the declaration/output/pad method seems the least invasive to
existing users of padding, and the highest level of flexibility going
forward for future users.

>> --- a/net/ipv4/fib_trie.c
>> +++ b/net/ipv4/fib_trie.c
> ...
>> @@ -2548,15 +2549,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
>>                                        (fi->fib_advmss ?
>>                                         fi->fib_advmss + 40 : 0),
>>                                        fi->fib_window,
>> -                                      fi->fib_rtt >> 3, &len);
>> +                                      fi->fib_rtt >> 3);
>>                       else
>>                               seq_printf(seq,
>>                                        "*\t%08X\t%08X\t%04X\t%d\t%u\t"
>> -                                      "%d\t%08X\t%d\t%u\t%u%n",
>> +                                      "%d\t%08X\t%d\t%u\t%u",
>>                                        prefix, 0, flags, 0, 0, 0,
>> -                                      mask, 0, 0, 0, &len);
>> +                                      mask, 0, 0, 0);
>>
>> -                     seq_printf(seq, "%*s\n", 127 - len, "");
>> +                     seq_pad(seq, '\n');
>
> Hmm, seq_pad is unintuitive. I would say it pads the string by '\n'. Of
> course it does not, but...

I don't think this is a very serious problem. Currently, the padding
character is always ' ' for all existing callers, so it only makes
sense to make the trailing character an argument.

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20 19:24                     ` Kees Cook
@ 2013-09-20 19:33                       ` Joe Perches
  2013-09-21  0:28                       ` Tetsuo Handa
  1 sibling, 0 replies; 46+ messages in thread
From: Joe Perches @ 2013-09-20 19:33 UTC (permalink / raw)
  To: Kees Cook
  Cc: Jiri Slaby, Tetsuo Handa, Al Viro, Pavel Emelyanov,
	Rémi Denis-Courmont, LKML, netdev, linux-sctp,
	George Spelvin, Andrew Morton, Dan Carpenter, Geert Uytterhoeven,
	Jan Beulich, Motohiro KOSAKI

On Fri, 2013-09-20 at 12:24 -0700, Kees Cook wrote:
> There are a few problems that have been discussed on the various
> threads. Namely, we want to minimize the changes to the seq_file
> structure and to not add additional work to all the seq_file users
> that don't care about padding.

I don't think saving a couple more values to a struct
is that big a deal.



^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20 19:24                     ` Kees Cook
  2013-09-20 19:33                       ` Joe Perches
@ 2013-09-21  0:28                       ` Tetsuo Handa
  2013-09-22  8:09                         ` George Spelvin
  2013-09-22  8:16                         ` Geert Uytterhoeven
  1 sibling, 2 replies; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-21  0:28 UTC (permalink / raw)
  To: keescook, jslaby
  Cc: viro, xemul, remi.denis-courmont, linux-kernel, netdev,
	linux-sctp, linux, akpm, dan.carpenter, geert, JBeulich, joe,
	kosaki.motohiro

Kees Cook wrote:
> >> -                     seq_printf(seq, "%*s\n", 127 - len, "");
> >> +                     seq_pad(seq, '\n');
> >
> > Hmm, seq_pad is unintuitive. I would say it pads the string by '\n'. Of
> > course it does not, but...
> 
> I don't think this is a very serious problem. Currently, the padding
> character is always ' ' for all existing callers, so it only makes
> sense to make the trailing character an argument.

If you want, we can rename seq_pad() to seq_pad_and_putc(). Also we can pass
both the padding character (e.g. ' ') and the trailing character (e.g. '\n')
like seq_pad_and_putc((' ' << 8) | '\n'), though I wonder someone wants to
use '\0', '\t', '\n' etc. as the padding character...

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-21  0:28                       ` Tetsuo Handa
@ 2013-09-22  8:09                         ` George Spelvin
  2013-09-22  8:16                         ` Geert Uytterhoeven
  1 sibling, 0 replies; 46+ messages in thread
From: George Spelvin @ 2013-09-22  8:09 UTC (permalink / raw)
  To: jslaby, keescook, penguin-kernel
  Cc: akpm, dan.carpenter, geert, JBeulich, joe, kosaki.motohiro,
	linux-kernel, linux-sctp, linux, netdev, remi.denis-courmont,
	viro, xemul

> If you want, we can rename seq_pad() to seq_pad_and_putc(). Also we can pass
> both the padding character (e.g. ' ') and the trailing character (e.g. '\n')
> like seq_pad_and_putc((' ' << 8) | '\n'), though I wonder someone wants to
> use '\0', '\t', '\n' etc. as the padding character...

How about let that complexity wait until it's needed?  It's not like
it's that big a PITA of a patch to write, and there's a significant
chance it will *never* be needed.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-21  0:28                       ` Tetsuo Handa
  2013-09-22  8:09                         ` George Spelvin
@ 2013-09-22  8:16                         ` Geert Uytterhoeven
  1 sibling, 0 replies; 46+ messages in thread
From: Geert Uytterhoeven @ 2013-09-22  8:16 UTC (permalink / raw)
  To: Tetsuo Handa
  Cc: Kees Cook, Jiri Slaby, Al Viro, xemul, remi.denis-courmont,
	linux-kernel, netdev, linux-sctp, George Spelvin, Andrew Morton,
	Dan Carpenter, Jan Beulich, Joe Perches, Motohiro KOSAKI

On Sat, Sep 21, 2013 at 2:28 AM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> Kees Cook wrote:
>> >> -                     seq_printf(seq, "%*s\n", 127 - len, "");
>> >> +                     seq_pad(seq, '\n');
>> >
>> > Hmm, seq_pad is unintuitive. I would say it pads the string by '\n'. Of
>> > course it does not, but...
>>
>> I don't think this is a very serious problem. Currently, the padding
>> character is always ' ' for all existing callers, so it only makes
>> sense to make the trailing character an argument.
>
> If you want, we can rename seq_pad() to seq_pad_and_putc(). Also we can pass
> both the padding character (e.g. ' ') and the trailing character (e.g. '\n')
> like seq_pad_and_putc((' ' << 8) | '\n'), though I wonder someone wants to
> use '\0', '\t', '\n' etc. as the padding character...

Not those special characters. '-' could be useful for tables (doh,
text-mode graphics
log output).

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-20  4:09                 ` Tetsuo Handa
  2013-09-20  4:23                   ` Joe Perches
  2013-09-20  8:08                   ` Jiri Slaby
@ 2013-09-23 21:24                   ` Kees Cook
  2013-09-30  8:16                     ` Tetsuo Handa
  2 siblings, 1 reply; 46+ messages in thread
From: Kees Cook @ 2013-09-23 21:24 UTC (permalink / raw)
  To: Tetsuo Handa, Andrew Morton
  Cc: Jiri Slaby, Al Viro, Pavel Emelyanov, LKML, netdev, linux-sctp,
	George Spelvin, Dan Carpenter, Geert Uytterhoeven, Jan Beulich,
	Joe Perches, Motohiro KOSAKI

[-remi (bouncing), +akpm]

On Thu, Sep 19, 2013 at 9:09 PM, Tetsuo Handa
<penguin-kernel@i-love.sakura.ne.jp> wrote:
> Hello.
>
> We are discussing about removal of %n support from vsnprintf() at
> https://lkml.org/lkml/2013/9/16/52 , and you are using %n in seq_printf().
>
> I posted https://lkml.org/lkml/diff/2013/9/19/53/1 which introduces
> seq_setwidth() / seq_pad() which can avoid use of %n in seq_printf().
> Assuming that this patch is merged, would you confirm that I didn't break
> your code with below patch?

As mentioned in the thread, I think we should carry this with the
patch that adds seq_pad and drops %n. It's the cleanest of the
solutions, adds no CPU overhead to other seq_file users, addresses the
basic need (seq_printf padding) while providing expanded functionality
(tracking padding for any seq_file writes, not just seq_printf).

Acked-by: Kees Cook <keescook@chromium.org>

-Kees

>
> Regards.
> ----------------------------------------
> >From f8b60ebe3971901b93dedb8eee0f85b60d0fdc5f Mon Sep 17 00:00:00 2001
> From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> Date: Fri, 20 Sep 2013 12:01:07 +0900
> Subject: [PATCH] Remove "%n" usage from seq_file users.
>
> All seq_printf() users are using "%n" for calculating padding size, convert
> them to use seq_setwidth() / seq_pad() pair.
>
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
>  fs/proc/consoles.c   |   10 ++++------
>  fs/proc/nommu.c      |   12 +++++-------
>  fs/proc/task_mmu.c   |   20 ++++++--------------
>  fs/proc/task_nommu.c |   19 ++++++-------------
>  net/ipv4/fib_trie.c  |   13 +++++++------
>  net/ipv4/ping.c      |   15 +++++++--------
>  net/ipv4/tcp_ipv4.c  |   33 +++++++++++++++------------------
>  net/ipv4/udp.c       |   15 +++++++--------
>  net/phonet/socket.c  |   24 +++++++++++-------------
>  net/sctp/objcnt.c    |    9 +++++----
>  10 files changed, 73 insertions(+), 97 deletions(-)
>
> diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
> index b701eaa..51942d5 100644
> --- a/fs/proc/consoles.c
> +++ b/fs/proc/consoles.c
> @@ -29,7 +29,6 @@ static int show_console_dev(struct seq_file *m, void *v)
>         char flags[ARRAY_SIZE(con_flags) + 1];
>         struct console *con = v;
>         unsigned int a;
> -       int len;
>         dev_t dev = 0;
>
>         if (con->device) {
> @@ -47,11 +46,10 @@ static int show_console_dev(struct seq_file *m, void *v)
>                         con_flags[a].name : ' ';
>         flags[a] = 0;
>
> -       seq_printf(m, "%s%d%n", con->name, con->index, &len);
> -       len = 21 - len;
> -       if (len < 1)
> -               len = 1;
> -       seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
> +       seq_setwidth(m, 21 - 1);
> +       seq_printf(m, "%s%d", con->name, con->index);
> +       seq_pad(m, ' ');
> +       seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
>                         con->write ? 'W' : '-', con->unblank ? 'U' : '-',
>                         flags);
>         if (dev)
> diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
> index ccfd99b..5f9bc8a 100644
> --- a/fs/proc/nommu.c
> +++ b/fs/proc/nommu.c
> @@ -39,7 +39,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
>         unsigned long ino = 0;
>         struct file *file;
>         dev_t dev = 0;
> -       int flags, len;
> +       int flags;
>
>         flags = region->vm_flags;
>         file = region->vm_file;
> @@ -50,8 +50,9 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
>                 ino = inode->i_ino;
>         }
>
> +       seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
>         seq_printf(m,
> -                  "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
> +                  "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
>                    region->vm_start,
>                    region->vm_end,
>                    flags & VM_READ ? 'r' : '-',
> @@ -59,13 +60,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
>                    flags & VM_EXEC ? 'x' : '-',
>                    flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
>                    ((loff_t)region->vm_pgoff) << PAGE_SHIFT,
> -                  MAJOR(dev), MINOR(dev), ino, &len);
> +                  MAJOR(dev), MINOR(dev), ino);
>
>         if (file) {
> -               len = 25 + sizeof(void *) * 6 - len;
> -               if (len < 1)
> -                       len = 1;
> -               seq_printf(m, "%*c", len, ' ');
> +               seq_pad(m, ' ');
>                 seq_path(m, &file->f_path, "");
>         }
>
> diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
> index 7366e9d..cc24165 100644
> --- a/fs/proc/task_mmu.c
> +++ b/fs/proc/task_mmu.c
> @@ -83,14 +83,6 @@ unsigned long task_statm(struct mm_struct *mm,
>         return mm->total_vm;
>  }
>
> -static void pad_len_spaces(struct seq_file *m, int len)
> -{
> -       len = 25 + sizeof(void*) * 6 - len;
> -       if (len < 1)
> -               len = 1;
> -       seq_printf(m, "%*c", len, ' ');
> -}
> -
>  #ifdef CONFIG_NUMA
>  /*
>   * These functions are for numa_maps but called in generic **maps seq_file
> @@ -268,7 +260,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
>         unsigned long long pgoff = 0;
>         unsigned long start, end;
>         dev_t dev = 0;
> -       int len;
>         const char *name = NULL;
>
>         if (file) {
> @@ -286,7 +277,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
>         if (stack_guard_page_end(vma, end))
>                 end -= PAGE_SIZE;
>
> -       seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
> +       seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
> +       seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
>                         start,
>                         end,
>                         flags & VM_READ ? 'r' : '-',
> @@ -294,14 +286,14 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
>                         flags & VM_EXEC ? 'x' : '-',
>                         flags & VM_MAYSHARE ? 's' : 'p',
>                         pgoff,
> -                       MAJOR(dev), MINOR(dev), ino, &len);
> +                       MAJOR(dev), MINOR(dev), ino);
>
>         /*
>          * Print the dentry name for named mappings, and a
>          * special [heap] marker for the heap:
>          */
>         if (file) {
> -               pad_len_spaces(m, len);
> +               seq_pad(m, ' ');
>                 seq_path(m, &file->f_path, "\n");
>                 goto done;
>         }
> @@ -333,7 +325,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
>                                 name = "[stack]";
>                         } else {
>                                 /* Thread stack in /proc/PID/maps */
> -                               pad_len_spaces(m, len);
> +                               seq_pad(m, ' ');
>                                 seq_printf(m, "[stack:%d]", tid);
>                         }
>                 }
> @@ -341,7 +333,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
>
>  done:
>         if (name) {
> -               pad_len_spaces(m, len);
> +               seq_pad(m, ' ');
>                 seq_puts(m, name);
>         }
>         seq_putc(m, '\n');
> diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
> index 56123a6..678455d 100644
> --- a/fs/proc/task_nommu.c
> +++ b/fs/proc/task_nommu.c
> @@ -123,14 +123,6 @@ unsigned long task_statm(struct mm_struct *mm,
>         return size;
>  }
>
> -static void pad_len_spaces(struct seq_file *m, int len)
> -{
> -       len = 25 + sizeof(void*) * 6 - len;
> -       if (len < 1)
> -               len = 1;
> -       seq_printf(m, "%*c", len, ' ');
> -}
> -
>  /*
>   * display a single VMA to a sequenced file
>   */
> @@ -142,7 +134,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
>         unsigned long ino = 0;
>         struct file *file;
>         dev_t dev = 0;
> -       int flags, len;
> +       int flags;
>         unsigned long long pgoff = 0;
>
>         flags = vma->vm_flags;
> @@ -155,8 +147,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
>                 pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
>         }
>
> +       seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
>         seq_printf(m,
> -                  "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
> +                  "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
>                    vma->vm_start,
>                    vma->vm_end,
>                    flags & VM_READ ? 'r' : '-',
> @@ -164,16 +157,16 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
>                    flags & VM_EXEC ? 'x' : '-',
>                    flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
>                    pgoff,
> -                  MAJOR(dev), MINOR(dev), ino, &len);
> +                  MAJOR(dev), MINOR(dev), ino);
>
>         if (file) {
> -               pad_len_spaces(m, len);
> +               seq_pad(m, ' ');
>                 seq_path(m, &file->f_path, "");
>         } else if (mm) {
>                 pid_t tid = vm_is_stack(priv->task, vma, is_pid);
>
>                 if (tid != 0) {
> -                       pad_len_spaces(m, len);
> +                       seq_pad(m, ' ');
>                         /*
>                          * Thread stack in /proc/PID/task/TID/maps or
>                          * the main process stack.
> diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
> index 3df6d3e..b1af50e 100644
> --- a/net/ipv4/fib_trie.c
> +++ b/net/ipv4/fib_trie.c
> @@ -2530,16 +2530,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
>                 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
>                         const struct fib_info *fi = fa->fa_info;
>                         unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
> -                       int len;
>
>                         if (fa->fa_type == RTN_BROADCAST
>                             || fa->fa_type == RTN_MULTICAST)
>                                 continue;
>
> +                       seq_setwidth(seq, 127);
> +
>                         if (fi)
>                                 seq_printf(seq,
>                                          "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
> -                                        "%d\t%08X\t%d\t%u\t%u%n",
> +                                        "%d\t%08X\t%d\t%u\t%u",
>                                          fi->fib_dev ? fi->fib_dev->name : "*",
>                                          prefix,
>                                          fi->fib_nh->nh_gw, flags, 0, 0,
> @@ -2548,15 +2549,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
>                                          (fi->fib_advmss ?
>                                           fi->fib_advmss + 40 : 0),
>                                          fi->fib_window,
> -                                        fi->fib_rtt >> 3, &len);
> +                                        fi->fib_rtt >> 3);
>                         else
>                                 seq_printf(seq,
>                                          "*\t%08X\t%08X\t%04X\t%d\t%u\t"
> -                                        "%d\t%08X\t%d\t%u\t%u%n",
> +                                        "%d\t%08X\t%d\t%u\t%u",
>                                          prefix, 0, flags, 0, 0, 0,
> -                                        mask, 0, 0, 0, &len);
> +                                        mask, 0, 0, 0);
>
> -                       seq_printf(seq, "%*s\n", 127 - len, "");
> +                       seq_pad(seq, '\n');
>                 }
>         }
>
> diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
> index d7d9882..94cc685 100644
> --- a/net/ipv4/ping.c
> +++ b/net/ipv4/ping.c
> @@ -1073,7 +1073,7 @@ void ping_seq_stop(struct seq_file *seq, void *v)
>  EXPORT_SYMBOL_GPL(ping_seq_stop);
>
>  static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
> -               int bucket, int *len)
> +               int bucket)
>  {
>         struct inet_sock *inet = inet_sk(sp);
>         __be32 dest = inet->inet_daddr;
> @@ -1082,7 +1082,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
>         __u16 srcp = ntohs(inet->inet_sport);
>
>         seq_printf(f, "%5d: %08X:%04X %08X:%04X"
> -               " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
> +               " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
>                 bucket, src, srcp, dest, destp, sp->sk_state,
>                 sk_wmem_alloc_get(sp),
>                 sk_rmem_alloc_get(sp),
> @@ -1090,23 +1090,22 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
>                 from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
>                 0, sock_i_ino(sp),
>                 atomic_read(&sp->sk_refcnt), sp,
> -               atomic_read(&sp->sk_drops), len);
> +               atomic_read(&sp->sk_drops));
>  }
>
>  static int ping_v4_seq_show(struct seq_file *seq, void *v)
>  {
> +       seq_setwidth(seq, 127);
>         if (v == SEQ_START_TOKEN)
> -               seq_printf(seq, "%-127s\n",
> -                          "  sl  local_address rem_address   st tx_queue "
> +               seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
>                            "rx_queue tr tm->when retrnsmt   uid  timeout "
>                            "inode ref pointer drops");
>         else {
>                 struct ping_iter_state *state = seq->private;
> -               int len;
>
> -               ping_v4_format_sock(v, seq, state->bucket, &len);
> -               seq_printf(seq, "%*s\n", 127 - len, "");
> +               ping_v4_format_sock(v, seq, state->bucket);
>         }
> +       seq_pad(seq, '\n');
>         return 0;
>  }
>
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index b14266b..2948b76 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -2598,13 +2598,13 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
>  EXPORT_SYMBOL(tcp_proc_unregister);
>
>  static void get_openreq4(const struct sock *sk, const struct request_sock *req,
> -                        struct seq_file *f, int i, kuid_t uid, int *len)
> +                        struct seq_file *f, int i, kuid_t uid)
>  {
>         const struct inet_request_sock *ireq = inet_rsk(req);
>         long delta = req->expires - jiffies;
>
>         seq_printf(f, "%4d: %08X:%04X %08X:%04X"
> -               " %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK%n",
> +               " %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK",
>                 i,
>                 ireq->loc_addr,
>                 ntohs(inet_sk(sk)->inet_sport),
> @@ -2619,11 +2619,10 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
>                 0,  /* non standard timer */
>                 0, /* open_requests have no inode */
>                 atomic_read(&sk->sk_refcnt),
> -               req,
> -               len);
> +               req);
>  }
>
> -static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
> +static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
>  {
>         int timer_active;
>         unsigned long timer_expires;
> @@ -2662,7 +2661,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
>                 rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
>
>         seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
> -                       "%08X %5u %8d %lu %d %pK %lu %lu %u %u %d%n",
> +                       "%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
>                 i, src, srcp, dest, destp, sk->sk_state,
>                 tp->write_seq - tp->snd_una,
>                 rx_queue,
> @@ -2679,12 +2678,11 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
>                 tp->snd_cwnd,
>                 sk->sk_state == TCP_LISTEN ?
>                     (fastopenq ? fastopenq->max_qlen : 0) :
> -                   (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh),
> -               len);
> +                   (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));
>  }
>
>  static void get_timewait4_sock(const struct inet_timewait_sock *tw,
> -                              struct seq_file *f, int i, int *len)
> +                              struct seq_file *f, int i)
>  {
>         __be32 dest, src;
>         __u16 destp, srcp;
> @@ -2696,10 +2694,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
>         srcp  = ntohs(tw->tw_sport);
>
>         seq_printf(f, "%4d: %08X:%04X %08X:%04X"
> -               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
> +               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
>                 i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
>                 3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
> -               atomic_read(&tw->tw_refcnt), tw, len);
> +               atomic_read(&tw->tw_refcnt), tw);
>  }
>
>  #define TMPSZ 150
> @@ -2707,11 +2705,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
>  static int tcp4_seq_show(struct seq_file *seq, void *v)
>  {
>         struct tcp_iter_state *st;
> -       int len;
>
> +       seq_setwidth(seq, TMPSZ - 1);
>         if (v == SEQ_START_TOKEN) {
> -               seq_printf(seq, "%-*s\n", TMPSZ - 1,
> -                          "  sl  local_address rem_address   st tx_queue "
> +               seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
>                            "rx_queue tr tm->when retrnsmt   uid  timeout "
>                            "inode");
>                 goto out;
> @@ -2721,17 +2718,17 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
>         switch (st->state) {
>         case TCP_SEQ_STATE_LISTENING:
>         case TCP_SEQ_STATE_ESTABLISHED:
> -               get_tcp4_sock(v, seq, st->num, &len);
> +               get_tcp4_sock(v, seq, st->num);
>                 break;
>         case TCP_SEQ_STATE_OPENREQ:
> -               get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
> +               get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid);
>                 break;
>         case TCP_SEQ_STATE_TIME_WAIT:
> -               get_timewait4_sock(v, seq, st->num, &len);
> +               get_timewait4_sock(v, seq, st->num);
>                 break;
>         }
> -       seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
>  out:
> +       seq_pad(seq, '\n');
>         return 0;
>  }
>
> diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
> index 74d2c95..31c132c 100644
> --- a/net/ipv4/udp.c
> +++ b/net/ipv4/udp.c
> @@ -2150,7 +2150,7 @@ EXPORT_SYMBOL(udp_proc_unregister);
>
>  /* ------------------------------------------------------------------------ */
>  static void udp4_format_sock(struct sock *sp, struct seq_file *f,
> -               int bucket, int *len)
> +               int bucket)
>  {
>         struct inet_sock *inet = inet_sk(sp);
>         __be32 dest = inet->inet_daddr;
> @@ -2159,7 +2159,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
>         __u16 srcp        = ntohs(inet->inet_sport);
>
>         seq_printf(f, "%5d: %08X:%04X %08X:%04X"
> -               " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
> +               " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
>                 bucket, src, srcp, dest, destp, sp->sk_state,
>                 sk_wmem_alloc_get(sp),
>                 sk_rmem_alloc_get(sp),
> @@ -2167,23 +2167,22 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
>                 from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
>                 0, sock_i_ino(sp),
>                 atomic_read(&sp->sk_refcnt), sp,
> -               atomic_read(&sp->sk_drops), len);
> +               atomic_read(&sp->sk_drops));
>  }
>
>  int udp4_seq_show(struct seq_file *seq, void *v)
>  {
> +       seq_setwidth(seq, 127);
>         if (v == SEQ_START_TOKEN)
> -               seq_printf(seq, "%-127s\n",
> -                          "  sl  local_address rem_address   st tx_queue "
> +               seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
>                            "rx_queue tr tm->when retrnsmt   uid  timeout "
>                            "inode ref pointer drops");
>         else {
>                 struct udp_iter_state *state = seq->private;
> -               int len;
>
> -               udp4_format_sock(v, seq, state->bucket, &len);
> -               seq_printf(seq, "%*s\n", 127 - len, "");
> +               udp4_format_sock(v, seq, state->bucket);
>         }
> +       seq_pad(seq, '\n');
>         return 0;
>  }
>
> diff --git a/net/phonet/socket.c b/net/phonet/socket.c
> index 77e38f7..008214a 100644
> --- a/net/phonet/socket.c
> +++ b/net/phonet/socket.c
> @@ -595,26 +595,25 @@ static void pn_sock_seq_stop(struct seq_file *seq, void *v)
>
>  static int pn_sock_seq_show(struct seq_file *seq, void *v)
>  {
> -       int len;
> -
> +       seq_setwidth(seq, 127);
>         if (v == SEQ_START_TOKEN)
> -               seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
> -                       "  uid inode ref pointer drops", &len);
> +               seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
> +                       "  uid inode ref pointer drops");
>         else {
>                 struct sock *sk = v;
>                 struct pn_sock *pn = pn_sk(sk);
>
>                 seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
> -                       "%d %pK %d%n",
> +                       "%d %pK %d",
>                         sk->sk_protocol, pn->sobject, pn->dobject,
>                         pn->resource, sk->sk_state,
>                         sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
>                         from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
>                         sock_i_ino(sk),
>                         atomic_read(&sk->sk_refcnt), sk,
> -                       atomic_read(&sk->sk_drops), &len);
> +                       atomic_read(&sk->sk_drops));
>         }
> -       seq_printf(seq, "%*s\n", 127 - len, "");
> +       seq_pad(seq, '\n');
>         return 0;
>  }
>
> @@ -785,20 +784,19 @@ static void pn_res_seq_stop(struct seq_file *seq, void *v)
>
>  static int pn_res_seq_show(struct seq_file *seq, void *v)
>  {
> -       int len;
> -
> +       seq_setwidth(seq, 63);
>         if (v == SEQ_START_TOKEN)
> -               seq_printf(seq, "%s%n", "rs   uid inode", &len);
> +               seq_puts(seq, "rs   uid inode");
>         else {
>                 struct sock **psk = v;
>                 struct sock *sk = *psk;
>
> -               seq_printf(seq, "%02X %5u %lu%n",
> +               seq_printf(seq, "%02X %5u %lu",
>                            (int) (psk - pnres.sk),
>                            from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
> -                          sock_i_ino(sk), &len);
> +                          sock_i_ino(sk));
>         }
> -       seq_printf(seq, "%*s\n", 63 - len, "");
> +       seq_pad(seq, '\n');
>         return 0;
>  }
>
> diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
> index 5ea573b..647396b 100644
> --- a/net/sctp/objcnt.c
> +++ b/net/sctp/objcnt.c
> @@ -79,12 +79,13 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
>   */
>  static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
>  {
> -       int i, len;
> +       int i;
>
>         i = (int)*(loff_t *)v;
> -       seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
> -                               atomic_read(sctp_dbg_objcnt[i].counter), &len);
> -       seq_printf(seq, "%*s\n", 127 - len, "");
> +       seq_setwidth(seq, 127);
> +       seq_printf(seq, "%s: %d", sctp_dbg_objcnt[i].label,
> +                               atomic_read(sctp_dbg_objcnt[i].counter));
> +       seq_pad(seq, '\n');
>         return 0;
>  }
>
> --
> 1.7.1



-- 
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: [PATCH 1/2] remove all uses of printf's %n
  2013-09-23 21:24                   ` Kees Cook
@ 2013-09-30  8:16                     ` Tetsuo Handa
  0 siblings, 0 replies; 46+ messages in thread
From: Tetsuo Handa @ 2013-09-30  8:16 UTC (permalink / raw)
  To: akpm
  Cc: keescook, jslaby, viro, xemul, linux-kernel, netdev, linux-sctp,
	linux, dan.carpenter, geert, JBeulich, joe, kosaki.motohiro

Hello.

As it seems that there is no critical problem (naming preference can easily be
fixed if needed), can these patches go to linux-next?

If these patches are accepted, Kees Cook will submit a patch which removes %n
support from vsnprintf() ( https://lkml.org/lkml/2013/9/16/54 ).

Regards.
----------------------------------------
>From 02b28fd709971f71e5de9a5b595ff4fd059028b3 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Date: Thu, 19 Sep 2013 17:23:17 +0900
Subject: [PATCH] seq_file: Introduce seq_setwidth() and seq_pad()

There are several users who want to know bytes written by seq_*() for alignment
purpose. Currently they are using %n format for knowing it because seq_*()
returns 0 on success.

This patch introduces seq_setwidth() and seq_pad() for allowing them to align
without using %n format.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Kees Cook <keescook@chromium.org>
---
 fs/seq_file.c            |   15 +++++++++++++++
 include/linux/seq_file.h |   15 +++++++++++++++
 2 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/fs/seq_file.c b/fs/seq_file.c
index 3135c25..40e471e 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -764,6 +764,21 @@ int seq_write(struct seq_file *seq, const void *data, size_t len)
 }
 EXPORT_SYMBOL(seq_write);
 
+/**
+ * seq_pad - write padding spaces to buffer
+ * @m: seq_file identifying the buffer to which data should be written
+ * @c: the byte to append after padding if non-zero
+ */
+void seq_pad(struct seq_file *m, char c)
+{
+	int size = m->pad_until - m->count;
+	if (size > 0)
+		seq_printf(m, "%*s", size, "");
+	if (c)
+		seq_putc(m, c);
+}
+EXPORT_SYMBOL(seq_pad);
+
 struct list_head *seq_list_start(struct list_head *head, loff_t pos)
 {
 	struct list_head *lh;
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 4e32edc..52e0097 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -20,6 +20,7 @@ struct seq_file {
 	size_t size;
 	size_t from;
 	size_t count;
+	size_t pad_until;
 	loff_t index;
 	loff_t read_pos;
 	u64 version;
@@ -79,6 +80,20 @@ static inline void seq_commit(struct seq_file *m, int num)
 	}
 }
 
+/**
+ * seq_setwidth - set padding width
+ * @m: the seq_file handle
+ * @size: the max number of bytes to pad.
+ *
+ * Call seq_setwidth() for setting max width, then call seq_printf() etc. and
+ * finally call seq_pad() to pad the remaining bytes.
+ */
+static inline void seq_setwidth(struct seq_file *m, size_t size)
+{
+	m->pad_until = m->count + size;
+}
+void seq_pad(struct seq_file *m, char c);
+
 char *mangle_path(char *s, const char *p, const char *esc);
 int seq_open(struct file *, const struct seq_operations *);
 ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
-- 
1.7.1
----------------------------------------
>From f8b60ebe3971901b93dedb8eee0f85b60d0fdc5f Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Date: Fri, 20 Sep 2013 12:01:07 +0900
Subject: [PATCH] Remove "%n" usage from seq_file users.

All seq_printf() users are using "%n" for calculating padding size, convert
them to use seq_setwidth() / seq_pad() pair.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Kees Cook <keescook@chromium.org>
---
 fs/proc/consoles.c   |   10 ++++------
 fs/proc/nommu.c      |   12 +++++-------
 fs/proc/task_mmu.c   |   20 ++++++--------------
 fs/proc/task_nommu.c |   19 ++++++-------------
 net/ipv4/fib_trie.c  |   13 +++++++------
 net/ipv4/ping.c      |   15 +++++++--------
 net/ipv4/tcp_ipv4.c  |   33 +++++++++++++++------------------
 net/ipv4/udp.c       |   15 +++++++--------
 net/phonet/socket.c  |   24 +++++++++++-------------
 net/sctp/objcnt.c    |    9 +++++----
 10 files changed, 73 insertions(+), 97 deletions(-)

diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index b701eaa..51942d5 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -29,7 +29,6 @@ static int show_console_dev(struct seq_file *m, void *v)
 	char flags[ARRAY_SIZE(con_flags) + 1];
 	struct console *con = v;
 	unsigned int a;
-	int len;
 	dev_t dev = 0;
 
 	if (con->device) {
@@ -47,11 +46,10 @@ static int show_console_dev(struct seq_file *m, void *v)
 			con_flags[a].name : ' ';
 	flags[a] = 0;
 
-	seq_printf(m, "%s%d%n", con->name, con->index, &len);
-	len = 21 - len;
-	if (len < 1)
-		len = 1;
-	seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
+	seq_setwidth(m, 21 - 1);
+	seq_printf(m, "%s%d", con->name, con->index);
+	seq_pad(m, ' ');
+	seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
 			con->write ? 'W' : '-', con->unblank ? 'U' : '-',
 			flags);
 	if (dev)
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index ccfd99b..5f9bc8a 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -39,7 +39,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 	unsigned long ino = 0;
 	struct file *file;
 	dev_t dev = 0;
-	int flags, len;
+	int flags;
 
 	flags = region->vm_flags;
 	file = region->vm_file;
@@ -50,8 +50,9 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 		ino = inode->i_ino;
 	}
 
+	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
 	seq_printf(m,
-		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 		   region->vm_start,
 		   region->vm_end,
 		   flags & VM_READ ? 'r' : '-',
@@ -59,13 +60,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region)
 		   flags & VM_EXEC ? 'x' : '-',
 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
 		   ((loff_t)region->vm_pgoff) << PAGE_SHIFT,
-		   MAJOR(dev), MINOR(dev), ino, &len);
+		   MAJOR(dev), MINOR(dev), ino);
 
 	if (file) {
-		len = 25 + sizeof(void *) * 6 - len;
-		if (len < 1)
-			len = 1;
-		seq_printf(m, "%*c", len, ' ');
+		seq_pad(m, ' ');
 		seq_path(m, &file->f_path, "");
 	}
 
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7366e9d..cc24165 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -83,14 +83,6 @@ unsigned long task_statm(struct mm_struct *mm,
 	return mm->total_vm;
 }
 
-static void pad_len_spaces(struct seq_file *m, int len)
-{
-	len = 25 + sizeof(void*) * 6 - len;
-	if (len < 1)
-		len = 1;
-	seq_printf(m, "%*c", len, ' ');
-}
-
 #ifdef CONFIG_NUMA
 /*
  * These functions are for numa_maps but called in generic **maps seq_file
@@ -268,7 +260,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 	unsigned long long pgoff = 0;
 	unsigned long start, end;
 	dev_t dev = 0;
-	int len;
 	const char *name = NULL;
 
 	if (file) {
@@ -286,7 +277,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 	if (stack_guard_page_end(vma, end))
 		end -= PAGE_SIZE;
 
-	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
+	seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 			start,
 			end,
 			flags & VM_READ ? 'r' : '-',
@@ -294,14 +286,14 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 			flags & VM_EXEC ? 'x' : '-',
 			flags & VM_MAYSHARE ? 's' : 'p',
 			pgoff,
-			MAJOR(dev), MINOR(dev), ino, &len);
+			MAJOR(dev), MINOR(dev), ino);
 
 	/*
 	 * Print the dentry name for named mappings, and a
 	 * special [heap] marker for the heap:
 	 */
 	if (file) {
-		pad_len_spaces(m, len);
+		seq_pad(m, ' ');
 		seq_path(m, &file->f_path, "\n");
 		goto done;
 	}
@@ -333,7 +325,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 				name = "[stack]";
 			} else {
 				/* Thread stack in /proc/PID/maps */
-				pad_len_spaces(m, len);
+				seq_pad(m, ' ');
 				seq_printf(m, "[stack:%d]", tid);
 			}
 		}
@@ -341,7 +333,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 
 done:
 	if (name) {
-		pad_len_spaces(m, len);
+		seq_pad(m, ' ');
 		seq_puts(m, name);
 	}
 	seq_putc(m, '\n');
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 56123a6..678455d 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -123,14 +123,6 @@ unsigned long task_statm(struct mm_struct *mm,
 	return size;
 }
 
-static void pad_len_spaces(struct seq_file *m, int len)
-{
-	len = 25 + sizeof(void*) * 6 - len;
-	if (len < 1)
-		len = 1;
-	seq_printf(m, "%*c", len, ' ');
-}
-
 /*
  * display a single VMA to a sequenced file
  */
@@ -142,7 +134,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 	unsigned long ino = 0;
 	struct file *file;
 	dev_t dev = 0;
-	int flags, len;
+	int flags;
 	unsigned long long pgoff = 0;
 
 	flags = vma->vm_flags;
@@ -155,8 +147,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 		pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
 	}
 
+	seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
 	seq_printf(m,
-		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+		   "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
 		   vma->vm_start,
 		   vma->vm_end,
 		   flags & VM_READ ? 'r' : '-',
@@ -164,16 +157,16 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
 		   flags & VM_EXEC ? 'x' : '-',
 		   flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
 		   pgoff,
-		   MAJOR(dev), MINOR(dev), ino, &len);
+		   MAJOR(dev), MINOR(dev), ino);
 
 	if (file) {
-		pad_len_spaces(m, len);
+		seq_pad(m, ' ');
 		seq_path(m, &file->f_path, "");
 	} else if (mm) {
 		pid_t tid = vm_is_stack(priv->task, vma, is_pid);
 
 		if (tid != 0) {
-			pad_len_spaces(m, len);
+			seq_pad(m, ' ');
 			/*
 			 * Thread stack in /proc/PID/task/TID/maps or
 			 * the main process stack.
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 3df6d3e..b1af50e 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2530,16 +2530,17 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 		list_for_each_entry_rcu(fa, &li->falh, fa_list) {
 			const struct fib_info *fi = fa->fa_info;
 			unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
-			int len;
 
 			if (fa->fa_type == RTN_BROADCAST
 			    || fa->fa_type == RTN_MULTICAST)
 				continue;
 
+			seq_setwidth(seq, 127);
+
 			if (fi)
 				seq_printf(seq,
 					 "%s\t%08X\t%08X\t%04X\t%d\t%u\t"
-					 "%d\t%08X\t%d\t%u\t%u%n",
+					 "%d\t%08X\t%d\t%u\t%u",
 					 fi->fib_dev ? fi->fib_dev->name : "*",
 					 prefix,
 					 fi->fib_nh->nh_gw, flags, 0, 0,
@@ -2548,15 +2549,15 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
 					 (fi->fib_advmss ?
 					  fi->fib_advmss + 40 : 0),
 					 fi->fib_window,
-					 fi->fib_rtt >> 3, &len);
+					 fi->fib_rtt >> 3);
 			else
 				seq_printf(seq,
 					 "*\t%08X\t%08X\t%04X\t%d\t%u\t"
-					 "%d\t%08X\t%d\t%u\t%u%n",
+					 "%d\t%08X\t%d\t%u\t%u",
 					 prefix, 0, flags, 0, 0, 0,
-					 mask, 0, 0, 0, &len);
+					 mask, 0, 0, 0);
 
-			seq_printf(seq, "%*s\n", 127 - len, "");
+			seq_pad(seq, '\n');
 		}
 	}
 
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index d7d9882..94cc685 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -1073,7 +1073,7 @@ void ping_seq_stop(struct seq_file *seq, void *v)
 EXPORT_SYMBOL_GPL(ping_seq_stop);
 
 static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
-		int bucket, int *len)
+		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->inet_daddr;
@@ -1082,7 +1082,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
 	__u16 srcp = ntohs(inet->inet_sport);
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
@@ -1090,23 +1090,22 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
 		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
 		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
-		atomic_read(&sp->sk_drops), len);
+		atomic_read(&sp->sk_drops));
 }
 
 static int ping_v4_seq_show(struct seq_file *seq, void *v)
 {
+	seq_setwidth(seq, 127);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%-127s\n",
-			   "  sl  local_address rem_address   st tx_queue "
+		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode ref pointer drops");
 	else {
 		struct ping_iter_state *state = seq->private;
-		int len;
 
-		ping_v4_format_sock(v, seq, state->bucket, &len);
-		seq_printf(seq, "%*s\n", 127 - len, "");
+		ping_v4_format_sock(v, seq, state->bucket);
 	}
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b14266b..2948b76 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2598,13 +2598,13 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 EXPORT_SYMBOL(tcp_proc_unregister);
 
 static void get_openreq4(const struct sock *sk, const struct request_sock *req,
-			 struct seq_file *f, int i, kuid_t uid, int *len)
+			 struct seq_file *f, int i, kuid_t uid)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	long delta = req->expires - jiffies;
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK",
 		i,
 		ireq->loc_addr,
 		ntohs(inet_sk(sk)->inet_sport),
@@ -2619,11 +2619,10 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
 		0,  /* non standard timer */
 		0, /* open_requests have no inode */
 		atomic_read(&sk->sk_refcnt),
-		req,
-		len);
+		req);
 }
 
-static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
+static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
 {
 	int timer_active;
 	unsigned long timer_expires;
@@ -2662,7 +2661,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d%n",
+			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
 		i, src, srcp, dest, destp, sk->sk_state,
 		tp->write_seq - tp->snd_una,
 		rx_queue,
@@ -2679,12 +2678,11 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
 		tp->snd_cwnd,
 		sk->sk_state == TCP_LISTEN ?
 		    (fastopenq ? fastopenq->max_qlen : 0) :
-		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh),
-		len);
+		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));
 }
 
 static void get_timewait4_sock(const struct inet_timewait_sock *tw,
-			       struct seq_file *f, int i, int *len)
+			       struct seq_file *f, int i)
 {
 	__be32 dest, src;
 	__u16 destp, srcp;
@@ -2696,10 +2694,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 	srcp  = ntohs(tw->tw_sport);
 
 	seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
 		i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
 		3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
-		atomic_read(&tw->tw_refcnt), tw, len);
+		atomic_read(&tw->tw_refcnt), tw);
 }
 
 #define TMPSZ 150
@@ -2707,11 +2705,10 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 static int tcp4_seq_show(struct seq_file *seq, void *v)
 {
 	struct tcp_iter_state *st;
-	int len;
 
+	seq_setwidth(seq, TMPSZ - 1);
 	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq, "%-*s\n", TMPSZ - 1,
-			   "  sl  local_address rem_address   st tx_queue "
+		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode");
 		goto out;
@@ -2721,17 +2718,17 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)
 	switch (st->state) {
 	case TCP_SEQ_STATE_LISTENING:
 	case TCP_SEQ_STATE_ESTABLISHED:
-		get_tcp4_sock(v, seq, st->num, &len);
+		get_tcp4_sock(v, seq, st->num);
 		break;
 	case TCP_SEQ_STATE_OPENREQ:
-		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
+		get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid);
 		break;
 	case TCP_SEQ_STATE_TIME_WAIT:
-		get_timewait4_sock(v, seq, st->num, &len);
+		get_timewait4_sock(v, seq, st->num);
 		break;
 	}
-	seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
 out:
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 74d2c95..31c132c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2150,7 +2150,7 @@ EXPORT_SYMBOL(udp_proc_unregister);
 
 /* ------------------------------------------------------------------------ */
 static void udp4_format_sock(struct sock *sp, struct seq_file *f,
-		int bucket, int *len)
+		int bucket)
 {
 	struct inet_sock *inet = inet_sk(sp);
 	__be32 dest = inet->inet_daddr;
@@ -2159,7 +2159,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 	__u16 srcp	  = ntohs(inet->inet_sport);
 
 	seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d%n",
+		" %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
 		bucket, src, srcp, dest, destp, sp->sk_state,
 		sk_wmem_alloc_get(sp),
 		sk_rmem_alloc_get(sp),
@@ -2167,23 +2167,22 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
 		from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
 		0, sock_i_ino(sp),
 		atomic_read(&sp->sk_refcnt), sp,
-		atomic_read(&sp->sk_drops), len);
+		atomic_read(&sp->sk_drops));
 }
 
 int udp4_seq_show(struct seq_file *seq, void *v)
 {
+	seq_setwidth(seq, 127);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%-127s\n",
-			   "  sl  local_address rem_address   st tx_queue "
+		seq_puts(seq, "  sl  local_address rem_address   st tx_queue "
 			   "rx_queue tr tm->when retrnsmt   uid  timeout "
 			   "inode ref pointer drops");
 	else {
 		struct udp_iter_state *state = seq->private;
-		int len;
 
-		udp4_format_sock(v, seq, state->bucket, &len);
-		seq_printf(seq, "%*s\n", 127 - len, "");
+		udp4_format_sock(v, seq, state->bucket);
 	}
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 77e38f7..008214a 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -595,26 +595,25 @@ static void pn_sock_seq_stop(struct seq_file *seq, void *v)
 
 static int pn_sock_seq_show(struct seq_file *seq, void *v)
 {
-	int len;
-
+	seq_setwidth(seq, 127);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%s%n", "pt  loc  rem rs st tx_queue rx_queue "
-			"  uid inode ref pointer drops", &len);
+		seq_puts(seq, "pt  loc  rem rs st tx_queue rx_queue "
+			"  uid inode ref pointer drops");
 	else {
 		struct sock *sk = v;
 		struct pn_sock *pn = pn_sk(sk);
 
 		seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
-			"%d %pK %d%n",
+			"%d %pK %d",
 			sk->sk_protocol, pn->sobject, pn->dobject,
 			pn->resource, sk->sk_state,
 			sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
 			from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
 			sock_i_ino(sk),
 			atomic_read(&sk->sk_refcnt), sk,
-			atomic_read(&sk->sk_drops), &len);
+			atomic_read(&sk->sk_drops));
 	}
-	seq_printf(seq, "%*s\n", 127 - len, "");
+	seq_pad(seq, '\n');
 	return 0;
 }
 
@@ -785,20 +784,19 @@ static void pn_res_seq_stop(struct seq_file *seq, void *v)
 
 static int pn_res_seq_show(struct seq_file *seq, void *v)
 {
-	int len;
-
+	seq_setwidth(seq, 63);
 	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "%s%n", "rs   uid inode", &len);
+		seq_puts(seq, "rs   uid inode");
 	else {
 		struct sock **psk = v;
 		struct sock *sk = *psk;
 
-		seq_printf(seq, "%02X %5u %lu%n",
+		seq_printf(seq, "%02X %5u %lu",
 			   (int) (psk - pnres.sk),
 			   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
-			   sock_i_ino(sk), &len);
+			   sock_i_ino(sk));
 	}
-	seq_printf(seq, "%*s\n", 63 - len, "");
+	seq_pad(seq, '\n');
 	return 0;
 }
 
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index 5ea573b..647396b 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -79,12 +79,13 @@ static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
  */
 static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
 {
-	int i, len;
+	int i;
 
 	i = (int)*(loff_t *)v;
-	seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
-				atomic_read(sctp_dbg_objcnt[i].counter), &len);
-	seq_printf(seq, "%*s\n", 127 - len, "");
+	seq_setwidth(seq, 127);
+	seq_printf(seq, "%s: %d", sctp_dbg_objcnt[i].label,
+				atomic_read(sctp_dbg_objcnt[i].counter));
+	seq_pad(seq, '\n');
 	return 0;
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2013-09-30  8:18 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-16  7:43 [PATCH 0/2] vsprintf: ignore %n again Kees Cook
2013-09-16  7:43 ` [PATCH 1/2] remove all uses of printf's %n Kees Cook
2013-09-16  8:09   ` Geert Uytterhoeven
2013-09-16 15:00     ` Kees Cook
2013-09-17 13:06       ` Tetsuo Handa
2013-09-17 14:34         ` Kees Cook
2013-09-17 20:57           ` George Spelvin
2013-09-19  8:56             ` Tetsuo Handa
2013-09-19 14:28               ` Kees Cook
2013-09-20  4:09                 ` Tetsuo Handa
2013-09-20  4:23                   ` Joe Perches
2013-09-20  4:53                     ` Kees Cook
2013-09-20  8:08                   ` Jiri Slaby
2013-09-20 19:24                     ` Kees Cook
2013-09-20 19:33                       ` Joe Perches
2013-09-21  0:28                       ` Tetsuo Handa
2013-09-22  8:09                         ` George Spelvin
2013-09-22  8:16                         ` Geert Uytterhoeven
2013-09-23 21:24                   ` Kees Cook
2013-09-30  8:16                     ` Tetsuo Handa
2013-09-16 11:41   ` Tetsuo Handa
2013-09-16 14:59     ` Kees Cook
2013-09-16 15:09       ` Joe Perches
2013-09-16 15:25         ` Kees Cook
2013-09-16 15:44           ` Joe Perches
2013-09-16 17:21         ` George Spelvin
2013-09-16 18:03           ` Joe Perches
2013-09-16 16:07   ` George Spelvin
2013-09-16 16:13     ` Joe Perches
2013-09-16 16:39       ` George Spelvin
2013-09-16 17:53         ` Joe Perches
2013-09-16 19:15           ` George Spelvin
2013-09-16 19:25             ` Joe Perches
2013-09-16  7:43 ` [PATCH 2/2] vsprintf: ignore %n again Kees Cook
2013-09-16 15:55 ` [PATCH 0/2] " Al Viro
2013-09-16 16:15   ` Lars-Peter Clausen
2013-09-16 16:30   ` George Spelvin
2013-09-16 18:20   ` Kees Cook
2013-09-18 13:14     ` Tetsuo Handa
2013-09-18 14:11       ` Dan Carpenter
2013-09-18 14:28         ` Dan Carpenter
2013-09-18 15:22         ` George Spelvin
2013-09-18 14:32       ` Kees Cook
2013-09-19  2:11         ` Tetsuo Handa
2013-09-19  7:08           ` Tetsuo Handa
2013-09-18 14:47       ` Kees Cook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).