Commit 81d2e766 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] /proc/ppc64 and /proc/iSeries fixes from Linas Vepstas

From: Anton Blanchard <anton@samba.org>

Linas Vepstas has audited the ppc64 proc code and found a number of issues.
parent 1a6100ca
...@@ -220,19 +220,25 @@ int proc_mf_dump_side ...@@ -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) int proc_mf_change_side(struct file *file, const char *buffer, unsigned long count, void *data)
{ {
char stkbuf[10];
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
if ((*buffer != 'A') && if (count > 9) count = 9;
(*buffer != 'B') && if (copy_from_user (stkbuf, buffer, count)) {
(*buffer != 'C') && return -EFAULT;
(*buffer != 'D')) }
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"); printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
return -EINVAL; return -EINVAL;
} }
mf_setSide(*buffer); mf_setSide(*stkbuf);
return count; return count;
} }
...@@ -256,6 +262,7 @@ int proc_mf_dump_src ...@@ -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) int proc_mf_change_src(struct file *file, const char *buffer, unsigned long count, void *data)
{ {
char stkbuf[10];
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
...@@ -265,11 +272,16 @@ int proc_mf_change_src(struct file *file, const char *buffer, unsigned long coun ...@@ -265,11 +272,16 @@ int proc_mf_change_src(struct file *file, const char *buffer, unsigned long coun
return -EINVAL; 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(); mf_clearSrc();
} else { } else {
mf_displaySrc(*(u32 *)buffer); mf_displaySrc(*(u32 *)stkbuf);
} }
return count; return count;
......
...@@ -127,7 +127,7 @@ void proc_ppc64_init(void) ...@@ -127,7 +127,7 @@ void proc_ppc64_init(void)
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
ent->read_proc = (void *)proc_ppc64_pmc_stab_read; 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, ent = create_proc_entry("htab", S_IRUGO | S_IWUSR,
...@@ -136,7 +136,7 @@ void proc_ppc64_init(void) ...@@ -136,7 +136,7 @@ void proc_ppc64_init(void)
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
ent->read_proc = (void *)proc_ppc64_pmc_htab_read; 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) ...@@ -146,7 +146,7 @@ void proc_ppc64_init(void)
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_system_root; ent->data = (void *)proc_ppc64_pmc_system_root;
ent->read_proc = (void *)proc_ppc64_pmc_stab_read; 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, ent = create_proc_entry("htab", S_IRUGO | S_IWUSR,
...@@ -155,7 +155,7 @@ void proc_ppc64_init(void) ...@@ -155,7 +155,7 @@ void proc_ppc64_init(void)
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_system_root; ent->data = (void *)proc_ppc64_pmc_system_root;
ent->read_proc = (void *)proc_ppc64_pmc_htab_read; 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. */ /* Create directories for the hardware counters. */
...@@ -168,7 +168,7 @@ void proc_ppc64_init(void) ...@@ -168,7 +168,7 @@ void proc_ppc64_init(void)
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_cpu_root[i]; ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
ent->read_proc = (void *)proc_ppc64_pmc_hw_read; 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) ...@@ -178,7 +178,7 @@ void proc_ppc64_init(void)
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_system_root; ent->data = (void *)proc_ppc64_pmc_system_root;
ent->read_proc = (void *)proc_ppc64_pmc_hw_read; 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) ...@@ -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 ) 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(); proc_pmc_stop();
else if ( ! strncmp( buffer, "start", 5 ) ) else if ( ! strncmp( stkbuf, "start", 5 ) )
proc_pmc_start(); proc_pmc_start();
else if ( ! strncmp( buffer, "reset", 5 ) ) else if ( ! strncmp( stkbuf, "reset", 5 ) )
proc_pmc_reset(); proc_pmc_reset();
else if ( ! strncmp( buffer, "cpi", 3 ) ) else if ( ! strncmp( stkbuf, "cpi", 3 ) )
proc_pmc_cpi(); proc_pmc_cpi();
else if ( ! strncmp( buffer, "tlb", 3 ) ) else if ( ! strncmp( stkbuf, "tlb", 3 ) )
proc_pmc_tlb(); proc_pmc_tlb();
/* IMPLEMENT ME */ /* IMPLEMENT ME */
......
...@@ -241,12 +241,18 @@ void proc_rtas_init(void) ...@@ -241,12 +241,18 @@ void proc_rtas_init(void)
static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char stkbuf[40]; /* its small, its on stack */
struct rtc_time tm; struct rtc_time tm;
unsigned long nowtime; unsigned long nowtime;
char *dest; char *dest;
int error; 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') { if (*dest != '\0' && *dest != '\n') {
printk("ppc_rtas_poweron_write: Invalid time\n"); printk("ppc_rtas_poweron_write: Invalid time\n");
return count; return count;
...@@ -267,18 +273,23 @@ static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, ...@@ -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, static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char stkbuf[40]; /* its small, its on stack */
int n; int n;
if (power_on_time == 0) 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 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; return 0;
if (n > strlen(buf) - *ppos) if (n > sn - *ppos)
n = strlen(buf) - *ppos; n = sn - *ppos;
if (n > count) if (n > count)
n = count; n = count;
if (copy_to_user (buf, stkbuf + (*ppos), n)) {
return -EFAULT;
}
*ppos += n; *ppos += n;
return n; return n;
} }
...@@ -291,11 +302,16 @@ static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, ...@@ -291,11 +302,16 @@ static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf,
{ {
unsigned long hex; 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 */ /* Lets see if the user passed hexdigits */
hex = simple_strtoul(buf, NULL, 10); hex = simple_strtoul(progress_led, NULL, 10);
ppc_md.progress ((char *)buf, hex); ppc_md.progress ((char *)progress_led, hex);
return count; return count;
/* clear the line */ /* ppc_md.progress(" ", 0xffff);*/ /* clear the line */ /* ppc_md.progress(" ", 0xffff);*/
...@@ -305,14 +321,30 @@ static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, ...@@ -305,14 +321,30 @@ static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
int n = 0; int n = 0;
if (progress_led != NULL)
n = sprintf (buf, "%s\n", progress_led); if (progress_led == NULL) return 0;
if (*ppos >= strlen(buf))
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; return 0;
if (n > strlen(buf) - *ppos) }
n = strlen(buf) - *ppos; if (n > sn - *ppos)
n = sn - *ppos;
if (n > count) if (n > count)
n = count; n = count;
if (copy_to_user (buf, tmpbuf + (*ppos), n)) {
kfree (tmpbuf);
return -EFAULT;
}
kfree (tmpbuf);
*ppos += n; *ppos += n;
return n; return n;
} }
...@@ -323,12 +355,18 @@ static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, ...@@ -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, static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char stkbuf[40]; /* its small, its on stack */
struct rtc_time tm; struct rtc_time tm;
unsigned long nowtime; unsigned long nowtime;
char *dest; char *dest;
int error; 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') { if (*dest != '\0' && *dest != '\n') {
printk("ppc_rtas_clock_write: Invalid time\n"); printk("ppc_rtas_clock_write: Invalid time\n");
return count; return count;
...@@ -356,21 +394,27 @@ static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, ...@@ -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]; year = ret[0]; mon = ret[1]; day = ret[2];
hour = ret[3]; min = ret[4]; sec = ret[5]; hour = ret[3]; min = ret[4]; sec = ret[5];
char stkbuf[40]; /* its small, its on stack */
if (error != 0){ if (error != 0){
printk(KERN_WARNING "error: reading the clock returned: %s\n", printk(KERN_WARNING "error: reading the clock returned: %s\n",
ppc_rtas_process_error(error)); ppc_rtas_process_error(error));
n = sprintf (buf, "0"); n = snprintf (stkbuf, 40, "0");
} else { } 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); kfree(ret);
if (*ppos >= strlen(buf)) int sn = strlen (stkbuf) +1;
if (*ppos >= sn)
return 0; return 0;
if (n > strlen(buf) - *ppos) if (n > sn - *ppos)
n = strlen(buf) - *ppos; n = sn - *ppos;
if (n > count) if (n > count)
n = count; n = count;
if (copy_to_user (buf, stkbuf + (*ppos), n)) {
return -EFAULT;
}
*ppos += n; *ppos += n;
return n; return n;
} }
...@@ -764,7 +808,7 @@ int get_location_code(struct individual_sensor s, char * buffer) ...@@ -764,7 +808,7 @@ int get_location_code(struct individual_sensor s, char * buffer)
n += check_location_string(ret, buffer + n); n += check_location_string(ret, buffer + n);
n += sprintf ( buffer+n, " "); n += sprintf ( buffer+n, " ");
/* see how many characters we have printed */ /* see how many characters we have printed */
sprintf ( t, "%s ", ret); snprintf ( t, 50, "%s ", ret);
pos += strlen(t); pos += strlen(t);
if (pos >= llen) pos=0; if (pos >= llen) pos=0;
...@@ -777,10 +821,17 @@ int get_location_code(struct individual_sensor s, char * buffer) ...@@ -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, static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char stkbuf[40]; /* its small, its on stack */
unsigned long freq; unsigned long freq;
char *dest; char *dest;
int error; 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') { if (*dest != '\0' && *dest != '\n') {
printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n"); printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
return count; return count;
...@@ -799,14 +850,19 @@ static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, ...@@ -799,14 +850,19 @@ static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
int n; 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; return 0;
if (n > strlen(buf) - *ppos) if (n > sn - *ppos)
n = strlen(buf) - *ppos; n = sn - *ppos;
if (n > count) if (n > count)
n = count; n = count;
if (copy_to_user (buf, stkbuf + (*ppos), n)) {
return -EFAULT;
}
*ppos += n; *ppos += n;
return n; return n;
} }
...@@ -816,10 +872,17 @@ static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, ...@@ -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, static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char stkbuf[40]; /* its small, its on stack */
unsigned long volume; unsigned long volume;
char *dest; char *dest;
int error; 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') { if (*dest != '\0' && *dest != '\n') {
printk("ppc_rtas_tone_volume_write: Invalid tone volume\n"); printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
return count; return count;
...@@ -840,14 +903,19 @@ static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, ...@@ -840,14 +903,19 @@ static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
int n; 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; return 0;
if (n > strlen(buf) - *ppos) if (n > sn - *ppos)
n = strlen(buf) - *ppos; n = sn - *ppos;
if (n > count) if (n > count)
n = count; n = count;
if (copy_to_user (buf, stkbuf + (*ppos), n)) {
return -EFAULT;
}
*ppos += n; *ppos += n;
return n; return n;
} }
...@@ -135,17 +135,24 @@ static ssize_t scanlog_read(struct file *file, char *buf, ...@@ -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, static ssize_t scanlog_write(struct file * file, const char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char stkbuf[20];
unsigned long status; unsigned long status;
if (count > 19) count = 19;
if (copy_from_user (stkbuf, buf, count)) {
return -EFAULT;
}
stkbuf[count] = 0;
if (buf) { if (buf) {
if (strncmp(buf, "reset", 5) == 0) { if (strncmp(stkbuf, "reset", 5) == 0) {
DEBUG("reset scanlog\n"); DEBUG("reset scanlog\n");
status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0); status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0);
DEBUG("rtas returns %ld\n", status); 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"); printk(KERN_ERR "scanlog: debug on\n");
scanlog_debug = 1; scanlog_debug = 1;
} else if (strncmp(buf, "debugoff", 8) == 0) { } else if (strncmp(stkbuf, "debugoff", 8) == 0) {
printk(KERN_ERR "scanlog: debug off\n"); printk(KERN_ERR "scanlog: debug off\n");
scanlog_debug = 0; scanlog_debug = 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment