From: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
Subject: powerpc/rtas_flash: Fix validate_flash buffer overflow issue
Git-commit: a94a14720eaf55c5f06d6ca7ecbe3f87f6864fc6
Patch-mainline: yes
References: bnc#847842 

    powerpc/rtas_flash: Fix validate_flash buffer overflow issue

    ibm,validate-flash-image RTAS call output buffer contains 150 - 200
    bytes of data on latest system. Presently we have output
    buffer size as 64 bytes and we use sprintf to copy data from
    RTAS buffer to local buffer. This causes kernel oops (see below
    call trace).

    This patch increases local buffer size to 256 and also uses
    snprintf instead of sprintf to copy data from RTAS buffer.

Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Torsten Duwe <duwe@suse.de>

--- a/arch/powerpc/kernel/rtas_flash.c	2013-10-22 07:17:59.000000000 -0500
+++ b/arch/powerpc/kernel/rtas_flash.c	2013-10-22 07:16:53.000000000 -0500
@@ -71,6 +71,7 @@
 
 /* Array sizes */
 #define VALIDATE_BUF_SIZE 4096    
+#define VALIDATE_MSG_LEN  256
 #define RTAS_MSG_MAXLEN   64
 
 /* Quirk - RTAS requires 4k list length and block size */
@@ -438,7 +439,7 @@ static void validate_flash(struct rtas_v
 }
 
 static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf, 
-		                   char *msg)
+		                   char *msg, int msglen)
 {
 	int n;
 
@@ -446,7 +447,8 @@ static int get_validate_flash_msg(struct
 		n = sprintf(msg, "%d\n", args_buf->update_results);
 		if ((args_buf->update_results >= VALIDATE_CUR_UNKNOWN) ||
 		    (args_buf->update_results == VALIDATE_TMP_UPDATE))
-			n += sprintf(msg + n, "%s\n", args_buf->buf);
+			n += snprintf(msg + n, msglen - n, "%s\n",
+					args_buf->buf);
 	} else {
 		n = sprintf(msg, "%d\n", args_buf->status);
 	}
@@ -458,12 +460,12 @@ static ssize_t validate_flash_read(struc
 {
 	struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
 	struct rtas_validate_flash_t *args_buf;
-	char msg[RTAS_MSG_MAXLEN];
+	char msg[VALIDATE_MSG_LEN];
 	int msglen;
 
 	args_buf = dp->data;
 
-	msglen = get_validate_flash_msg(args_buf, msg);
+	msglen = get_validate_flash_msg(args_buf, msg, VALIDATE_MSG_LEN);
 
 	return simple_read_from_buffer(buf, count, ppos, msg, msglen);
 }
