From 81d2e766100b6bc311be63a961422956aecf6ce4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 7 Jan 2004 05:56:50 -0800 Subject: [PATCH] [PATCH] /proc/ppc64 and /proc/iSeries fixes from Linas Vepstas From: Anton Blanchard Linas Vepstas has audited the ppc64 proc code and found a number of issues. --- arch/ppc64/kernel/mf_proc.c | 26 +++++-- arch/ppc64/kernel/proc_pmc.c | 29 +++++--- arch/ppc64/kernel/rtas-proc.c | 132 +++++++++++++++++++++++++--------- arch/ppc64/kernel/scanlog.c | 13 +++- 4 files changed, 147 insertions(+), 53 deletions(-) diff --git a/arch/ppc64/kernel/mf_proc.c b/arch/ppc64/kernel/mf_proc.c index a6ec2ddce351e..dd12477d2c590 100644 --- a/arch/ppc64/kernel/mf_proc.c +++ b/arch/ppc64/kernel/mf_proc.c @@ -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, const char *buffer, unsigned long coun 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 --git a/arch/ppc64/kernel/proc_pmc.c b/arch/ppc64/kernel/proc_pmc.c index 2b4fec39bec19..349e4cd39a77c 100644 --- a/arch/ppc64/kernel/proc_pmc.c +++ b/arch/ppc64/kernel/proc_pmc.c @@ -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 --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c index b7e133a7518fe..1dcb17b0d3151 100644 --- a/arch/ppc64/kernel/rtas-proc.c +++ b/arch/ppc64/kernel/rtas-proc.c @@ -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(struct file * file, const char * buf, 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(struct file * file, const char * buf, { 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(struct file * file, char * buf, 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(struct file * file, char * buf, 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(struct file * file, char * buf, 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_sensor s, char * buffer) 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_sensor s, char * buffer) 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(struct file * file, char * buf, 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(struct file * file, char * buf, 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(struct file * file, char * buf, 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 --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c index 725d3c778efa9..33a2ff7a50cc5 100644 --- a/arch/ppc64/kernel/scanlog.c +++ b/arch/ppc64/kernel/scanlog.c @@ -135,17 +135,24 @@ static ssize_t scanlog_read(struct file *file, char *buf, 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; } -- 2.53.0