Commit cfc0e9b7 authored by Paul Mackerras's avatar Paul Mackerras

Merge samba.org:/home/paulus/kernel/linux-2.5

into samba.org:/home/paulus/kernel/for-linus-ppc
parents 3f379e03 ff7b0319
...@@ -170,7 +170,6 @@ static void __init geode_configure(void) ...@@ -170,7 +170,6 @@ static void __init geode_configure(void)
{ {
unsigned long flags; unsigned long flags;
u8 ccr3, ccr4; u8 ccr3, ccr4;
unsigned long cr0;
local_irq_save(flags); local_irq_save(flags);
ccr3 = getCx86(CX86_CCR3); ccr3 = getCx86(CX86_CCR3);
......
...@@ -1749,10 +1749,11 @@ void __init setup_IO_APIC(void) ...@@ -1749,10 +1749,11 @@ void __init setup_IO_APIC(void)
* APIC bugs then we can allow the modify fast path * APIC bugs then we can allow the modify fast path
*/ */
static void __init io_apic_bug_finalize(void) static int __init io_apic_bug_finalize(void)
{ {
if(sis_apic_bug == -1) if(sis_apic_bug == -1)
sis_apic_bug = 0; sis_apic_bug = 0;
return 0;
} }
late_initcall(io_apic_bug_finalize); late_initcall(io_apic_bug_finalize);
......
#undef DEBUG #undef DEBUG
#ifdef DEBUG
# define DBG(x...) printk(x)
#else
# define DBG(x...)
#endif
extern struct list_head global_device_list;
extern spinlock_t device_lock;
extern struct semaphore device_sem; extern struct semaphore device_sem;
extern int bus_add_device(struct device * dev); extern int bus_add_device(struct device * dev);
...@@ -22,8 +14,8 @@ extern void devclass_remove_device(struct device *); ...@@ -22,8 +14,8 @@ extern void devclass_remove_device(struct device *);
extern int devclass_add_driver(struct device_driver *); extern int devclass_add_driver(struct device_driver *);
extern void devclass_remove_driver(struct device_driver *); extern void devclass_remove_driver(struct device_driver *);
extern int interface_add(struct device_class *, struct device *); extern int interface_add_dev(struct device *);
extern void interface_remove(struct device_class *, struct device *); extern void interface_remove_dev(struct device *);
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
......
...@@ -132,6 +132,91 @@ struct subsystem bus_subsys = { ...@@ -132,6 +132,91 @@ struct subsystem bus_subsys = {
}; };
/**
* bus_for_each_dev - device iterator.
* @bus: bus type.
* @start: device to start iterating from.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @bus's list of devices, and call @fn for each,
* passing it @data. If @start is not NULL, we use that device to
* begin iterating from.
*
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*
* NOTE: The device that returns a non-zero value is not retained
* in any way, nor is its refcount incremented. If the caller needs
* to retain this data, it should do, and increment the reference
* count in the supplied callback.
*/
int bus_for_each_dev(struct bus_type * bus, struct device * start,
void * data, int (*fn)(struct device *, void *))
{
struct list_head * head, * entry;
int error = 0;
if (!(bus = get_bus(bus)))
return -EINVAL;
head = start ? &start->bus_list : &bus->devices;
down_read(&bus->subsys.rwsem);
list_for_each(entry,head) {
struct device * dev = get_device(to_dev(entry));
error = fn(dev,data);
put_device(dev);
if (error)
break;
}
up_read(&bus->subsys.rwsem);
return error;
}
/**
* bus_for_each_drv - driver iterator
* @bus: bus we're dealing with.
* @start: driver to start iterating on.
* @data: data to pass to the callback.
* @fn: function to call for each driver.
*
* This is nearly identical to the device iterator above.
* We iterate over each driver that belongs to @bus, and call
* @fn for each. If @fn returns anything but 0, we break out
* and return it. If @start is not NULL, we use it as the head
* of the list.
*
* NOTE: we don't return the driver that returns a non-zero
* value, nor do we leave the reference count incremented for that
* driver. If the caller needs to know that info, it must set it
* in the callback. It must also be sure to increment the refcount
* so it doesn't disappear before returning to the caller.
*/
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *))
{
struct list_head * head, * entry;
int error = 0;
if(!(bus = get_bus(bus)))
return -EINVAL;
head = start ? &start->bus_list : &bus->drivers;
down_read(&bus->subsys.rwsem);
list_for_each(entry,head) {
struct device_driver * drv = get_driver(to_drv(entry));
error = fn(drv,data);
put_driver(drv);
if(error)
break;
}
up_read(&bus->subsys.rwsem);
return error;
}
/** /**
* attach - add device to driver. * attach - add device to driver.
* @dev: device. * @dev: device.
...@@ -190,7 +275,7 @@ static int bus_match(struct device * dev, struct device_driver * drv) ...@@ -190,7 +275,7 @@ static int bus_match(struct device * dev, struct device_driver * drv)
*/ */
static int device_attach(struct device * dev) static int device_attach(struct device * dev)
{ {
struct bus_type * bus = dev->bus; struct bus_type * bus = dev->bus;
struct list_head * entry; struct list_head * entry;
int error = 0; int error = 0;
...@@ -455,6 +540,9 @@ static int __init bus_subsys_init(void) ...@@ -455,6 +540,9 @@ static int __init bus_subsys_init(void)
core_initcall(bus_subsys_init); core_initcall(bus_subsys_init);
EXPORT_SYMBOL(bus_for_each_dev);
EXPORT_SYMBOL(bus_for_each_drv);
EXPORT_SYMBOL(bus_add_device); EXPORT_SYMBOL(bus_add_device);
EXPORT_SYMBOL(bus_remove_device); EXPORT_SYMBOL(bus_remove_device);
EXPORT_SYMBOL(bus_register); EXPORT_SYMBOL(bus_register);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* class.c - basic device class management * class.c - basic device class management
*/ */
#undef DEBUG #define DEBUG
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -98,7 +98,6 @@ void devclass_remove_file(struct device_class * cls, struct devclass_attribute * ...@@ -98,7 +98,6 @@ void devclass_remove_file(struct device_class * cls, struct devclass_attribute *
} }
int devclass_add_driver(struct device_driver * drv) int devclass_add_driver(struct device_driver * drv)
{ {
struct device_class * cls = get_devclass(drv->devclass); struct device_class * cls = get_devclass(drv->devclass);
...@@ -172,9 +171,11 @@ int devclass_add_device(struct device * dev) ...@@ -172,9 +171,11 @@ int devclass_add_device(struct device * dev)
error = cls->add_device(dev); error = cls->add_device(dev);
if (!error) { if (!error) {
enum_device(cls,dev); enum_device(cls,dev);
interface_add(cls,dev); interface_add_dev(dev);
} }
list_add_tail(&dev->class_list,&cls->devices);
/* notify userspace (call /sbin/hotplug) */ /* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "add"); class_hotplug (dev, "add");
...@@ -196,9 +197,11 @@ void devclass_remove_device(struct device * dev) ...@@ -196,9 +197,11 @@ void devclass_remove_device(struct device * dev)
down_write(&cls->subsys.rwsem); down_write(&cls->subsys.rwsem);
pr_debug("device class %s: removing device %s\n", pr_debug("device class %s: removing device %s\n",
cls->name,dev->name); cls->name,dev->name);
interface_remove(cls,dev); interface_remove_dev(dev);
unenum_device(cls,dev); unenum_device(cls,dev);
list_del(&dev->class_list);
/* notify userspace (call /sbin/hotplug) */ /* notify userspace (call /sbin/hotplug) */
class_hotplug (dev, "remove"); class_hotplug (dev, "remove");
...@@ -224,6 +227,7 @@ void put_devclass(struct device_class * cls) ...@@ -224,6 +227,7 @@ void put_devclass(struct device_class * cls)
int devclass_register(struct device_class * cls) int devclass_register(struct device_class * cls)
{ {
INIT_LIST_HEAD(&cls->drivers); INIT_LIST_HEAD(&cls->drivers);
INIT_LIST_HEAD(&cls->devices);
pr_debug("device class '%s': registering\n",cls->name); pr_debug("device class '%s': registering\n",cls->name);
strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN); strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN);
......
...@@ -18,15 +18,11 @@ ...@@ -18,15 +18,11 @@
#include "base.h" #include "base.h"
LIST_HEAD(global_device_list);
int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL;
DECLARE_MUTEX(device_sem); DECLARE_MUTEX(device_sem);
spinlock_t device_lock = SPIN_LOCK_UNLOCKED;
#define to_dev(obj) container_of(obj,struct device,kobj) #define to_dev(obj) container_of(obj,struct device,kobj)
...@@ -146,11 +142,10 @@ void device_initialize(struct device *dev) ...@@ -146,11 +142,10 @@ void device_initialize(struct device *dev)
kobject_init(&dev->kobj); kobject_init(&dev->kobj);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list);
INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->driver_list);
INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->bus_list);
INIT_LIST_HEAD(&dev->class_list);
INIT_LIST_HEAD(&dev->intf_list); INIT_LIST_HEAD(&dev->intf_list);
// spin_lock_init(&dev->lock);
} }
/** /**
...@@ -188,13 +183,11 @@ int device_add(struct device *dev) ...@@ -188,13 +183,11 @@ int device_add(struct device *dev)
goto register_done; goto register_done;
/* now take care of our own registration */ /* now take care of our own registration */
down(&device_sem);
if (parent) { if (parent) {
list_add_tail(&dev->g_list,&dev->parent->g_list); down(&device_sem);
list_add_tail(&dev->node,&parent->children); list_add_tail(&dev->node,&parent->children);
} else up(&device_sem);
list_add_tail(&dev->g_list,&global_device_list); }
up(&device_sem);
bus_add_device(dev); bus_add_device(dev);
...@@ -276,10 +269,11 @@ void device_del(struct device * dev) ...@@ -276,10 +269,11 @@ void device_del(struct device * dev)
{ {
struct device * parent = dev->parent; struct device * parent = dev->parent;
down(&device_sem); if (parent) {
list_del_init(&dev->node); down(&device_sem);
list_del_init(&dev->g_list); list_del_init(&dev->node);
up(&device_sem); up(&device_sem);
}
/* Notify the platform of the removal, in case they /* Notify the platform of the removal, in case they
* need to do anything... * need to do anything...
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* intf.c - class-specific interface management * intf.c - class-specific interface management
*/ */
#undef DEBUG #define DEBUG
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -10,98 +10,267 @@ ...@@ -10,98 +10,267 @@
#include "base.h" #include "base.h"
#define to_intf(node) container_of(node,struct device_interface,kobj.entry) #define to_intf(node) container_of(node,struct device_interface,subsys.kobj.entry)
#define to_data(e) container_of(e,struct intf_data,kobj.entry)
#define intf_from_data(d) container_of(d->kobj.subsys,struct device_interface, subsys);
/** /**
* intf_dev_link - symlink from interface's directory to device's directory * intf_dev_link - create sysfs symlink for interface.
* @data: interface data descriptor.
* *
* Create a symlink 'phys' in the interface's directory to
*/ */
static int intf_dev_link(struct intf_data * data) static int intf_dev_link(struct intf_data * data)
{ {
char linkname[16]; char name[16];
snprintf(name,16,"%d",data->intf_num);
snprintf(linkname,16,"%u",data->intf_num); return sysfs_create_link(&data->intf->subsys.kobj,&data->dev->kobj,name);
return sysfs_create_link(&data->intf->kobj,&data->dev->kobj,linkname);
} }
/**
* intf_dev_unlink - remove symlink for interface.
* @intf: interface data descriptor.
*
*/
static void intf_dev_unlink(struct intf_data * data) static void intf_dev_unlink(struct intf_data * data)
{ {
char linkname[16]; char name[16];
snprintf(linkname,16,"%u",data->intf_num); snprintf(name,16,"%d",data->intf_num);
sysfs_remove_link(&data->intf->kobj,linkname); sysfs_remove_link(&data->intf->subsys.kobj,name);
}
/**
* interface_add_data - attach data descriptor
* @data: interface data descriptor.
*
* This attaches the per-instance interface object to the
* interface (by registering its kobject) and the device
* itself (by inserting it into the device's list).
*
* Note that there is no explicit protection done in this
* function. This should be called from the interface's
* add_device() method, which is called under the protection
* of the class's rwsem.
*/
int interface_add_data(struct intf_data * data)
{
struct device_interface * intf = intf_from_data(data);
data->intf_num = data->intf->devnum++;
data->kobj.subsys = &intf->subsys;
kobject_register(&data->kobj);
list_add_tail(&data->dev_entry,&data->dev->intf_list);
intf_dev_link(data);
return 0;
}
/**
* interface_remove_data - detach data descriptor.
* @data: interface data descriptor.
*
* This detaches the per-instance data descriptor by removing
* it from the device's list and unregistering the kobject from
* the subsystem.
*/
void interface_remove_data(struct intf_data * data)
{
intf_dev_unlink(data);
list_del_init(&data->dev_entry);
kobject_unregister(&data->kobj);
} }
/**
* add - attach device to interface
* @intf: interface.
* @dev: device.
*
* This is just a simple helper. Check the interface's interface
* helper and call it. This is called when adding an interface
* the class's devices, or a device to the class's interfaces.
*/
static int add(struct device_interface * intf, struct device * dev)
{
int error = 0;
if (intf->add_device)
error = intf->add_device(dev);
pr_debug(" -> %s (%d)\n",dev->bus_id,error);
return error;
}
/**
* del - detach device from interface.
* @data: interface data descriptor.
*
* Another simple helper. Remove the data descriptor from
* the device and the interface, then call the interface's
* remove_device() method.
*/
static void del(struct intf_data * data)
{
struct device_interface * intf = intf_from_data(data);
pr_debug(" -> %s ",data->intf->name);
interface_remove_data(data);
if (intf->remove_device)
intf->remove_device(data);
}
#define to_dev(entry) container_of(entry,struct device,class_list)
/**
* add_intf - add class's devices to interface.
* @intf: interface.
*
* Loop over the devices registered with the class, and call
* the interface's add_device() method for each.
*
* On an error, we won't break, but we will print debugging info.
*/
static void add_intf(struct device_interface * intf)
{
struct device_class * cls = intf->devclass;
struct list_head * entry;
down_write(&cls->subsys.rwsem);
list_for_each(entry,&cls->devices)
add(intf,to_dev(entry));
up_write(&cls->subsys.rwsem);
}
/**
* interface_register - register an interface with a device class.
* @intf: interface.
*
* An interface may be loaded after drivers and devices have been
* added to the class. So, we must add each device already known to
* the class to the interface as its registered.
*/
int interface_register(struct device_interface * intf) int interface_register(struct device_interface * intf)
{ {
struct device_class * cls = get_devclass(intf->devclass); struct device_class * cls = get_devclass(intf->devclass);
int error = 0;
if (cls) { if (cls) {
pr_debug("register interface '%s' with class '%s'\n", pr_debug("register interface '%s' with class '%s'\n",
intf->name,cls->name); intf->name,cls->name);
strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN);
intf->kobj.subsys = &cls->subsys; strncpy(intf->subsys.kobj.name,intf->name,KOBJ_NAME_LEN);
kobject_register(&intf->kobj); intf->subsys.kobj.subsys = &cls->subsys;
} else subsystem_register(&intf->subsys);
error = -EINVAL; add_intf(intf);
return error; }
return 0;
} }
/**
* del_intf - remove devices from interface.
* @intf: interface being unloaded.
*
* This loops over the devices registered with a class and
* calls the interface's remove_device() method for each.
* This is called when an interface is being unregistered.
*/
static void del_intf(struct device_interface * intf)
{
struct list_head * entry;
down_write(&intf->devclass->subsys.rwsem);
list_for_each(entry,&intf->subsys.list) {
struct intf_data * data = to_data(entry);
del(data);
}
up_write(&intf->devclass->subsys.rwsem);
}
/**
* interface_unregister - remove interface from class.
* @intf: interface.
*
* This is called when an interface in unloaded, giving it a
* chance to remove itself from devicse that have been added to
* it.
*/
void interface_unregister(struct device_interface * intf) void interface_unregister(struct device_interface * intf)
{ {
pr_debug("unregistering interface '%s' from class '%s'\n", struct device_class * cls = intf->devclass;
intf->name,intf->devclass->name); if (cls) {
kobject_unregister(&intf->kobj); pr_debug("unregistering interface '%s' from class '%s'\n",
intf->name,cls->name);
del_intf(intf);
subsystem_unregister(&intf->subsys);
put_devclass(cls);
}
} }
int interface_add(struct device_class * cls, struct device * dev)
/**
* interface_add_dev - add device to interfaces.
* @dev: device.
*
* This is a helper for the class driver core. When a
* device is being added to a class, this is called to add
* the device to all the interfaces in the class.
*
* The operation is simple enough: loop over the interfaces
* and call add() [above] for each. The class rwsem is assumed
* to be held.
*/
int interface_add_dev(struct device * dev)
{ {
struct device_class * cls = dev->driver->devclass;
struct list_head * node; struct list_head * node;
int error = 0;
pr_debug("adding '%s' to %s class interfaces\n",dev->name,cls->name); pr_debug("interfaces: adding device %s\n",dev->name);
list_for_each(node,&cls->subsys.list) { list_for_each(node,&cls->subsys.list) {
struct device_interface * intf = to_intf(node); struct device_interface * intf = to_intf(node);
if (intf->add_device) { add(intf,dev);
error = intf->add_device(dev);
if (error)
pr_debug("%s:%s: adding '%s' failed: %d\n",
cls->name,intf->name,dev->name,error);
}
} }
return 0; return 0;
} }
void interface_remove(struct device_class * cls, struct device * dev)
{
struct list_head * node;
struct list_head * next;
pr_debug("remove '%s' from %s class interfaces: ",dev->name,cls->name); /**
* interface_remove_dev - remove device from interfaces.
* @dev: device.
*
* This is another helper for the class driver core, and called
* when the device is being removed from the class.
*
* We iterate over the list of interface data descriptors attached
* to the device, and call del() [above] for each. Again, the
* class's rwsem is assumed to be held during this.
*/
list_for_each_safe(node,next,&dev->intf_list) { void interface_remove_dev(struct device * dev)
struct intf_data * intf_data = container_of(node,struct intf_data,node); {
list_del_init(&intf_data->node); struct list_head * entry, * next;
intf_dev_unlink(intf_data); pr_debug("interfaces: removing device %s\n",dev->name);
pr_debug("%s ",intf_data->intf->name);
if (intf_data->intf->remove_device)
intf_data->intf->remove_device(intf_data);
}
pr_debug("\n");
}
int interface_add_data(struct intf_data * data) list_for_each_safe(entry,next,&dev->intf_list) {
{ struct intf_data * intf_data = to_data(entry);
down_write(&data->intf->devclass->subsys.rwsem); del(intf_data);
list_add_tail(&data->node,&data->dev->intf_list); }
data->intf_num = data->intf->devnum++;
intf_dev_link(data);
up_write(&data->intf->devclass->subsys.rwsem);
return 0;
} }
EXPORT_SYMBOL(interface_register); EXPORT_SYMBOL(interface_register);
......
...@@ -93,7 +93,7 @@ int __init register_node(struct node *node, int num, struct node *parent) ...@@ -93,7 +93,7 @@ int __init register_node(struct node *node, int num, struct node *parent)
static int __init register_node_type(void) static int __init register_node_type(void)
{ {
driver_register(&node_driver); devclass_register(&node_devclass);
return devclass_register(&node_devclass); return driver_register(&node_driver);
} }
postcore_initcall(register_node_type); postcore_initcall(register_node_type);
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include "base.h" #include "base.h"
#define to_dev(node) container_of(node,struct device,g_list) #define to_dev(node) container_of(node,struct device,kobj.entry)
extern struct subsystem device_subsys;
/** /**
* device_suspend - suspend/remove all devices on the device ree * device_suspend - suspend/remove all devices on the device ree
...@@ -35,8 +37,8 @@ int device_suspend(u32 state, u32 level) ...@@ -35,8 +37,8 @@ int device_suspend(u32 state, u32 level)
printk(KERN_EMERG "Suspending devices\n"); printk(KERN_EMERG "Suspending devices\n");
down(&device_sem); down_write(&device_subsys.rwsem);
list_for_each(node,&global_device_list) { list_for_each(node,&device_subsys.list) {
struct device * dev = to_dev(node); struct device * dev = to_dev(node);
if (dev->driver && dev->driver->suspend) { if (dev->driver && dev->driver->suspend) {
pr_debug("suspending device %s\n",dev->name); pr_debug("suspending device %s\n",dev->name);
...@@ -45,7 +47,7 @@ int device_suspend(u32 state, u32 level) ...@@ -45,7 +47,7 @@ int device_suspend(u32 state, u32 level)
printk(KERN_ERR "%s: suspend returned %d\n",dev->name,error); printk(KERN_ERR "%s: suspend returned %d\n",dev->name,error);
} }
} }
up(&device_sem); up_write(&device_subsys.rwsem);
return error; return error;
} }
...@@ -61,15 +63,15 @@ void device_resume(u32 level) ...@@ -61,15 +63,15 @@ void device_resume(u32 level)
{ {
struct list_head * node; struct list_head * node;
down(&device_sem); down_write(&device_subsys.rwsem);
list_for_each_prev(node,&global_device_list) { list_for_each_prev(node,&device_subsys.list) {
struct device * dev = to_dev(node); struct device * dev = to_dev(node);
if (dev->driver && dev->driver->resume) { if (dev->driver && dev->driver->resume) {
pr_debug("resuming device %s\n",dev->name); pr_debug("resuming device %s\n",dev->name);
dev->driver->resume(dev,level); dev->driver->resume(dev,level);
} }
} }
up(&device_sem); up_write(&device_subsys.rwsem);
printk(KERN_EMERG "Devices Resumed\n"); printk(KERN_EMERG "Devices Resumed\n");
} }
...@@ -83,15 +85,15 @@ void device_shutdown(void) ...@@ -83,15 +85,15 @@ void device_shutdown(void)
printk(KERN_EMERG "Shutting down devices\n"); printk(KERN_EMERG "Shutting down devices\n");
down(&device_sem); down_write(&device_subsys.rwsem);
list_for_each(entry,&global_device_list) { list_for_each(entry,&device_subsys.list) {
struct device * dev = to_dev(entry); struct device * dev = to_dev(entry);
if (dev->driver && dev->driver->shutdown) { if (dev->driver && dev->driver->shutdown) {
pr_debug("shutting down %s\n",dev->name); pr_debug("shutting down %s\n",dev->name);
dev->driver->shutdown(dev); dev->driver->shutdown(dev);
} }
} }
up(&device_sem); up_write(&device_subsys.rwsem);
} }
EXPORT_SYMBOL(device_suspend); EXPORT_SYMBOL(device_suspend);
......
...@@ -3977,18 +3977,6 @@ static void __init register_devfs_entries (int drive) ...@@ -3977,18 +3977,6 @@ static void __init register_devfs_entries (int drive)
} }
} }
static void unregister_devfs_entries (int drive)
{
int i;
if (UDP->cmos < NUMBER(default_drive_params)) {
i = 0;
do {
devfs_remove("floppy/%d%s", drive, table[table_sup[UDP->cmos][i]]);
} while (table_sup[UDP->cmos][i++]);
}
}
/* /*
* Floppy Driver initialization * Floppy Driver initialization
* ============================= * =============================
...@@ -4543,6 +4531,18 @@ static void floppy_release_irq_and_dma(void) ...@@ -4543,6 +4531,18 @@ static void floppy_release_irq_and_dma(void)
char *floppy; char *floppy;
static void unregister_devfs_entries (int drive)
{
int i;
if (UDP->cmos < NUMBER(default_drive_params)) {
i = 0;
do {
devfs_remove("floppy/%d%s", drive, table[table_sup[UDP->cmos][i]]);
} while (table_sup[UDP->cmos][i++]);
}
}
static void __init parse_floppy_cfg_string(char *cfg) static void __init parse_floppy_cfg_string(char *cfg)
{ {
char *ptr; char *ptr;
......
...@@ -410,11 +410,11 @@ struct gendisk *alloc_disk(int minors) ...@@ -410,11 +410,11 @@ struct gendisk *alloc_disk(int minors)
disk->minors = minors; disk->minors = minors;
while (minors >>= 1) while (minors >>= 1)
disk->minor_shift++; disk->minor_shift++;
kobject_init(&disk->kobj);
disk->kobj.subsys = &block_subsys; disk->kobj.subsys = &block_subsys;
kobject_init(&disk->kobj);
INIT_LIST_HEAD(&disk->full_list); INIT_LIST_HEAD(&disk->full_list);
rand_initialize_disk(disk);
} }
rand_initialize_disk(disk);
return disk; return disk;
} }
......
...@@ -448,6 +448,7 @@ struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp) ...@@ -448,6 +448,7 @@ struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
/* now put in global tree */ /* now put in global tree */
strcpy(dev->dev.bus_id,dev->slot_name); strcpy(dev->dev.bus_id,dev->slot_name);
dev->dev.dma_mask = &dev->dma_mask;
device_register(&dev->dev); device_register(&dev->dev);
return dev; return dev;
......
...@@ -80,6 +80,7 @@ ...@@ -80,6 +80,7 @@
/* host controllers we manage */ /* host controllers we manage */
LIST_HEAD (usb_bus_list); LIST_HEAD (usb_bus_list);
EXPORT_SYMBOL (usb_bus_list);
/* used when allocating bus numbers */ /* used when allocating bus numbers */
#define USB_MAXBUS 64 #define USB_MAXBUS 64
...@@ -90,6 +91,7 @@ static struct usb_busmap busmap; ...@@ -90,6 +91,7 @@ static struct usb_busmap busmap;
/* used when updating list of hcds */ /* used when updating list of hcds */
DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */
EXPORT_SYMBOL (usb_bus_list_lock);
/* used when updating hcd data */ /* used when updating hcd data */
static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/pagevec.h> #include <linux/pagevec.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/dnotify.h> #include <linux/dnotify.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -377,7 +377,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) ...@@ -377,7 +377,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
p->start_sect = start; p->start_sect = start;
p->nr_sects = len; p->nr_sects = len;
devfs_register_partition(disk, part); devfs_register_partition(disk, part);
kobject_init(&p->kobj);
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
p->kobj.parent = &disk->kobj; p->kobj.parent = &disk->kobj;
p->kobj.subsys = &part_subsys; p->kobj.subsys = &part_subsys;
...@@ -406,7 +405,7 @@ void register_disk(struct gendisk *disk) ...@@ -406,7 +405,7 @@ void register_disk(struct gendisk *disk)
s = strchr(disk->kobj.name, '/'); s = strchr(disk->kobj.name, '/');
if (s) if (s)
*s = '!'; *s = '!';
kobject_register(&disk->kobj); kobject_add(&disk->kobj);
disk_sysfs_symlinks(disk); disk_sysfs_symlinks(disk);
if (disk->flags & GENHD_FL_CD) if (disk->flags & GENHD_FL_CD)
...@@ -529,8 +528,7 @@ void del_gendisk(struct gendisk *disk) ...@@ -529,8 +528,7 @@ void del_gendisk(struct gendisk *disk)
sysfs_remove_link(&disk->driverfs_dev->kobj, "block"); sysfs_remove_link(&disk->driverfs_dev->kobj, "block");
put_device(disk->driverfs_dev); put_device(disk->driverfs_dev);
} }
kobject_get(&disk->kobj); /* kobject model is fucked in head */ kobject_del(&disk->kobj);
kobject_unregister(&disk->kobj);
} }
struct dev_name { struct dev_name {
......
...@@ -96,9 +96,10 @@ static int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t ...@@ -96,9 +96,10 @@ static int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
if (!dentry->d_inode) { if (!dentry->d_inode) {
inode = sysfs_get_inode(dir->i_sb, mode, dev); inode = sysfs_get_inode(dir->i_sb, mode, dev);
if (inode) if (inode) {
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
else dget(dentry);
} else
error = -ENOSPC; error = -ENOSPC;
} else } else
error = -EEXIST; error = -EEXIST;
...@@ -135,14 +136,52 @@ static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * ...@@ -135,14 +136,52 @@ static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char *
if (inode) { if (inode) {
int l = strlen(symname)+1; int l = strlen(symname)+1;
error = page_symlink(inode, symname, l); error = page_symlink(inode, symname, l);
if (!error) if (!error) {
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
else dget(dentry);
} else
iput(inode); iput(inode);
} }
return error; return error;
} }
#define to_subsys(k) container_of(k,struct subsystem,kobj)
#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
/**
* Subsystem file operations.
* These operations allow subsystems to have files that can be
* read/written.
*/
ssize_t subsys_attr_show(struct kobject * kobj, struct attribute * attr,
char * page, size_t count, loff_t off)
{
struct subsystem * s = to_subsys(kobj);
struct subsys_attribute * sattr = to_sattr(attr);
ssize_t ret = 0;
if (sattr->show)
ret = sattr->show(s,page,count,off);
return ret;
}
ssize_t subsys_attr_store(struct kobject * kobj, struct attribute * attr,
const char * page, size_t count, loff_t off)
{
struct subsystem * s = to_subsys(kobj);
struct subsys_attribute * sattr = to_sattr(attr);
ssize_t ret = 0;
if (sattr->store)
ret = sattr->store(s,page,count,off);
return ret;
}
static struct sysfs_ops subsys_sysfs_ops = {
.show = subsys_attr_show,
.store = subsys_attr_store,
};
/** /**
* sysfs_read_file - read an attribute. * sysfs_read_file - read an attribute.
* @file: file pointer. * @file: file pointer.
...@@ -263,9 +302,14 @@ static int check_perm(struct inode * inode, struct file * file) ...@@ -263,9 +302,14 @@ static int check_perm(struct inode * inode, struct file * file)
if (!kobj || !attr) if (!kobj || !attr)
goto Einval; goto Einval;
/* if the kobject has no subsystem, then it is a subsystem itself,
* so give it the subsys_sysfs_ops.
*/
if (kobj->subsys) if (kobj->subsys)
ops = kobj->subsys->sysfs_ops; ops = kobj->subsys->sysfs_ops;
else
ops = &subsys_sysfs_ops;
/* No sysfs operations, either from having no subsystem, /* No sysfs operations, either from having no subsystem,
* or the subsystem have no operations. * or the subsystem have no operations.
...@@ -571,8 +615,8 @@ static void hash_and_remove(struct dentry * dir, const char * name) ...@@ -571,8 +615,8 @@ static void hash_and_remove(struct dentry * dir, const char * name)
/* make sure dentry is really there */ /* make sure dentry is really there */
if (victim->d_inode && if (victim->d_inode &&
(victim->d_parent->d_inode == dir->d_inode)) { (victim->d_parent->d_inode == dir->d_inode)) {
d_invalidate(victim);
simple_unlink(dir->d_inode,victim); simple_unlink(dir->d_inode,victim);
d_delete(victim);
} }
} }
up(&dir->d_inode->i_sem); up(&dir->d_inode->i_sem);
...@@ -631,15 +675,15 @@ void sysfs_remove_dir(struct kobject * kobj) ...@@ -631,15 +675,15 @@ void sysfs_remove_dir(struct kobject * kobj)
struct dentry * d = list_entry(node,struct dentry,d_child); struct dentry * d = list_entry(node,struct dentry,d_child);
/* make sure dentry is still there */ /* make sure dentry is still there */
if (d->d_inode) { if (d->d_inode) {
d_invalidate(d);
simple_unlink(dentry->d_inode,d); simple_unlink(dentry->d_inode,d);
d_delete(dentry);
} }
} }
up(&dentry->d_inode->i_sem); up(&dentry->d_inode->i_sem);
d_invalidate(dentry); d_invalidate(dentry);
simple_rmdir(parent->d_inode,dentry); simple_rmdir(parent->d_inode,dentry);
d_delete(dentry);
up(&parent->d_inode->i_sem); up(&parent->d_inode->i_sem);
dput(parent); dput(parent);
} }
......
...@@ -85,6 +85,15 @@ extern struct bus_type * get_bus(struct bus_type * bus); ...@@ -85,6 +85,15 @@ extern struct bus_type * get_bus(struct bus_type * bus);
extern void put_bus(struct bus_type * bus); extern void put_bus(struct bus_type * bus);
/* iterator helpers for buses */
int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
int (*fn)(struct device *, void *));
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *));
/* driverfs interface for exporting bus attributes */ /* driverfs interface for exporting bus attributes */
struct bus_attribute { struct bus_attribute {
...@@ -159,6 +168,7 @@ struct device_class { ...@@ -159,6 +168,7 @@ struct device_class {
struct subsystem devsubsys; struct subsystem devsubsys;
struct subsystem drvsubsys; struct subsystem drvsubsys;
struct list_head drivers; struct list_head drivers;
struct list_head devices;
int (*add_device)(struct device *); int (*add_device)(struct device *);
void (*remove_device)(struct device *); void (*remove_device)(struct device *);
...@@ -207,9 +217,7 @@ struct device_interface { ...@@ -207,9 +217,7 @@ struct device_interface {
char * name; char * name;
struct device_class * devclass; struct device_class * devclass;
struct kobject kobj; struct subsystem subsys;
struct list_head devices;
u32 devnum; u32 devnum;
int (*add_device) (struct device *); int (*add_device) (struct device *);
...@@ -230,10 +238,11 @@ extern void interface_unregister(struct device_interface *); ...@@ -230,10 +238,11 @@ extern void interface_unregister(struct device_interface *);
* and create a driverfs symlink for it. * and create a driverfs symlink for it.
*/ */
struct intf_data { struct intf_data {
struct list_head node;
struct device_interface * intf; struct device_interface * intf;
struct device * dev; struct device * dev;
u32 intf_num; u32 intf_num;
struct list_head dev_entry;
struct kobject kobj;
}; };
extern int interface_add_data(struct intf_data *); extern int interface_add_data(struct intf_data *);
...@@ -241,9 +250,9 @@ extern int interface_add_data(struct intf_data *); ...@@ -241,9 +250,9 @@ extern int interface_add_data(struct intf_data *);
struct device { struct device {
struct list_head g_list; /* node in depth-first order list */
struct list_head node; /* node in sibling list */ struct list_head node; /* node in sibling list */
struct list_head bus_list; /* node in bus's list */ struct list_head bus_list; /* node in bus's list */
struct list_head class_list;
struct list_head driver_list; struct list_head driver_list;
struct list_head children; struct list_head children;
struct list_head intf_list; struct list_head intf_list;
...@@ -270,6 +279,7 @@ struct device { ...@@ -270,6 +279,7 @@ struct device {
being off. */ being off. */
unsigned char *saved_state; /* saved device state */ unsigned char *saved_state; /* saved device state */
u64 *dma_mask; /* dma mask (if dma'able device) */
void (*release)(struct device * dev); void (*release)(struct device * dev);
}; };
...@@ -280,12 +290,6 @@ list_to_dev(struct list_head *node) ...@@ -280,12 +290,6 @@ list_to_dev(struct list_head *node)
return list_entry(node, struct device, node); return list_entry(node, struct device, node);
} }
static inline struct device *
g_list_to_dev(struct list_head *g_list)
{
return list_entry(g_list, struct device, g_list);
}
static inline void * static inline void *
dev_get_drvdata (struct device *dev) dev_get_drvdata (struct device *dev)
{ {
......
...@@ -60,4 +60,13 @@ static inline void subsys_put(struct subsystem * s) ...@@ -60,4 +60,13 @@ static inline void subsys_put(struct subsystem * s)
kobject_put(&s->kobj); kobject_put(&s->kobj);
} }
struct subsys_attribute {
struct attribute attr;
ssize_t (*show)(struct subsystem *, char *, size_t, loff_t);
ssize_t (*store)(struct subsystem *, const char *, size_t, loff_t);
};
extern int subsys_create_file(struct subsystem * , struct subsys_attribute *);
extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *);
#endif /* _KOBJECT_H_ */ #endif /* _KOBJECT_H_ */
...@@ -48,13 +48,6 @@ extern void machine_restart(char *cmd); ...@@ -48,13 +48,6 @@ extern void machine_restart(char *cmd);
extern void machine_halt(void); extern void machine_halt(void);
extern void machine_power_off(void); extern void machine_power_off(void);
/*
* Architecture-independent suspend facility
*/
extern void software_suspend(void);
extern unsigned char software_suspend_enabled;
#endif #endif
#endif /* _LINUX_REBOOT_H */ #endif /* _LINUX_REBOOT_H */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/times.h> #include <linux/times.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/dcookies.h> #include <linux/dcookies.h>
#include <linux/suspend.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
......
...@@ -110,8 +110,7 @@ int kobject_register(struct kobject * kobj) ...@@ -110,8 +110,7 @@ int kobject_register(struct kobject * kobj)
if (kobj) { if (kobj) {
kobject_init(kobj); kobject_init(kobj);
error = kobject_add(kobj); error = kobject_add(kobj);
if (error) WARN_ON(error);
kobject_cleanup(kobj);
} else } else
error = -EINVAL; error = -EINVAL;
return error; return error;
...@@ -229,6 +228,38 @@ void subsystem_unregister(struct subsystem * s) ...@@ -229,6 +228,38 @@ void subsystem_unregister(struct subsystem * s)
} }
/**
* subsystem_create_file - export sysfs attribute file.
* @s: subsystem.
* @a: subsystem attribute descriptor.
*/
int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
{
int error = 0;
if (subsys_get(s)) {
error = sysfs_create_file(&s->kobj,&a->attr);
subsys_put(s);
}
return error;
}
/**
* subsystem_remove_file - remove sysfs attribute file.
* @s: subsystem.
* @a: attribute desciptor.
*/
void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
{
if (subsys_get(s)) {
sysfs_remove_file(&s->kobj,&a->attr);
subsys_put(s);
}
}
EXPORT_SYMBOL(kobject_init); EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register); EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister); EXPORT_SYMBOL(kobject_unregister);
...@@ -238,3 +269,5 @@ EXPORT_SYMBOL(kobject_put); ...@@ -238,3 +269,5 @@ EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(subsystem_init); EXPORT_SYMBOL(subsystem_init);
EXPORT_SYMBOL(subsystem_register); EXPORT_SYMBOL(subsystem_register);
EXPORT_SYMBOL(subsystem_unregister); EXPORT_SYMBOL(subsystem_unregister);
EXPORT_SYMBOL(subsys_create_file);
EXPORT_SYMBOL(subsys_remove_file);
...@@ -22,5 +22,15 @@ config SECURITY_CAPABILITIES ...@@ -22,5 +22,15 @@ config SECURITY_CAPABILITIES
This enables the "default" Linux capabilities functionality. This enables the "default" Linux capabilities functionality.
If you are unsure how to answer this question, answer Y. If you are unsure how to answer this question, answer Y.
config SECURITY_ROOTPLUG
tristate "Root Plug Support"
depends on SECURITY!=n
help
This is a sample LSM module that should only be used as such.
It enables control over processes being created by root users
if a specific USB device is not present in the system.
If you are unsure how to answer this question, answer N.
endmenu endmenu
...@@ -13,5 +13,6 @@ endif ...@@ -13,5 +13,6 @@ endif
# Object file lists # Object file lists
obj-$(CONFIG_SECURITY) += security.o dummy.o obj-$(CONFIG_SECURITY) += security.o dummy.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
This diff is collapsed.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#undef DEBUG
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -19,6 +21,7 @@ ...@@ -19,6 +21,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netlink.h> #include <linux/netlink.h>
static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
{ {
return 0; return 0;
...@@ -122,55 +125,55 @@ static int dummy_sb_statfs (struct super_block *sb) ...@@ -122,55 +125,55 @@ static int dummy_sb_statfs (struct super_block *sb)
return 0; return 0;
} }
static int dummy_mount (char *dev_name, struct nameidata *nd, char *type, static int dummy_sb_mount (char *dev_name, struct nameidata *nd, char *type,
unsigned long flags, void *data) unsigned long flags, void *data)
{ {
return 0; return 0;
} }
static int dummy_check_sb (struct vfsmount *mnt, struct nameidata *nd) static int dummy_sb_check_sb (struct vfsmount *mnt, struct nameidata *nd)
{ {
return 0; return 0;
} }
static int dummy_umount (struct vfsmount *mnt, int flags) static int dummy_sb_umount (struct vfsmount *mnt, int flags)
{ {
return 0; return 0;
} }
static void dummy_umount_close (struct vfsmount *mnt) static void dummy_sb_umount_close (struct vfsmount *mnt)
{ {
return; return;
} }
static void dummy_umount_busy (struct vfsmount *mnt) static void dummy_sb_umount_busy (struct vfsmount *mnt)
{ {
return; return;
} }
static void dummy_post_remount (struct vfsmount *mnt, unsigned long flags, static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,
void *data) void *data)
{ {
return; return;
} }
static void dummy_post_mountroot (void) static void dummy_sb_post_mountroot (void)
{ {
return; return;
} }
static void dummy_post_addmount (struct vfsmount *mnt, struct nameidata *nd) static void dummy_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
{ {
return; return;
} }
static int dummy_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) static int dummy_sb_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
{ {
return 0; return 0;
} }
static void dummy_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd) static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
{ {
return; return;
} }
...@@ -303,12 +306,12 @@ static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry) ...@@ -303,12 +306,12 @@ static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
return 0; return 0;
} }
static void dummy_post_lookup (struct inode *ino, struct dentry *d) static void dummy_inode_post_lookup (struct inode *ino, struct dentry *d)
{ {
return; return;
} }
static void dummy_delete (struct inode *ino) static void dummy_inode_delete (struct inode *ino)
{ {
return; return;
} }
...@@ -529,12 +532,12 @@ static void dummy_sem_free_security (struct sem_array *sma) ...@@ -529,12 +532,12 @@ static void dummy_sem_free_security (struct sem_array *sma)
return; return;
} }
static int dummy_register (const char *name, struct security_operations *ops) static int dummy_register_security (const char *name, struct security_operations *ops)
{ {
return -EINVAL; return -EINVAL;
} }
static int dummy_unregister (const char *name, struct security_operations *ops) static int dummy_unregister_security (const char *name, struct security_operations *ops)
{ {
return -EINVAL; return -EINVAL;
} }
...@@ -558,16 +561,16 @@ struct security_operations dummy_security_ops = { ...@@ -558,16 +561,16 @@ struct security_operations dummy_security_ops = {
.sb_alloc_security = dummy_sb_alloc_security, .sb_alloc_security = dummy_sb_alloc_security,
.sb_free_security = dummy_sb_free_security, .sb_free_security = dummy_sb_free_security,
.sb_statfs = dummy_sb_statfs, .sb_statfs = dummy_sb_statfs,
.sb_mount = dummy_mount, .sb_mount = dummy_sb_mount,
.sb_check_sb = dummy_check_sb, .sb_check_sb = dummy_sb_check_sb,
.sb_umount = dummy_umount, .sb_umount = dummy_sb_umount,
.sb_umount_close = dummy_umount_close, .sb_umount_close = dummy_sb_umount_close,
.sb_umount_busy = dummy_umount_busy, .sb_umount_busy = dummy_sb_umount_busy,
.sb_post_remount = dummy_post_remount, .sb_post_remount = dummy_sb_post_remount,
.sb_post_mountroot = dummy_post_mountroot, .sb_post_mountroot = dummy_sb_post_mountroot,
.sb_post_addmount = dummy_post_addmount, .sb_post_addmount = dummy_sb_post_addmount,
.sb_pivotroot = dummy_pivotroot, .sb_pivotroot = dummy_sb_pivotroot,
.sb_post_pivotroot = dummy_post_pivotroot, .sb_post_pivotroot = dummy_sb_post_pivotroot,
.inode_alloc_security = dummy_inode_alloc_security, .inode_alloc_security = dummy_inode_alloc_security,
.inode_free_security = dummy_inode_free_security, .inode_free_security = dummy_inode_free_security,
...@@ -591,8 +594,8 @@ struct security_operations dummy_security_ops = { ...@@ -591,8 +594,8 @@ struct security_operations dummy_security_ops = {
.inode_permission_lite = dummy_inode_permission_lite, .inode_permission_lite = dummy_inode_permission_lite,
.inode_setattr = dummy_inode_setattr, .inode_setattr = dummy_inode_setattr,
.inode_getattr = dummy_inode_getattr, .inode_getattr = dummy_inode_getattr,
.inode_post_lookup = dummy_post_lookup, .inode_post_lookup = dummy_inode_post_lookup,
.inode_delete = dummy_delete, .inode_delete = dummy_inode_delete,
.inode_setxattr = dummy_inode_setxattr, .inode_setxattr = dummy_inode_setxattr,
.inode_getxattr = dummy_inode_getxattr, .inode_getxattr = dummy_inode_getxattr,
.inode_listxattr = dummy_inode_listxattr, .inode_listxattr = dummy_inode_listxattr,
...@@ -641,7 +644,113 @@ struct security_operations dummy_security_ops = { ...@@ -641,7 +644,113 @@ struct security_operations dummy_security_ops = {
.sem_alloc_security = dummy_sem_alloc_security, .sem_alloc_security = dummy_sem_alloc_security,
.sem_free_security = dummy_sem_free_security, .sem_free_security = dummy_sem_free_security,
.register_security = dummy_register, .register_security = dummy_register_security,
.unregister_security = dummy_unregister, .unregister_security = dummy_unregister_security,
}; };
#define set_to_dummy_if_null(ops, function) \
do { \
if (!ops->function) { \
ops->function = dummy_##function; \
pr_debug("Had to override the " #function \
" security operation with the dummy one.\n");\
} \
} while (0)
void security_fixup_ops (struct security_operations *ops)
{
set_to_dummy_if_null(ops, ptrace);
set_to_dummy_if_null(ops, capget);
set_to_dummy_if_null(ops, capset_check);
set_to_dummy_if_null(ops, capset_set);
set_to_dummy_if_null(ops, acct);
set_to_dummy_if_null(ops, capable);
set_to_dummy_if_null(ops, quotactl);
set_to_dummy_if_null(ops, quota_on);
set_to_dummy_if_null(ops, bprm_alloc_security);
set_to_dummy_if_null(ops, bprm_free_security);
set_to_dummy_if_null(ops, bprm_compute_creds);
set_to_dummy_if_null(ops, bprm_set_security);
set_to_dummy_if_null(ops, bprm_check_security);
set_to_dummy_if_null(ops, sb_alloc_security);
set_to_dummy_if_null(ops, sb_free_security);
set_to_dummy_if_null(ops, sb_statfs);
set_to_dummy_if_null(ops, sb_mount);
set_to_dummy_if_null(ops, sb_check_sb);
set_to_dummy_if_null(ops, sb_umount);
set_to_dummy_if_null(ops, sb_umount_close);
set_to_dummy_if_null(ops, sb_umount_busy);
set_to_dummy_if_null(ops, sb_post_remount);
set_to_dummy_if_null(ops, sb_post_mountroot);
set_to_dummy_if_null(ops, sb_post_addmount);
set_to_dummy_if_null(ops, sb_pivotroot);
set_to_dummy_if_null(ops, sb_post_pivotroot);
set_to_dummy_if_null(ops, inode_alloc_security);
set_to_dummy_if_null(ops, inode_free_security);
set_to_dummy_if_null(ops, inode_create);
set_to_dummy_if_null(ops, inode_post_create);
set_to_dummy_if_null(ops, inode_link);
set_to_dummy_if_null(ops, inode_post_link);
set_to_dummy_if_null(ops, inode_unlink);
set_to_dummy_if_null(ops, inode_symlink);
set_to_dummy_if_null(ops, inode_post_symlink);
set_to_dummy_if_null(ops, inode_mkdir);
set_to_dummy_if_null(ops, inode_post_mkdir);
set_to_dummy_if_null(ops, inode_rmdir);
set_to_dummy_if_null(ops, inode_mknod);
set_to_dummy_if_null(ops, inode_post_mknod);
set_to_dummy_if_null(ops, inode_rename);
set_to_dummy_if_null(ops, inode_post_rename);
set_to_dummy_if_null(ops, inode_readlink);
set_to_dummy_if_null(ops, inode_follow_link);
set_to_dummy_if_null(ops, inode_permission);
set_to_dummy_if_null(ops, inode_permission_lite);
set_to_dummy_if_null(ops, inode_setattr);
set_to_dummy_if_null(ops, inode_getattr);
set_to_dummy_if_null(ops, inode_post_lookup);
set_to_dummy_if_null(ops, inode_delete);
set_to_dummy_if_null(ops, inode_setxattr);
set_to_dummy_if_null(ops, inode_getxattr);
set_to_dummy_if_null(ops, inode_listxattr);
set_to_dummy_if_null(ops, inode_removexattr);
set_to_dummy_if_null(ops, file_permission);
set_to_dummy_if_null(ops, file_alloc_security);
set_to_dummy_if_null(ops, file_free_security);
set_to_dummy_if_null(ops, file_ioctl);
set_to_dummy_if_null(ops, file_mmap);
set_to_dummy_if_null(ops, file_mprotect);
set_to_dummy_if_null(ops, file_lock);
set_to_dummy_if_null(ops, file_fcntl);
set_to_dummy_if_null(ops, file_set_fowner);
set_to_dummy_if_null(ops, file_send_sigiotask);
set_to_dummy_if_null(ops, file_receive);
set_to_dummy_if_null(ops, task_create);
set_to_dummy_if_null(ops, task_alloc_security);
set_to_dummy_if_null(ops, task_free_security);
set_to_dummy_if_null(ops, task_setuid);
set_to_dummy_if_null(ops, task_post_setuid);
set_to_dummy_if_null(ops, task_setgid);
set_to_dummy_if_null(ops, task_setpgid);
set_to_dummy_if_null(ops, task_getpgid);
set_to_dummy_if_null(ops, task_getsid);
set_to_dummy_if_null(ops, task_setgroups);
set_to_dummy_if_null(ops, task_setnice);
set_to_dummy_if_null(ops, task_setrlimit);
set_to_dummy_if_null(ops, task_setscheduler);
set_to_dummy_if_null(ops, task_getscheduler);
set_to_dummy_if_null(ops, task_wait);
set_to_dummy_if_null(ops, task_kill);
set_to_dummy_if_null(ops, task_prctl);
set_to_dummy_if_null(ops, task_kmod_set_label);
set_to_dummy_if_null(ops, task_reparent_to_init);
set_to_dummy_if_null(ops, ipc_permission);
set_to_dummy_if_null(ops, msg_queue_alloc_security);
set_to_dummy_if_null(ops, msg_queue_free_security);
set_to_dummy_if_null(ops, shm_alloc_security);
set_to_dummy_if_null(ops, shm_free_security);
set_to_dummy_if_null(ops, sem_alloc_security);
set_to_dummy_if_null(ops, sem_free_security);
set_to_dummy_if_null(ops, register_security);
set_to_dummy_if_null(ops, unregister_security);
}
/*
* Root Plug sample LSM module
*
* Originally written for a Linux Journal.
*
* Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com>
*
* Prevents any programs running with egid == 0 if a specific USB device
* is not present in the system. Yes, it can be gotten around, but is a
* nice starting point for people to play with, and learn the LSM
* interface.
*
* If you want to turn this into something with a semblance of security,
* you need to hook the task_* functions also.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/security.h>
#include <linux/usb.h>
/* flag to keep track of how we were registered */
static int secondary;
/* default is a generic type of usb to serial converter */
static int vendor_id = 0x0557;
static int product_id = 0x2008;
MODULE_PARM(vendor_id, "h");
MODULE_PARM_DESC(vendor_id, "USB Vendor ID of device to look for");
MODULE_PARM(product_id, "h");
MODULE_PARM_DESC(product_id, "USB Product ID of device to look for");
/* should we print out debug messages */
static int debug = 0;
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
#if defined(CONFIG_SECURITY_ROOTPLUG_MODULE)
#define MY_NAME THIS_MODULE->name
#else
#define MY_NAME "root_plug"
#endif
#define dbg(fmt, arg...) \
do { \
if (debug) \
printk(KERN_DEBUG "%s: %s: " fmt , \
MY_NAME , __FUNCTION__ , \
## arg); \
} while (0)
extern struct list_head usb_bus_list;
extern struct semaphore usb_bus_list_lock;
static int match_device (struct usb_device *dev)
{
int retval = -ENODEV;
int child;
dbg ("looking at vendor %d, product %d\n",
dev->descriptor.idVendor,
dev->descriptor.idProduct);
/* see if this device matches */
if ((dev->descriptor.idVendor == vendor_id) &&
(dev->descriptor.idProduct == product_id)) {
dbg ("found the device!\n");
retval = 0;
goto exit;
}
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
retval = match_device (dev->children[child]);
if (retval == 0)
goto exit;
}
}
exit:
return retval;
}
static int find_usb_device (void)
{
struct list_head *buslist;
struct usb_bus *bus;
int retval = -ENODEV;
down (&usb_bus_list_lock);
for (buslist = usb_bus_list.next;
buslist != &usb_bus_list;
buslist = buslist->next) {
bus = container_of (buslist, struct usb_bus, bus_list);
retval = match_device(bus->root_hub);
if (retval == 0)
goto exit;
}
exit:
up (&usb_bus_list_lock);
return retval;
}
static int rootplug_bprm_check_security (struct linux_binprm *bprm)
{
dbg ("file %s, e_uid = %d, e_gid = %d\n",
bprm->filename, bprm->e_uid, bprm->e_gid);
if (bprm->e_gid == 0) {
if (find_usb_device() != 0) {
dbg ("e_gid = 0, and device not found, "
"task not allowed to run...\n");
return -EPERM;
}
}
return 0;
}
static struct security_operations rootplug_security_ops = {
/* Use the capability functions for some of the hooks */
.ptrace = cap_ptrace,
.capget = cap_capget,
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
.capable = cap_capable,
.bprm_compute_creds = cap_bprm_compute_creds,
.bprm_set_security = cap_bprm_set_security,
.task_post_setuid = cap_task_post_setuid,
.task_kmod_set_label = cap_task_kmod_set_label,
.task_reparent_to_init = cap_task_reparent_to_init,
.bprm_check_security = rootplug_bprm_check_security,
};
static int __init rootplug_init (void)
{
/* register ourselves with the security framework */
if (register_security (&rootplug_security_ops)) {
printk (KERN_INFO
"Failure registering Root Plug module with the kernel\n");
/* try registering with primary module */
if (mod_reg_security (MY_NAME, &rootplug_security_ops)) {
printk (KERN_INFO "Failure registering Root Plug "
" module with primary security module.\n");
return -EINVAL;
}
secondary = 1;
}
printk (KERN_INFO "Root Plug module initialized, "
"vendor_id = %4.4x, product id = %4.4x\n", vendor_id, product_id);
return 0;
}
static void __exit rootplug_exit (void)
{
/* remove ourselves from the security framework */
if (secondary) {
if (mod_unreg_security (MY_NAME, &rootplug_security_ops))
printk (KERN_INFO "Failure unregistering Root Plug "
" module with primary module.\n");
} else {
if (unregister_security (&rootplug_security_ops)) {
printk (KERN_INFO "Failure unregistering Root Plug "
"module with the kernel\n");
}
}
printk (KERN_INFO "Root Plug module removed\n");
}
module_init (rootplug_init);
module_exit (rootplug_exit);
MODULE_DESCRIPTION("Root Plug sample LSM module, written for Linux Journal article");
MODULE_LICENSE("GPL");
...@@ -20,59 +20,21 @@ ...@@ -20,59 +20,21 @@
#define SECURITY_SCAFFOLD_VERSION "1.0.0" #define SECURITY_SCAFFOLD_VERSION "1.0.0"
extern struct security_operations dummy_security_ops; /* lives in dummy.c */ /* things that live in dummy.c */
extern struct security_operations dummy_security_ops;
extern void security_fixup_ops (struct security_operations *ops);
struct security_operations *security_ops; /* Initialized to NULL */ struct security_operations *security_ops; /* Initialized to NULL */
/* This macro checks that all pointers in a struct are non-NULL. It static inline int verify (struct security_operations *ops)
* can be fooled by struct padding for object tile alignment and when
* pointers to data and pointers to functions aren't the same size.
* Yes it's ugly, we'll replace it if it becomes a problem.
*/
#define VERIFY_STRUCT(struct_type, s, e) \
do { \
unsigned long * __start = (unsigned long *)(s); \
unsigned long * __end = __start + \
sizeof(struct_type)/sizeof(unsigned long *); \
while (__start != __end) { \
if (!*__start) { \
printk(KERN_INFO "%s is missing something\n",\
#struct_type); \
e++; \
break; \
} \
__start++; \
} \
} while (0)
static int inline verify (struct security_operations *ops)
{ {
int err;
/* verify the security_operations structure exists */ /* verify the security_operations structure exists */
if (!ops) { if (!ops) {
printk (KERN_INFO "Passed a NULL security_operations " printk (KERN_INFO "Passed a NULL security_operations "
"pointer, %s failed.\n", __FUNCTION__); "pointer, %s failed.\n", __FUNCTION__);
return -EINVAL; return -EINVAL;
} }
security_fixup_ops (ops);
/* Perform a little sanity checking on our inputs */
err = 0;
/* This first check scans the whole security_ops struct for
* missing structs or functions.
*
* (There is no further check now, but will leave as is until
* the lazy registration stuff is done -- JM).
*/
VERIFY_STRUCT(struct security_operations, ops, err);
if (err) {
printk (KERN_INFO "Not enough functions specified in the "
"security_operation structure, %s failed.\n",
__FUNCTION__);
return -EINVAL;
}
return 0; return 0;
} }
...@@ -106,12 +68,12 @@ int security_scaffolding_startup (void) ...@@ -106,12 +68,12 @@ int security_scaffolding_startup (void)
*/ */
int register_security (struct security_operations *ops) int register_security (struct security_operations *ops)
{ {
if (verify (ops)) { if (verify (ops)) {
printk (KERN_INFO "%s could not verify " printk (KERN_INFO "%s could not verify "
"security_operations structure.\n", __FUNCTION__); "security_operations structure.\n", __FUNCTION__);
return -EINVAL; return -EINVAL;
} }
if (security_ops != &dummy_security_ops) { if (security_ops != &dummy_security_ops) {
printk (KERN_INFO "There is already a security " printk (KERN_INFO "There is already a security "
"framework initialized, %s failed.\n", __FUNCTION__); "framework initialized, %s failed.\n", __FUNCTION__);
......
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