From: Anton Blanchard Linas Vepstas has audited the ppc64 proc code and found a number of issues. 25-akpm/arch/ppc64/kernel/mf_proc.c | 26 ++++-- 25-akpm/arch/ppc64/kernel/proc_pmc.c | 29 ++++--- 25-akpm/arch/ppc64/kernel/rtas-proc.c | 132 +++++++++++++++++++++++++--------- 25-akpm/arch/ppc64/kernel/scanlog.c | 13 ++- 4 files changed, 147 insertions(+), 53 deletions(-) diff -puN arch/ppc64/kernel/mf_proc.c~ppc64-proc-fixes arch/ppc64/kernel/mf_proc.c --- 25/arch/ppc64/kernel/mf_proc.c~ppc64-proc-fixes Wed Jan 7 11:22:19 2004 +++ 25-akpm/arch/ppc64/kernel/mf_proc.c Wed Jan 7 11:22:19 2004 @@ -220,19 +220,25 @@ int proc_mf_dump_side int proc_mf_change_side(struct file *file, const char *buffer, unsigned long count, void *data) { + char stkbuf[10]; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if ((*buffer != 'A') && - (*buffer != 'B') && - (*buffer != 'C') && - (*buffer != 'D')) + if (count > 9) count = 9; + if (copy_from_user (stkbuf, buffer, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + if ((*stkbuf != 'A') && + (*stkbuf != 'B') && + (*stkbuf != 'C') && + (*stkbuf != 'D')) { printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); return -EINVAL; } - mf_setSide(*buffer); + mf_setSide(*stkbuf); return count; } @@ -256,6 +262,7 @@ int proc_mf_dump_src int proc_mf_change_src(struct file *file, const char *buffer, unsigned long count, void *data) { + char stkbuf[10]; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -265,11 +272,16 @@ int proc_mf_change_src(struct file *file return -EINVAL; } - if ((count == 1) && ((*buffer) == '\0')) + if (count > 9) count = 9; + if (copy_from_user (stkbuf, buffer, count)) { + return -EFAULT; + } + + if ((count == 1) && ((*stkbuf) == '\0')) { mf_clearSrc(); } else { - mf_displaySrc(*(u32 *)buffer); + mf_displaySrc(*(u32 *)stkbuf); } return count; diff -puN arch/ppc64/kernel/proc_pmc.c~ppc64-proc-fixes arch/ppc64/kernel/proc_pmc.c --- 25/arch/ppc64/kernel/proc_pmc.c~ppc64-proc-fixes Wed Jan 7 11:22:19 2004 +++ 25-akpm/arch/ppc64/kernel/proc_pmc.c Wed Jan 7 11:22:19 2004 @@ -127,7 +127,7 @@ void proc_ppc64_init(void) ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->read_proc = (void *)proc_ppc64_pmc_stab_read; - ent->write_proc = (void *)proc_ppc64_pmc_stab_read; + ent->write_proc = NULL; } ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, @@ -136,7 +136,7 @@ void proc_ppc64_init(void) ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->read_proc = (void *)proc_ppc64_pmc_htab_read; - ent->write_proc = (void *)proc_ppc64_pmc_htab_read; + ent->write_proc = NULL; } } @@ -146,7 +146,7 @@ void proc_ppc64_init(void) ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_system_root; ent->read_proc = (void *)proc_ppc64_pmc_stab_read; - ent->write_proc = (void *)proc_ppc64_pmc_stab_read; + ent->write_proc = NULL; } ent = create_proc_entry("htab", S_IRUGO | S_IWUSR, @@ -155,7 +155,7 @@ void proc_ppc64_init(void) ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_system_root; ent->read_proc = (void *)proc_ppc64_pmc_htab_read; - ent->write_proc = (void *)proc_ppc64_pmc_htab_read; + ent->write_proc = NULL; } /* Create directories for the hardware counters. */ @@ -168,7 +168,7 @@ void proc_ppc64_init(void) ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->read_proc = (void *)proc_ppc64_pmc_hw_read; - ent->write_proc = (void *)proc_ppc64_pmc_hw_read; + ent->write_proc = NULL; } } @@ -178,7 +178,7 @@ void proc_ppc64_init(void) ent->nlink = 1; ent->data = (void *)proc_ppc64_pmc_system_root; ent->read_proc = (void *)proc_ppc64_pmc_hw_read; - ent->write_proc = (void *)proc_ppc64_pmc_hw_read; + ent->write_proc = NULL; } } @@ -676,15 +676,22 @@ static inline void proc_pmc_tlb(void) int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data ) { - if ( ! strncmp( buffer, "stop", 4 ) ) + char stkbuf[10]; + if (count > 9) count = 9; + if (copy_from_user (stkbuf, buffer, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + + if ( ! strncmp( stkbuf, "stop", 4 ) ) proc_pmc_stop(); - else if ( ! strncmp( buffer, "start", 5 ) ) + else if ( ! strncmp( stkbuf, "start", 5 ) ) proc_pmc_start(); - else if ( ! strncmp( buffer, "reset", 5 ) ) + else if ( ! strncmp( stkbuf, "reset", 5 ) ) proc_pmc_reset(); - else if ( ! strncmp( buffer, "cpi", 3 ) ) + else if ( ! strncmp( stkbuf, "cpi", 3 ) ) proc_pmc_cpi(); - else if ( ! strncmp( buffer, "tlb", 3 ) ) + else if ( ! strncmp( stkbuf, "tlb", 3 ) ) proc_pmc_tlb(); /* IMPLEMENT ME */ diff -puN arch/ppc64/kernel/rtas-proc.c~ppc64-proc-fixes arch/ppc64/kernel/rtas-proc.c --- 25/arch/ppc64/kernel/rtas-proc.c~ppc64-proc-fixes Wed Jan 7 11:22:19 2004 +++ 25-akpm/arch/ppc64/kernel/rtas-proc.c Wed Jan 7 11:22:19 2004 @@ -241,12 +241,18 @@ void proc_rtas_init(void) static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + char stkbuf[40]; /* its small, its on stack */ struct rtc_time tm; unsigned long nowtime; char *dest; int error; - nowtime = simple_strtoul(buf, &dest, 10); + if (39 < count) count = 39; + if (copy_from_user (stkbuf, buf, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + nowtime = simple_strtoul(stkbuf, &dest, 10); if (*dest != '\0' && *dest != '\n') { printk("ppc_rtas_poweron_write: Invalid time\n"); return count; @@ -267,18 +273,23 @@ static ssize_t ppc_rtas_poweron_write(st static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, size_t count, loff_t *ppos) { + char stkbuf[40]; /* its small, its on stack */ int n; if (power_on_time == 0) - n = sprintf(buf, "Power on time not set\n"); + n = snprintf(stkbuf, 40, "Power on time not set\n"); else - n = sprintf(buf, "%lu\n", power_on_time); + n = snprintf(stkbuf, 40, "%lu\n", power_on_time); - if (*ppos >= strlen(buf)) + int sn = strlen (stkbuf) +1; + if (*ppos >= sn) return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; + if (n > sn - *ppos) + n = sn - *ppos; if (n > count) n = count; + if (copy_to_user (buf, stkbuf + (*ppos), n)) { + return -EFAULT; + } *ppos += n; return n; } @@ -291,11 +302,16 @@ static ssize_t ppc_rtas_progress_write(s { unsigned long hex; - strcpy(progress_led, buf); /* save the string */ + if (count >= MAX_LINELENGTH) count = MAX_LINELENGTH -1; + if (copy_from_user (progress_led, buf, count)) { /* save the string */ + return -EFAULT; + } + progress_led[count] = 0; + /* Lets see if the user passed hexdigits */ - hex = simple_strtoul(buf, NULL, 10); - - ppc_md.progress ((char *)buf, hex); + hex = simple_strtoul(progress_led, NULL, 10); + + ppc_md.progress ((char *)progress_led, hex); return count; /* clear the line */ /* ppc_md.progress(" ", 0xffff);*/ @@ -305,14 +321,30 @@ static ssize_t ppc_rtas_progress_read(st size_t count, loff_t *ppos) { int n = 0; - if (progress_led != NULL) - n = sprintf (buf, "%s\n", progress_led); - if (*ppos >= strlen(buf)) + + if (progress_led == NULL) return 0; + + char * tmpbuf = kmalloc (MAX_LINELENGTH, GFP_KERNEL); + if (!tmpbuf) { + printk(KERN_ERR "error: kmalloc failed\n"); + return -ENOMEM; + } + n = sprintf (tmpbuf, "%s\n", progress_led); + + int sn = strlen (tmpbuf) +1; + if (*ppos >= sn) { + kfree (tmpbuf); return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; + } + if (n > sn - *ppos) + n = sn - *ppos; if (n > count) n = count; + if (copy_to_user (buf, tmpbuf + (*ppos), n)) { + kfree (tmpbuf); + return -EFAULT; + } + kfree (tmpbuf); *ppos += n; return n; } @@ -323,12 +355,18 @@ static ssize_t ppc_rtas_progress_read(st static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + char stkbuf[40]; /* its small, its on stack */ struct rtc_time tm; unsigned long nowtime; char *dest; int error; - nowtime = simple_strtoul(buf, &dest, 10); + if (39 < count) count = 39; + if (copy_from_user (stkbuf, buf, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + nowtime = simple_strtoul(stkbuf, &dest, 10); if (*dest != '\0' && *dest != '\n') { printk("ppc_rtas_clock_write: Invalid time\n"); return count; @@ -356,21 +394,27 @@ static ssize_t ppc_rtas_clock_read(struc year = ret[0]; mon = ret[1]; day = ret[2]; hour = ret[3]; min = ret[4]; sec = ret[5]; + char stkbuf[40]; /* its small, its on stack */ + if (error != 0){ printk(KERN_WARNING "error: reading the clock returned: %s\n", ppc_rtas_process_error(error)); - n = sprintf (buf, "0"); + n = snprintf (stkbuf, 40, "0"); } else { - n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec)); + n = snprintf (stkbuf, 40, "%lu\n", mktime(year, mon, day, hour, min, sec)); } kfree(ret); - if (*ppos >= strlen(buf)) + int sn = strlen (stkbuf) +1; + if (*ppos >= sn) return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; + if (n > sn - *ppos) + n = sn - *ppos; if (n > count) n = count; + if (copy_to_user (buf, stkbuf + (*ppos), n)) { + return -EFAULT; + } *ppos += n; return n; } @@ -764,7 +808,7 @@ int get_location_code(struct individual_ n += check_location_string(ret, buffer + n); n += sprintf ( buffer+n, " "); /* see how many characters we have printed */ - sprintf ( t, "%s ", ret); + snprintf ( t, 50, "%s ", ret); pos += strlen(t); if (pos >= llen) pos=0; @@ -777,10 +821,17 @@ int get_location_code(struct individual_ static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + char stkbuf[40]; /* its small, its on stack */ unsigned long freq; char *dest; int error; - freq = simple_strtoul(buf, &dest, 10); + + if (39 < count) count = 39; + if (copy_from_user (stkbuf, buf, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + freq = simple_strtoul(stkbuf, &dest, 10); if (*dest != '\0' && *dest != '\n') { printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n"); return count; @@ -799,14 +850,19 @@ static ssize_t ppc_rtas_tone_freq_read(s size_t count, loff_t *ppos) { int n; - n = sprintf(buf, "%lu\n", rtas_tone_frequency); + char stkbuf[40]; /* its small, its on stack */ + n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency); - if (*ppos >= strlen(buf)) + int sn = strlen (stkbuf) +1; + if (*ppos >= sn) return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; + if (n > sn - *ppos) + n = sn - *ppos; if (n > count) n = count; + if (copy_to_user (buf, stkbuf + (*ppos), n)) { + return -EFAULT; + } *ppos += n; return n; } @@ -816,10 +872,17 @@ static ssize_t ppc_rtas_tone_freq_read(s static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + char stkbuf[40]; /* its small, its on stack */ unsigned long volume; char *dest; int error; - volume = simple_strtoul(buf, &dest, 10); + + if (39 < count) count = 39; + if (copy_from_user (stkbuf, buf, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + volume = simple_strtoul(stkbuf, &dest, 10); if (*dest != '\0' && *dest != '\n') { printk("ppc_rtas_tone_volume_write: Invalid tone volume\n"); return count; @@ -840,14 +903,19 @@ static ssize_t ppc_rtas_tone_volume_read size_t count, loff_t *ppos) { int n; - n = sprintf(buf, "%lu\n", rtas_tone_volume); + char stkbuf[40]; /* its small, its on stack */ + n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_volume); - if (*ppos >= strlen(buf)) + int sn = strlen (stkbuf) +1; + if (*ppos >= sn) return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; + if (n > sn - *ppos) + n = sn - *ppos; if (n > count) n = count; + if (copy_to_user (buf, stkbuf + (*ppos), n)) { + return -EFAULT; + } *ppos += n; return n; } diff -puN arch/ppc64/kernel/scanlog.c~ppc64-proc-fixes arch/ppc64/kernel/scanlog.c --- 25/arch/ppc64/kernel/scanlog.c~ppc64-proc-fixes Wed Jan 7 11:22:19 2004 +++ 25-akpm/arch/ppc64/kernel/scanlog.c Wed Jan 7 11:22:19 2004 @@ -135,17 +135,24 @@ static ssize_t scanlog_read(struct file static ssize_t scanlog_write(struct file * file, const char * buf, size_t count, loff_t *ppos) { + char stkbuf[20]; unsigned long status; + if (count > 19) count = 19; + if (copy_from_user (stkbuf, buf, count)) { + return -EFAULT; + } + stkbuf[count] = 0; + if (buf) { - if (strncmp(buf, "reset", 5) == 0) { + if (strncmp(stkbuf, "reset", 5) == 0) { DEBUG("reset scanlog\n"); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0); DEBUG("rtas returns %ld\n", status); - } else if (strncmp(buf, "debugon", 7) == 0) { + } else if (strncmp(stkbuf, "debugon", 7) == 0) { printk(KERN_ERR "scanlog: debug on\n"); scanlog_debug = 1; - } else if (strncmp(buf, "debugoff", 8) == 0) { + } else if (strncmp(stkbuf, "debugoff", 8) == 0) { printk(KERN_ERR "scanlog: debug off\n"); scanlog_debug = 0; } _