Revision da9846ae15186d491d6e21ebbb5051e1d3c7f652 authored by Tejun Heo on 29 January 2014, 17:04:03 UTC, committed by Greg Kroah-Hartman on 05 February 2014, 19:44:04 UTC
kernfs_deactivate() forgot to check whether KERNFS_LOCKDEP is set before performing lockdep annotations and ends up feeding uninitialized lockdep_map to lockdep triggering warning like the following on USB stick hotunplug. usb 1-2: USB disconnect, device number 2 INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 1 PID: 62 Comm: khubd Not tainted 3.13.0-work+ #82 Hardware name: empty empty/S3992, BIOS 080011 10/26/2007 ffff880065ca7f60 ffff88013a4ffa08 ffffffff81cfb6bd 0000000000000002 ffff88013a4ffac8 ffffffff810f8530 ffff88013a4fc710 0000000000000002 ffff880100000000 ffffffff82a3db50 0000000000000001 ffff88013a4fc710 Call Trace: [<ffffffff81cfb6bd>] dump_stack+0x4e/0x7a [<ffffffff810f8530>] __lock_acquire+0x1910/0x1e70 [<ffffffff810f931a>] lock_acquire+0x9a/0x1d0 [<ffffffff8127c75e>] kernfs_deactivate+0xee/0x130 [<ffffffff8127d4c8>] kernfs_addrm_finish+0x38/0x60 [<ffffffff8127d701>] kernfs_remove_by_name_ns+0x51/0xa0 [<ffffffff8127b4f1>] remove_files.isra.1+0x41/0x80 [<ffffffff8127b7e7>] sysfs_remove_group+0x47/0xa0 [<ffffffff8127b873>] sysfs_remove_groups+0x33/0x50 [<ffffffff8177d66d>] device_remove_attrs+0x4d/0x80 [<ffffffff8177e25e>] device_del+0x12e/0x1d0 [<ffffffff819722c2>] usb_disconnect+0x122/0x1a0 [<ffffffff819749b5>] hub_thread+0x3c5/0x1290 [<ffffffff810c6a6d>] kthread+0xed/0x110 [<ffffffff81d0a56c>] ret_from_fork+0x7c/0xb0 Fix it by making kernfs_deactivate() perform lockdep annotations only if KERNFS_LOCKDEP is set. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Fabio Estevam <festevam@gmail.com> Reported-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Jiri Kosina <jkosina@suse.cz> Reported-by: Dave Jones <davej@redhat.com> Tested-by: Fabio Estevam <fabio.estevam@freescale.com> Tested-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 38dbfb5
sysctl_net.c
/* -*- linux-c -*-
* sysctl_net.c: sysctl interface to net subsystem.
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net directories for each protocol family. [MS]
*
* Revision 1.2 1996/05/08 20:24:40 shaver
* Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and
* NET_IPV4_IP_FORWARD.
*
*
*/
#include <linux/mm.h>
#include <linux/export.h>
#include <linux/sysctl.h>
#include <linux/nsproxy.h>
#include <net/sock.h>
#ifdef CONFIG_INET
#include <net/ip.h>
#endif
#ifdef CONFIG_NET
#include <linux/if_ether.h>
#endif
static struct ctl_table_set *
net_ctl_header_lookup(struct ctl_table_root *root, struct nsproxy *namespaces)
{
return &namespaces->net_ns->sysctls;
}
static int is_seen(struct ctl_table_set *set)
{
return ¤t->nsproxy->net_ns->sysctls == set;
}
/* Return standard mode bits for table entry. */
static int net_ctl_permissions(struct ctl_table_header *head,
struct ctl_table *table)
{
struct net *net = container_of(head->set, struct net, sysctls);
kuid_t root_uid = make_kuid(net->user_ns, 0);
kgid_t root_gid = make_kgid(net->user_ns, 0);
/* Allow network administrator to have same access as root. */
if (ns_capable(net->user_ns, CAP_NET_ADMIN) ||
uid_eq(root_uid, current_euid())) {
int mode = (table->mode >> 6) & 7;
return (mode << 6) | (mode << 3) | mode;
}
/* Allow netns root group to have the same access as the root group */
if (in_egroup_p(root_gid)) {
int mode = (table->mode >> 3) & 7;
return (mode << 3) | mode;
}
return table->mode;
}
static struct ctl_table_root net_sysctl_root = {
.lookup = net_ctl_header_lookup,
.permissions = net_ctl_permissions,
};
static int __net_init sysctl_net_init(struct net *net)
{
setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen);
return 0;
}
static void __net_exit sysctl_net_exit(struct net *net)
{
retire_sysctl_set(&net->sysctls);
}
static struct pernet_operations sysctl_pernet_ops = {
.init = sysctl_net_init,
.exit = sysctl_net_exit,
};
static struct ctl_table_header *net_header;
__init int net_sysctl_init(void)
{
static struct ctl_table empty[1];
int ret = -ENOMEM;
/* Avoid limitations in the sysctl implementation by
* registering "/proc/sys/net" as an empty directory not in a
* network namespace.
*/
net_header = register_sysctl("net", empty);
if (!net_header)
goto out;
ret = register_pernet_subsys(&sysctl_pernet_ops);
if (ret)
goto out;
register_sysctl_root(&net_sysctl_root);
out:
return ret;
}
struct ctl_table_header *register_net_sysctl(struct net *net,
const char *path, struct ctl_table *table)
{
return __register_sysctl_table(&net->sysctls, path, table);
}
EXPORT_SYMBOL_GPL(register_net_sysctl);
void unregister_net_sysctl_table(struct ctl_table_header *header)
{
unregister_sysctl_table(header);
}
EXPORT_SYMBOL_GPL(unregister_net_sysctl_table);
Computing file changes ...