Commit ea81e272 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6:
  [S390] cio: allow offline processing for disconnected devices
  [S390] cio: handle ssch() return codes correctly.
  [S390] cio: Correct cleanup on error.
  [S390] CVE-2008-1514: prevent ptrace padding area read/write in 31-bit mode
parents 0b1fc335 b301ea8c
...@@ -42,6 +42,7 @@ struct user_regs_struct32 ...@@ -42,6 +42,7 @@ struct user_regs_struct32
u32 gprs[NUM_GPRS]; u32 gprs[NUM_GPRS];
u32 acrs[NUM_ACRS]; u32 acrs[NUM_ACRS];
u32 orig_gpr2; u32 orig_gpr2;
/* nb: there's a 4-byte hole here */
s390_fp_regs fp_regs; s390_fp_regs fp_regs;
/* /*
* These per registers are in here so that gdb can modify them * These per registers are in here so that gdb can modify them
......
...@@ -170,6 +170,13 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) ...@@ -170,6 +170,13 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr)
*/ */
tmp = (addr_t) task_pt_regs(child)->orig_gpr2; tmp = (addr_t) task_pt_regs(child)->orig_gpr2;
} else if (addr < (addr_t) &dummy->regs.fp_regs) {
/*
* prevent reads of padding hole between
* orig_gpr2 and fp_regs on s390.
*/
tmp = 0;
} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
/* /*
* floating point regs. are stored in the thread structure * floating point regs. are stored in the thread structure
...@@ -270,6 +277,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -270,6 +277,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
*/ */
task_pt_regs(child)->orig_gpr2 = data; task_pt_regs(child)->orig_gpr2 = data;
} else if (addr < (addr_t) &dummy->regs.fp_regs) {
/*
* prevent writes of padding hole between
* orig_gpr2 and fp_regs on s390.
*/
return 0;
} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
/* /*
* floating point regs. are stored in the thread structure * floating point regs. are stored in the thread structure
...@@ -428,6 +442,13 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) ...@@ -428,6 +442,13 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
*/ */
tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4);
} else if (addr < (addr_t) &dummy32->regs.fp_regs) {
/*
* prevent reads of padding hole between
* orig_gpr2 and fp_regs on s390.
*/
tmp = 0;
} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
/* /*
* floating point regs. are stored in the thread structure * floating point regs. are stored in the thread structure
...@@ -514,6 +535,13 @@ static int __poke_user_compat(struct task_struct *child, ...@@ -514,6 +535,13 @@ static int __poke_user_compat(struct task_struct *child,
*/ */
*(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp;
} else if (addr < (addr_t) &dummy32->regs.fp_regs) {
/*
* prevent writess of padding hole between
* orig_gpr2 and fp_regs on s390.
*/
return 0;
} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
/* /*
* floating point regs. are stored in the thread structure * floating point regs. are stored in the thread structure
......
...@@ -423,7 +423,7 @@ int chp_new(struct chp_id chpid) ...@@ -423,7 +423,7 @@ int chp_new(struct chp_id chpid)
ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
if (ret) { if (ret) {
device_unregister(&chp->dev); device_unregister(&chp->dev);
goto out_free; goto out;
} }
mutex_lock(&channel_subsystems[chpid.cssid]->mutex); mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
if (channel_subsystems[chpid.cssid]->cm_enabled) { if (channel_subsystems[chpid.cssid]->cm_enabled) {
...@@ -432,14 +432,15 @@ int chp_new(struct chp_id chpid) ...@@ -432,14 +432,15 @@ int chp_new(struct chp_id chpid)
sysfs_remove_group(&chp->dev.kobj, &chp_attr_group); sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
device_unregister(&chp->dev); device_unregister(&chp->dev);
mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
goto out_free; goto out;
} }
} }
channel_subsystems[chpid.cssid]->chps[chpid.id] = chp; channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
mutex_unlock(&channel_subsystems[chpid.cssid]->mutex); mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
return ret; goto out;
out_free: out_free:
kfree(chp); kfree(chp);
out:
return ret; return ret;
} }
......
...@@ -208,8 +208,10 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ ...@@ -208,8 +208,10 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
case 1: /* status pending */ case 1: /* status pending */
case 2: /* busy */ case 2: /* busy */
return -EBUSY; return -EBUSY;
default: /* device/path not operational */ case 3: /* device/path not operational */
return cio_start_handle_notoper(sch, lpm); return cio_start_handle_notoper(sch, lpm);
default:
return ccode;
} }
} }
......
...@@ -633,6 +633,11 @@ channel_subsystem_release(struct device *dev) ...@@ -633,6 +633,11 @@ channel_subsystem_release(struct device *dev)
css = to_css(dev); css = to_css(dev);
mutex_destroy(&css->mutex); mutex_destroy(&css->mutex);
if (css->pseudo_subchannel) {
/* Implies that it has been generated but never registered. */
css_subchannel_release(&css->pseudo_subchannel->dev);
css->pseudo_subchannel = NULL;
}
kfree(css); kfree(css);
} }
...@@ -785,11 +790,15 @@ init_channel_subsystem (void) ...@@ -785,11 +790,15 @@ init_channel_subsystem (void)
} }
channel_subsystems[i] = css; channel_subsystems[i] = css;
ret = setup_css(i); ret = setup_css(i);
if (ret) if (ret) {
goto out_free; kfree(channel_subsystems[i]);
goto out_unregister;
}
ret = device_register(&css->device); ret = device_register(&css->device);
if (ret) if (ret) {
goto out_free_all; put_device(&css->device);
goto out_unregister;
}
if (css_chsc_characteristics.secm) { if (css_chsc_characteristics.secm) {
ret = device_create_file(&css->device, ret = device_create_file(&css->device,
&dev_attr_cm_enable); &dev_attr_cm_enable);
...@@ -802,7 +811,7 @@ init_channel_subsystem (void) ...@@ -802,7 +811,7 @@ init_channel_subsystem (void)
} }
ret = register_reboot_notifier(&css_reboot_notifier); ret = register_reboot_notifier(&css_reboot_notifier);
if (ret) if (ret)
goto out_pseudo; goto out_unregister;
css_init_done = 1; css_init_done = 1;
/* Enable default isc for I/O subchannels. */ /* Enable default isc for I/O subchannels. */
...@@ -810,18 +819,12 @@ init_channel_subsystem (void) ...@@ -810,18 +819,12 @@ init_channel_subsystem (void)
for_each_subchannel(__init_channel_subsystem, NULL); for_each_subchannel(__init_channel_subsystem, NULL);
return 0; return 0;
out_pseudo:
device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
out_file: out_file:
if (css_chsc_characteristics.secm)
device_remove_file(&channel_subsystems[i]->device, device_remove_file(&channel_subsystems[i]->device,
&dev_attr_cm_enable); &dev_attr_cm_enable);
out_device: out_device:
device_unregister(&channel_subsystems[i]->device); device_unregister(&channel_subsystems[i]->device);
out_free_all:
kfree(channel_subsystems[i]->pseudo_subchannel->lock);
kfree(channel_subsystems[i]->pseudo_subchannel);
out_free:
kfree(channel_subsystems[i]);
out_unregister: out_unregister:
while (i > 0) { while (i > 0) {
struct channel_subsystem *css; struct channel_subsystem *css;
...@@ -829,6 +832,7 @@ out_unregister: ...@@ -829,6 +832,7 @@ out_unregister:
i--; i--;
css = channel_subsystems[i]; css = channel_subsystems[i];
device_unregister(&css->pseudo_subchannel->dev); device_unregister(&css->pseudo_subchannel->dev);
css->pseudo_subchannel = NULL;
if (css_chsc_characteristics.secm) if (css_chsc_characteristics.secm)
device_remove_file(&css->device, device_remove_file(&css->device,
&dev_attr_cm_enable); &dev_attr_cm_enable);
......
...@@ -658,6 +658,13 @@ ccw_device_offline(struct ccw_device *cdev) ...@@ -658,6 +658,13 @@ ccw_device_offline(struct ccw_device *cdev)
{ {
struct subchannel *sch; struct subchannel *sch;
/* Allow ccw_device_offline while disconnected. */
if (cdev->private->state == DEV_STATE_DISCONNECTED ||
cdev->private->state == DEV_STATE_NOT_OPER) {
cdev->private->flags.donotify = 0;
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
return 0;
}
if (ccw_device_is_orphan(cdev)) { if (ccw_device_is_orphan(cdev)) {
ccw_device_done(cdev, DEV_STATE_OFFLINE); ccw_device_done(cdev, DEV_STATE_OFFLINE);
return 0; return 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