]> git.hungrycats.org Git - linux/commitdiff
[PATCH] /proc/ppc64 and /proc/iSeries fixes from Linas Vepstas
authorAndrew Morton <akpm@osdl.org>
Wed, 7 Jan 2004 13:56:50 +0000 (05:56 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Wed, 7 Jan 2004 13:56:50 +0000 (05:56 -0800)
From: Anton Blanchard <anton@samba.org>

Linas Vepstas has audited the ppc64 proc code and found a number of issues.

arch/ppc64/kernel/mf_proc.c
arch/ppc64/kernel/proc_pmc.c
arch/ppc64/kernel/rtas-proc.c
arch/ppc64/kernel/scanlog.c

index a6ec2ddce351e4dc3ac42e267871f7df0fe172d2..dd12477d2c5900a7a4d794986ff177413333f4c0 100644 (file)
@@ -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;                   
index 2b4fec39bec1938b368900bf29156ce8b722adb7..349e4cd39a77cb5e4f88c36be05c12e2701f9441 100644 (file)
@@ -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 */
index b7e133a7518fed0199707d1b4e80a85880ae1e8e..1dcb17b0d31517b32acfef33face3f00d0c93d71 100644 (file)
@@ -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;
 }
index 725d3c778efa903ae11ae30dcc44b7f93e3e18f8..33a2ff7a50cc5e6c10734a34789801a31450f0fc 100644 (file)
@@ -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;
                }