static int eeprom_usr_write(const char __user *buf, size_t count, unsigned long addr)
{
int ret = -EFAULT;
+ char *k_wbuf;
eep_log("eep write.\n");
+
if (!buf) {
eep_err("Invalid User buffer.\n");
+ return ret;
} else if (count > 0) {
if (addr + count > eeprom_size) {
eep_err("overflow!!.\n");
+ return ret;
+ }
+
+ k_wbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!k_wbuf) {
+ eep_err("failed to allocate kernel wbuf!\n");
+ return -ENOMEM;
+ }
+
+ if(copy_from_user(k_wbuf, buf, count)) {
+ eep_err("copy from user failed!\n");
goto out_err;
}
- ret = eeprom_write_file(buf, count, addr);
+
+ ret = eeprom_write_file(k_wbuf, count, addr);
if (ret < 0) {
eep_warn("Write failed.\n");
+ goto out_err;
}
} else {
eep_warn("inavalid count.\n");
+ return ret;
}
out_err:
+ kfree(k_wbuf);
return ret;
}
static ssize_t eeprom_usr_read(char __user *buf, size_t count, unsigned long addr)
{
int ret = -EFAULT;
+ char *k_rbuf;
eep_log("eep read.\n");
+
if (!buf) {
eep_err("User buf has no memory allocation.\n");
+ return ret;
} else if (count > 0) {
if (count + addr > eeprom_size) {
eep_err("overflow!!.\n");
- goto out_err;
+ return ret;
}
- ret = eeprom_read_file(buf, count, addr);
+
+ k_rbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!k_rbuf) {
+ eep_err("failed to allocate kernel rbuf!\n");
+ return -ENOMEM;
+ }
+
+ ret = eeprom_read_file(k_rbuf, count, addr);
if (ret < 0) {
eep_warn("read failed.\n");
+ goto out_err;
+ } else {
+ if (copy_to_user(buf, k_rbuf, count)) {
+ eep_err("copy to user failed!\n");
+ goto out_err;
+ }
}
} else {
eep_warn("invalid count.\n");
+ return ret;
}
out_err:
+ kfree(k_rbuf);
return ret;
}
case EEPROM_WRITE_DATA:
case EEPROM_READ_DATA:
{
- struct eeprom_io_pkt *pkt = (struct eeprom_io_pkt *)args;
- if (cmd == EEPROM_WRITE_DATA)
- ret = eeprom_usr_write(pkt->wbuf, pkt->size, pkt->addr);
- else
- ret = eeprom_usr_read(pkt->rbuf, pkt->size, pkt->addr);
- if (ret < 0) {
- eep_warn("failed handle eeprom data: %ld", ret);
+ struct eeprom_io_pkt eemprom_pkt;
+
+ if (copy_from_user(&eemprom_pkt,
+ (struct eeprom_io_pkt *)args,
+ sizeof(struct eeprom_io_pkt))) {
+ eep_warn("eemprom_pkt failed copy_from_user\n");
+ ret = -EFAULT;
+ goto out_unlock;
}
+
+ if (cmd == EEPROM_WRITE_DATA) {
+ if (!access_ok(VERIFY_READ,
+ (const char __user *)eemprom_pkt.wbuf,
+ eemprom_pkt.size)) {
+ eep_err("eemprom_pkt.wbuf access fail!\n");
+ ret = -EFAULT;
+ goto out_unlock;
+ } else {
+ ret = eeprom_usr_write(eemprom_pkt.wbuf,
+ eemprom_pkt.size,
+ eemprom_pkt.addr);
+ if (ret < 0)
+ eep_warn("failed write eeprom data: %ld", ret);
+ }
+ } else {
+ if (!access_ok(VERIFY_WRITE,
+ (const char __user *)eemprom_pkt.rbuf,
+ eemprom_pkt.size)) {
+ eep_err("eemprom_pkt.rbuf access fail!\n");
+ ret = -EFAULT;
+ goto out_unlock;
+ } else {
+ ret = eeprom_usr_read(eemprom_pkt.rbuf,
+ eemprom_pkt.size,
+ eemprom_pkt.addr);
+ if (ret < 0)
+ eep_warn("failed read eeprom data: %ld", ret);
+ }
+ }
+
}
break;
default:
ret = -EFAULT;
break;
}
+
+out_unlock:
mutex_unlock(&eep_mutex);
return ret;
}