From 7cec4833d01b9597a65e28173c7c231135365d3d Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Wed, 17 Aug 2011 16:43:00 -0700 Subject: netfilter: xt_qtaguid: Fix socket refcounts when tagging * Don't hold the sockets after tagging. sockfd_lookup() does a get() on the associated file. There was no matching put() so a closed socket could never be freed. * Don't rely on struct member order for tag_node The structs that had a struct tag_node member would work with the *_tree_* routines only because tag_node was 1st. * Improve debug messages Provide info on who the caller is. Use unsigned int for uid. * Only process NETDEV_UP events. * Pacifier: disable netfilter matching. Leave .../stats header. Change-Id: Iccb8ae3cca9608210c417597287a2391010dff2c Signed-off-by: JP Abgrall --- net/netfilter/xt_qtaguid.c | 309 +++++++++++++++++++++++++++------------------ 1 file changed, 186 insertions(+), 123 deletions(-) diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index b04b4710574..b9dcfde9976 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -183,7 +183,6 @@ struct tag_stat { * matching parent uid_tag. */ struct data_counters *parent_counters; - struct proc_dir_entry *proc_ptr; }; struct iface_stat { @@ -215,8 +214,11 @@ struct iface_stat_work { * This is the tag against which tag_stat.counters will be billed. */ struct sock_tag { - struct rb_node node; - struct sock *sk; + struct rb_node sock_node; + struct sock *sk; /* Only used as a number, never dereferenced */ + /* The socket is needed for sockfd_put() */ + struct socket *socket; + tag_t tag; }; @@ -345,24 +347,31 @@ static void tag_node_tree_insert(struct tag_node *data, struct rb_root *root) static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root) { - tag_node_tree_insert((struct tag_node *)data, root); + tag_node_tree_insert(&data->tn, root); } static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag) { - return (struct tag_stat *)tag_node_tree_search(root, tag); + struct tag_node *node = tag_node_tree_search(root, tag); + if (!node) + return NULL; + return rb_entry(&node->node, struct tag_stat, tn.node); } static void tag_counter_set_tree_insert(struct tag_counter_set *data, struct rb_root *root) { - tag_node_tree_insert((struct tag_node *)data, root); + tag_node_tree_insert(&data->tn, root); } static struct tag_counter_set *tag_counter_set_tree_search(struct rb_root *root, tag_t tag) { - return (struct tag_counter_set *)tag_node_tree_search(root, tag); + struct tag_node *node = tag_node_tree_search(root, tag); + if (!node) + return NULL; + return rb_entry(&node->node, struct tag_counter_set, tn.node); + } static struct sock_tag *sock_tag_tree_search(struct rb_root *root, @@ -371,7 +380,8 @@ static struct sock_tag *sock_tag_tree_search(struct rb_root *root, struct rb_node *node = root->rb_node; while (node) { - struct sock_tag *data = rb_entry(node, struct sock_tag, node); + struct sock_tag *data = rb_entry(node, struct sock_tag, + sock_node); ptrdiff_t result = sk - data->sk; if (result < 0) node = node->rb_left; @@ -389,7 +399,8 @@ static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root) /* Figure out where to put new node */ while (*new) { - struct sock_tag *this = rb_entry(*new, struct sock_tag, node); + struct sock_tag *this = rb_entry(*new, struct sock_tag, + sock_node); ptrdiff_t result = data->sk - this->sk; parent = *new; if (result < 0) @@ -401,8 +412,8 @@ static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root) } /* Add new node and rebalance tree. */ - rb_link_node(&data->node, parent, new); - rb_insert_color(&data->node, root); + rb_link_node(&data->sock_node, parent, new); + rb_insert_color(&data->sock_node, root); } static int read_proc_u64(char *page, char **start, off_t off, @@ -412,6 +423,7 @@ static int read_proc_u64(char *page, char **start, off_t off, uint64_t value; char *p = page; uint64_t *iface_entry = data; + if (!data) return 0; @@ -430,6 +442,7 @@ static int read_proc_bool(char *page, char **start, off_t off, bool value; char *p = page; bool *bool_entry = data; + if (!data) return 0; @@ -447,7 +460,7 @@ static int get_active_counter_set(tag_t tag) struct tag_counter_set *tcs; MT_DEBUG("qtaguid: get_active_counter_set(tag=0x%llx)" - " (uid=%d)\n", + " (uid=%u)\n", tag, get_uid_from_tag(tag)); /* For now we only handle UID tags for active sets */ tag = get_utag_from_tag(tag); @@ -469,11 +482,10 @@ static struct iface_stat *get_iface_entry(const char *ifname) /* Find the entry for tracking the specified tag within the interface */ if (ifname == NULL) { - pr_info("iface_stat: NULL device name\n"); + pr_info("qtaguid: iface_stat: get() NULL device name\n"); return NULL; } - /* Iterate over interfaces */ list_for_each_entry(iface_entry, &iface_stat_list, list) { if (!strcmp(ifname, iface_entry->ifname)) @@ -525,12 +537,14 @@ static struct iface_stat *iface_alloc(const char *ifname) new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC); if (new_iface == NULL) { - pr_err("qtaguid: iface_stat: create(): failed to alloc iface_stat\n"); + pr_err("qtaguid: iface_stat: create(%s): " + "iface_stat alloc failed\n", ifname); return NULL; } new_iface->ifname = kstrdup(ifname, GFP_ATOMIC); if (new_iface->ifname == NULL) { - pr_err("qtaguid: iface_stat: create(): failed to alloc ifname\n"); + pr_err("qtaguid: iface_stat: create(%s): " + "ifname alloc failed\n", ifname); kfree(new_iface); return NULL; } @@ -544,8 +558,8 @@ static struct iface_stat *iface_alloc(const char *ifname) */ isw = kmalloc(sizeof(*isw), GFP_ATOMIC); if (!isw) { - pr_err("qtaguid: iface_stat: create(): " - "failed to alloc work for %s\n", new_iface->ifname); + pr_err("qtaguid: iface_stat: create(%s): " + "work alloc failed\n", new_iface->ifname); kfree(new_iface->ifname); kfree(new_iface); return NULL; @@ -571,10 +585,11 @@ void iface_stat_create(const struct net_device *net_dev, __be32 ipaddr = 0; struct iface_stat *new_iface; - IF_DEBUG("qtaguid: iface_stat: create(): ifa=%p netdev=%p->name=%s\n", - ifa, net_dev, net_dev ? net_dev->name : ""); + IF_DEBUG("qtaguid: iface_stat: create(%s): ifa=%p netdev=%p\n", + net_dev ? net_dev->name : "?", + ifa, net_dev); if (!net_dev) { - pr_err("qtaguid: iface_stat: create(): no net dev!\n"); + pr_err("qtaguid: iface_stat: create(): no net dev\n"); return; } @@ -582,16 +597,16 @@ void iface_stat_create(const struct net_device *net_dev, if (!ifa) { in_dev = in_dev_get(net_dev); if (!in_dev) { - pr_err("qtaguid: iface_stat: create(): " - "no inet dev for %s!\n", ifname); + pr_err("qtaguid: iface_stat: create(%s): no inet dev\n", + ifname); return; } - IF_DEBUG("qtaguid: iface_stat: create(): in_dev=%p ifname=%p\n", - in_dev, ifname); + IF_DEBUG("qtaguid: iface_stat: create(%s): in_dev=%p\n", + ifname, in_dev); for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { - IF_DEBUG("qtaguid: iface_stat: create(): " - "ifa=%p ifname=%s ifa_label=%s\n", - ifa, ifname, + IF_DEBUG("qtaguid: iface_stat: create(%s): " + "ifa=%p ifa_label=%s\n", + ifname, ifa, ifa->ifa_label ? ifa->ifa_label : "(null)"); if (ifa->ifa_label && !strcmp(ifname, ifa->ifa_label)) break; @@ -599,8 +614,7 @@ void iface_stat_create(const struct net_device *net_dev, } if (!ifa) { - IF_DEBUG("qtaguid: iface_stat: create(): " - "dev %s has no matching IP\n", + IF_DEBUG("qtaguid: iface_stat: create(%s): no matching IP\n", ifname); goto done_put; } @@ -609,29 +623,29 @@ void iface_stat_create(const struct net_device *net_dev, spin_lock_bh(&iface_stat_list_lock); entry = get_iface_entry(ifname); if (entry != NULL) { - IF_DEBUG("qtaguid: iface_stat: create(): dev %s entry=%p\n", + IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n", ifname, entry); if (ipv4_is_loopback(ipaddr)) { entry->active = false; - IF_DEBUG("qtaguid: iface_stat: create(): " - "disable tracking of loopback dev %s\n", + IF_DEBUG("qtaguid: iface_stat: create(%s): " + "disable tracking of loopback dev\n", ifname); } else { entry->active = true; - IF_DEBUG("qtaguid: iface_stat: create(): " - "enable tracking of dev %s with ip=%pI4\n", + IF_DEBUG("qtaguid: iface_stat: create(%s): " + "enable tracking. ip=%pI4\n", ifname, &ipaddr); } goto done_unlock_put; } else if (ipv4_is_loopback(ipaddr)) { - IF_DEBUG("qtaguid: iface_stat: create(): ignore loopback dev %s" - " ip=%pI4\n", ifname, &ipaddr); + IF_DEBUG("qtaguid: iface_stat: create(%s): " + "ignore loopback dev. ip=%pI4\n", ifname, &ipaddr); goto done_unlock_put; } new_iface = iface_alloc(ifname); - IF_DEBUG("qtaguid: iface_stat: create(): done " - "entry=%p dev=%s ip=%pI4\n", new_iface, ifname, &ipaddr); + IF_DEBUG("qtaguid: iface_stat: create(%s): done " + "entry=%p ip=%pI4\n", ifname, new_iface, &ipaddr); done_unlock_put: spin_unlock_bh(&iface_stat_list_lock); @@ -659,17 +673,16 @@ void iface_stat_create_ipv6(const struct net_device *net_dev, in_dev = in_dev_get(net_dev); if (!in_dev) { - pr_err("qtaguid: iface_stat: create6(): no inet dev for %s!\n", + pr_err("qtaguid: iface_stat: create6(%s): no inet dev\n", ifname); return; } - IF_DEBUG("qtaguid: iface_stat: create6(): in_dev=%p ifname=%p\n", - in_dev, ifname); + IF_DEBUG("qtaguid: iface_stat: create6(%s): in_dev=%p\n", + ifname, in_dev); if (!ifa) { - IF_DEBUG("qtaguid: iface_stat: create6(): " - "dev %s has no matching IP\n", + IF_DEBUG("qtaguid: iface_stat: create6(%s): no matching IP\n", ifname); goto done_put; } @@ -678,30 +691,30 @@ void iface_stat_create_ipv6(const struct net_device *net_dev, spin_lock_bh(&iface_stat_list_lock); entry = get_iface_entry(ifname); if (entry != NULL) { - IF_DEBUG("qtaguid: iface_stat: create6(): dev %s entry=%p\n", + IF_DEBUG("qtaguid: iface_stat: create6(%s): entry=%p\n", ifname, entry); if (addr_type & IPV6_ADDR_LOOPBACK) { entry->active = false; - IF_DEBUG("qtaguid: iface_stat: create6(): " - "disable tracking of loopback dev %s\n", + IF_DEBUG("qtaguid: iface_stat: create6(%s): " + "disable tracking of loopback dev\n", ifname); } else { entry->active = true; - IF_DEBUG("qtaguid: iface_stat: create6(): " - "enable tracking of dev %s with ip=%pI6c\n", + IF_DEBUG("qtaguid: iface_stat: create6(%s): " + "enable tracking. ip=%pI6c\n", ifname, &ifa->addr); } goto done_unlock_put; } else if (addr_type & IPV6_ADDR_LOOPBACK) { - IF_DEBUG("qtaguid: iface_stat: create6(): " - "ignore loopback dev %s ip=%pI6c\n", + IF_DEBUG("qtaguid: iface_stat: create6(%s): " + "ignore loopback dev. ip=%pI6c\n", ifname, &ifa->addr); goto done_unlock_put; } new_iface = iface_alloc(ifname); - IF_DEBUG("qtaguid: iface_stat: create6(): done " - "entry=%p dev=%s ip=%pI6c\n", new_iface, ifname, &ifa->addr); + IF_DEBUG("qtaguid: iface_stat: create6(%s): done " + "entry=%p ip=%pI6c\n", ifname, new_iface, &ifa->addr); done_unlock_put: spin_unlock_bh(&iface_stat_list_lock); @@ -760,22 +773,22 @@ static void iface_stat_update(struct net_device *dev) spin_lock_bh(&iface_stat_list_lock); entry = get_iface_entry(dev->name); if (entry == NULL) { - IF_DEBUG("qtaguid: iface_stat: dev %s monitor not found\n", + IF_DEBUG("qtaguid: iface_stat_update: dev=%s not tracked\n", dev->name); spin_unlock_bh(&iface_stat_list_lock); return; } + IF_DEBUG("qtaguid: iface_stat_update: dev=%s entry=%p\n", + dev->name, entry); if (entry->active) { entry->tx_bytes += stats->tx_bytes; entry->tx_packets += stats->tx_packets; entry->rx_bytes += stats->rx_bytes; entry->rx_packets += stats->rx_packets; entry->active = false; - IF_DEBUG("qtaguid: iface_stat: Updating stats for " - "dev %s which went down\n", dev->name); } else { - IF_DEBUG("qtaguid: iface_stat: Did not update stats for " - "dev %s which went down\n", dev->name); + IF_DEBUG("qtaguid: iface_stat_update: dev=%s inactive\n", + dev->name); } spin_unlock_bh(&iface_stat_list_lock); } @@ -785,7 +798,7 @@ static void tag_stat_update(struct tag_stat *tag_entry, { int active_set; active_set = get_active_counter_set(tag_entry->tn.tag); - MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%d) set=%d " + MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%u) set=%d " "dir=%d proto=%d bytes=%d)\n", tag_entry->tn.tag, get_uid_from_tag(tag_entry->tn.tag), active_set, direction, proto, bytes); @@ -806,11 +819,11 @@ static struct tag_stat *create_if_tag_stat(struct iface_stat *iface_entry, { struct tag_stat *new_tag_stat_entry = NULL; IF_DEBUG("qtaguid: iface_stat: create_if_tag_stat(): ife=%p tag=0x%llx" - " (uid=%d)\n", + " (uid=%u)\n", iface_entry, tag, get_uid_from_tag(tag)); new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC); if (!new_tag_stat_entry) { - pr_err("qtaguid: iface_stat: failed to alloc new tag entry\n"); + pr_err("qtaguid: iface_stat: tag stat alloc failed\n"); goto done; } new_tag_stat_entry->tn.tag = tag; @@ -831,19 +844,20 @@ static void if_tag_stat_update(const char *ifname, uid_t uid, struct iface_stat *iface_entry; struct tag_stat *new_tag_stat; MT_DEBUG("qtaguid: if_tag_stat_update(ifname=%s " - "uid=%d sk=%p dir=%d proto=%d bytes=%d)\n", + "uid=%u sk=%p dir=%d proto=%d bytes=%d)\n", ifname, uid, sk, direction, proto, bytes); iface_entry = get_iface_entry(ifname); if (!iface_entry) { - pr_err("qtaguid: iface_stat: interface %s not found\n", ifname); + pr_err("qtaguid: iface_stat: stat_update() %s not found\n", + ifname); return; } /* It is ok to process data when an iface_entry is inactive */ - MT_DEBUG("qtaguid: iface_stat: stat_update() got entry=%p\n", - iface_entry); + MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n", + ifname, iface_entry); /* * Look for a tagged sock. @@ -860,7 +874,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid, tag = combine_atag_with_uid(acct_tag, uid); } MT_DEBUG("qtaguid: iface_stat: stat_update(): " - " looking for tag=0x%llx (uid=%d) in ife=%p\n", + " looking for tag=0x%llx (uid=%u) in ife=%p\n", tag, get_uid_from_tag(tag), iface_entry); /* Loop over tag list under this interface for {acct_tag,uid_tag} */ spin_lock_bh(&iface_entry->tag_stat_list_lock); @@ -913,12 +927,6 @@ static int iface_netdev_event_handler(struct notifier_block *nb, switch (event) { case NETDEV_UP: - case NETDEV_REBOOT: - case NETDEV_CHANGE: - case NETDEV_REGISTER: /* Most likely no IP */ - case NETDEV_CHANGEADDR: /* MAC addr change */ - case NETDEV_CHANGENAME: - case NETDEV_FEAT_CHANGE: /* Might be usefull when cell type changes */ iface_stat_create(dev, NULL); break; case NETDEV_UNREGISTER: @@ -992,25 +1000,26 @@ static int __init iface_stat_init(struct proc_dir_entry *parent_procdir) iface_stat_procdir = proc_mkdir(iface_stat_procdirname, parent_procdir); if (!iface_stat_procdir) { - pr_err("qtaguid: iface_stat: failed to create proc entry\n"); + pr_err("qtaguid: iface_stat: init failed to create proc entry\n"); err = -1; goto err; } err = register_netdevice_notifier(&iface_netdev_notifier_blk); if (err) { - pr_err("qtaguid: iface_stat: failed to register dev event handler\n"); + pr_err("qtaguid: iface_stat: init " + "failed to register dev event handler\n"); goto err_zap_entry; } err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk); if (err) { - pr_err("qtaguid: iface_stat: " + pr_err("qtaguid: iface_stat: init " "failed to register ipv4 dev event handler\n"); goto err_unreg_nd; } err = register_inet6addr_notifier(&iface_inet6addr_notifier_blk); if (err) { - pr_err("qtaguid: iface_stat: " + pr_err("qtaguid: iface_stat: init " "failed to register ipv6 dev event handler\n"); goto err_unreg_ip4_addr; } @@ -1116,6 +1125,9 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) uid_t sock_uid; bool res; + if (unlikely(module_passive)) + return (info->match ^ info->invert) == 0; + MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n", par->hooknum, skb, par->in, par->out, par->family); @@ -1145,7 +1157,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par) par->hooknum, sk, sk->sk_socket, sk->sk_socket ? sk->sk_socket->file : (void *)-1LL); filp = sk->sk_socket ? sk->sk_socket->file : NULL; - MT_DEBUG("qtaguid[%d]: filp...uid=%d\n", + MT_DEBUG("qtaguid[%d]: filp...uid=%u\n", par->hooknum, filp ? filp->f_cred->fsuid : -1); } @@ -1254,12 +1266,13 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned, node = rb_next(node)) { if (item_index++ < items_to_skip) continue; - sock_tag_entry = rb_entry(node, struct sock_tag, node); + sock_tag_entry = rb_entry(node, struct sock_tag, sock_node); uid = get_uid_from_tag(sock_tag_entry->tag); - CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%d)\n", - sock_tag_entry->sk, - sock_tag_entry->tag, - uid); + CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u)\n", + sock_tag_entry->sk, + sock_tag_entry->tag, + uid + ); len = snprintf(outp, char_count, "sock=%p tag=0x%llx (uid=%u)\n", sock_tag_entry->sk, sock_tag_entry->tag, uid); @@ -1315,10 +1328,9 @@ static int ctrl_cmd_delete(const char *input) struct tag_stat *ts_entry; struct tag_counter_set *tcs_entry; - CT_DEBUG("qtaguid: ctrl_delete(%s): entered\n", input); argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid); CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c " - "acct_tag=0x%llx uid=%u\n", input, argc, cmd, + "user_tag=0x%llx uid=%u\n", input, argc, cmd, acct_tag, uid); if (argc < 2) { res = -EINVAL; @@ -1332,8 +1344,9 @@ static int ctrl_cmd_delete(const char *input) if (argc < 3) { uid = current_fsuid(); } else if (!can_impersonate_uid(uid)) { - pr_info("qtaguid: ctrl_delete(%s): insuficient priv\n", - input); + pr_info("qtaguid: ctrl_delete(%s): " + "insufficient priv from pid=%u uid=%u\n", + input, current->pid, current_fsuid()); res = -EPERM; goto err; } @@ -1342,7 +1355,7 @@ static int ctrl_cmd_delete(const char *input) spin_lock_bh(&sock_tag_list_lock); node = rb_first(&sock_tag_tree); while (node) { - st_entry = rb_entry(node, struct sock_tag, node); + st_entry = rb_entry(node, struct sock_tag, sock_node); entry_uid = get_uid_from_tag(st_entry->tag); node = rb_next(node); if (entry_uid != uid) @@ -1350,11 +1363,12 @@ static int ctrl_cmd_delete(const char *input) if (!acct_tag || st_entry->tag == tag) { CT_DEBUG("qtaguid: ctrl_delete(): " - "erase st: sk=%p tag=0x%llx (uid=%d)\n", + "erase st: sk=%p tag=0x%llx (uid=%u)\n", st_entry->sk, st_entry->tag, entry_uid); - rb_erase(&st_entry->node, &sock_tag_tree); + rb_erase(&st_entry->sock_node, &sock_tag_tree); + sockfd_put(st_entry->socket); kfree(st_entry); } } @@ -1367,7 +1381,7 @@ static int ctrl_cmd_delete(const char *input) tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag); if (tcs_entry) { CT_DEBUG("qtaguid: ctrl_delete(): " - "erase tcs: tag=0x%llx (uid=%d) set=%d\n", + "erase tcs: tag=0x%llx (uid=%u) set=%d\n", tcs_entry->tn.tag, get_uid_from_tag(tcs_entry->tn.tag), tcs_entry->active_set); @@ -1408,7 +1422,6 @@ static int ctrl_cmd_delete(const char *input) res = 0; err: - CT_DEBUG("qtaguid: ctrl_delete(%s) res=%d\n", input, res); return res; } @@ -1421,7 +1434,6 @@ static int ctrl_cmd_counter_set(const char *input) struct tag_counter_set *tcs; int counter_set; - CT_DEBUG("qtaguid: ctrl_counterset(%s): entered\n", input); argc = sscanf(input, "%c %d %u", &cmd, &counter_set, &uid); CT_DEBUG("qtaguid: ctrl_counterset(%s): argc=%d cmd=%c " "set=%d uid=%u\n", input, argc, cmd, @@ -1437,8 +1449,9 @@ static int ctrl_cmd_counter_set(const char *input) goto err; } if (!can_manipulate_uids()) { - pr_info("qtaguid: ctrl_counterset(%s): insufficient priv\n", - input); + pr_info("qtaguid: ctrl_counterset(%s): " + "insufficient priv from pid=%u uid=%u\n", + input, current->pid, current_fsuid()); res = -EPERM; goto err; } @@ -1459,7 +1472,7 @@ static int ctrl_cmd_counter_set(const char *input) tcs->tn.tag = tag; tag_counter_set_tree_insert(tcs, &tag_counter_set_tree); CT_DEBUG("qtaguid: ctrl_counterset(%s): added tcs tag=0x%llx " - "(uid=%d) set=%d\n", + "(uid=%u) set=%d\n", input, tag, get_uid_from_tag(tag), counter_set); } tcs->active_set = counter_set; @@ -1468,7 +1481,6 @@ static int ctrl_cmd_counter_set(const char *input) res = 0; err: - CT_DEBUG("qtaguid: ctrl_counterset(%s) res=%d\n", input, res); return res; } @@ -1479,6 +1491,7 @@ static int ctrl_cmd_tag(const char *input) uid_t uid = 0; tag_t acct_tag = 0; struct socket *el_socket; + int refcnt = -1; int res, argc; struct sock_tag *sock_tag_entry; @@ -1491,55 +1504,80 @@ static int ctrl_cmd_tag(const char *input) res = -EINVAL; goto err; } - el_socket = sockfd_lookup(sock_fd, &res); + el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */ if (!el_socket) { pr_info("qtaguid: ctrl_tag(%s): failed to lookup" " sock_fd=%d err=%d\n", input, sock_fd, res); goto err; } + refcnt = atomic_read(&el_socket->file->f_count); + CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%d\n", + input, refcnt); if (argc < 3) { acct_tag = 0; } else if (!valid_atag(acct_tag)) { pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input); res = -EINVAL; - goto err; - } + goto err_put; + } + CT_DEBUG("qtaguid: ctrl_tag(%s): " + "uid=%u euid=%u fsuid=%u " + "in_group=%d in_egroup=%d\n", + input, current_uid(), current_euid(), current_fsuid(), + in_group_p(proc_stats_readall_gid), + in_egroup_p(proc_stats_readall_gid)); if (argc < 4) { uid = current_fsuid(); } else if (!can_impersonate_uid(uid)) { - pr_info("qtaguid: ctrl_tag(%s): insuficient priv\n", - input); + pr_info("qtaguid: ctrl_tag(%s): " + "insufficient priv from pid=%u uid=%u\n", + input, current->pid, current_fsuid()); res = -EPERM; - goto err; + goto err_put; } spin_lock_bh(&sock_tag_list_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); if (sock_tag_entry) { + /* + * This is a re-tagging, so release the sock_fd that was + * locked at the time of the 1st tagging. + */ + sockfd_put(sock_tag_entry->socket); + refcnt--; sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid); } else { sock_tag_entry = kzalloc(sizeof(*sock_tag_entry), GFP_ATOMIC); if (!sock_tag_entry) { + pr_err("qtaguid: ctrl_tag(%s): " + "socket tag alloc failed\n", + input); + spin_unlock_bh(&sock_tag_list_lock); res = -ENOMEM; - goto err; + goto err_put; } sock_tag_entry->sk = el_socket->sk; + sock_tag_entry->socket = el_socket; sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid); sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree); } spin_unlock_bh(&sock_tag_list_lock); + /* We keep the ref to the socket (file) until it is untagged */ + CT_DEBUG("qtaguid: ctrl_tag(%s): done. socket->...->f_count=%d\n", + input, + el_socket ? atomic_read(&el_socket->file->f_count) : -1); + return 0; - CT_DEBUG("qtaguid: tag: sock_tag_entry->sk=%p " - "...->tag=0x%llx (uid=%u)\n", - sock_tag_entry->sk, sock_tag_entry->tag, - get_uid_from_tag(sock_tag_entry->tag)); - res = 0; - +err_put: + /* Release the sock_fd that was grabbed by sockfd_lookup(). */ + sockfd_put(el_socket); + refcnt--; err: - CT_DEBUG("qtaguid: ctrl_tag(%s) res=%d\n", input, res); + CT_DEBUG("qtaguid: ctrl_tag(%s): done. socket->...->f_count=%d\n", + input, refcnt); return res; } @@ -1548,10 +1586,10 @@ static int ctrl_cmd_untag(const char *input) char cmd; int sock_fd = 0; struct socket *el_socket; + int refcnt = -1; int res, argc; struct sock_tag *sock_tag_entry; - CT_DEBUG("qtaguid: ctrl_untag(%s): entered\n", input); argc = sscanf(input, "%c %d", &cmd, &sock_fd); CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n", input, argc, cmd, sock_fd); @@ -1559,28 +1597,49 @@ static int ctrl_cmd_untag(const char *input) res = -EINVAL; goto err; } - el_socket = sockfd_lookup(sock_fd, &res); + el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */ if (!el_socket) { pr_info("qtaguid: ctrl_untag(%s): failed to lookup" " sock_fd=%d err=%d\n", input, sock_fd, res); goto err; } + refcnt = atomic_read(&el_socket->file->f_count); + CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%d\n", + input, refcnt); spin_lock_bh(&sock_tag_list_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); if (!sock_tag_entry) { spin_unlock_bh(&sock_tag_list_lock); res = -EINVAL; - goto err; + goto err_put; } - /* The socket already belongs to the current process - * so it can do whatever it wants to it. */ - rb_erase(&sock_tag_entry->node, &sock_tag_tree); + /* + * The socket already belongs to the current process + * so it can do whatever it wants to it. + */ + rb_erase(&sock_tag_entry->sock_node, &sock_tag_tree); + + /* + * Release the sock_fd that was grabbed at tag time, + * and once more for the sockfd_lookup() here. + */ + sockfd_put(sock_tag_entry->socket); spin_unlock_bh(&sock_tag_list_lock); + sockfd_put(el_socket); + refcnt -= 2; kfree(sock_tag_entry); + CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n", + input, refcnt); - res = 0; + return 0; + +err_put: + /* Release the sock_fd that was grabbed by sockfd_lookup(). */ + sockfd_put(el_socket); + refcnt--; err: - CT_DEBUG("qtaguid: ctrl_untag(%s): res=%d\n", input, res); + CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n", + input, refcnt); return res; } @@ -1589,7 +1648,6 @@ static int qtaguid_ctrl_parse(const char *input, int count) char cmd; int res; - CT_DEBUG("qtaguid: ctrl(%s): entered\n", input); cmd = input[0]; /* Collect params for commands */ switch (cmd) { @@ -1667,10 +1725,12 @@ static int pp_stats_line(struct proc_print_info *ppi, int cnt_set) tag_t tag = ppi->ts_entry->tn.tag; uid_t stat_uid = get_uid_from_tag(tag); if (!can_read_other_uid_stats(stat_uid)) { - CT_DEBUG("qtaguid: insufficient priv for stat line:" - "%s 0x%llx %u\n", + CT_DEBUG("qtaguid: stats line: " + "%s 0x%llx %u: " + "insufficient priv from pid=%u uid=%u\n", ppi->iface_entry->ifname, - get_atag_from_tag(tag), stat_uid); + get_atag_from_tag(tag), stat_uid, + current->pid, current_fsuid()); return 0; } cnts = &ppi->ts_entry->counters; @@ -1748,8 +1808,11 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned, ppi.num_items_returned = num_items_returned; if (unlikely(module_passive)) { + len = pp_stats_line(&ppi, 0); + /* The header should always be shorter than the buffer. */ + WARN_ON(len >= ppi.char_count); *eof = 1; - return 0; + return len; } CT_DEBUG("qtaguid:proc stats page=%p *num_items_returned=%p off=%ld " -- cgit v1.2.3 From 8b404d162085c675989d7fb55c3f641fdfa11eec Mon Sep 17 00:00:00 2001 From: ECCO PARK Date: Thu, 18 Aug 2011 15:18:04 -0700 Subject: net: wireless: bcmdhd: Fix Softap initialization Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd.h | 7 ++++ drivers/net/wireless/bcmdhd/dhd_common.c | 57 ++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index ea8f67ce8b4..b0df6c77200 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -71,6 +71,12 @@ enum dhd_bus_state { DHD_BUS_DATA /* Ready for frame transfers */ }; +/* Firmware requested operation mode */ +#define STA_MASK 0x0001 +#define HOSTAPD_MASK 0x0002 +#define WFD_MASK 0x0004 +#define SOFTAP_FW_MASK 0x0008 + enum dhd_bus_wake_state { WAKE_LOCK_OFF, WAKE_LOCK_PRIV, @@ -173,6 +179,7 @@ typedef struct dhd_pub { wl_country_t dhd_cspec; /* Current Locale info */ char eventmask[WL_EVENTING_MASK_LEN]; + int op_mode; /* STA, HostAPD, WFD, SoftAP */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) struct wake_lock wakelock[WAKE_LOCK_MAX]; diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 2ad61868484..66d60420069 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -1535,7 +1535,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint bcn_timeout = 4; uint retry_max = 3; int arpoe = 1; - int arp_ol = 0xf; int scan_assoc_time = 40; int scan_unassoc_time = 40; const char *str; @@ -1552,7 +1551,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(SOFTAP) uint dtim = 1; #endif -#ifdef AP +#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ #endif /* AP */ #if defined(AP) || defined(WLP2P) @@ -1562,6 +1561,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ + dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE ret = dhd_custom_get_mac_address(ea_addr.octet); if (!ret) { @@ -1610,9 +1610,39 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* SET_RANDOM_MAC_SOFTAP */ - DHD_ERROR(("Firmware up: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2], - dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5])); +#if !defined(AP) && defined(WLP2P) + /* Check if firmware with WFD support used */ + if (strstr(fw_path, "_p2p") != NULL) { + bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, + iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret)); + } else { + dhd->op_mode |= WFD_MASK; + arpoe = 0; + } + } +#endif /* !defined(AP) && defined(WLP2P) */ + +#if !defined(AP) && defined(WL_CFG80211) + /* Check if firmware with HostAPD support used */ + if (strstr(fw_path, "_apsta") != NULL) { + /* Turn off MPC in AP mode */ + bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); + } else { + dhd->op_mode |= HOSTAPD_MASK; + arpoe = 0; + } + } +#endif /* !defined(AP) && defined(WL_CFG80211) */ + DHD_ERROR(("Firmware up: op_mode=%d, " + "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + dhd->op_mode, + dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2], + dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5])); /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { @@ -1655,16 +1685,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Setup assoc_retry_max count to reconnect target AP in dongle */ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#ifdef AP +#if defined(AP) && !defined(WLP2P) /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* AP */ -#if defined(AP) || defined(WLP2P) - /* Enable APSTA mode */ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* defined(AP) || defined(WLP2P) */ +#endif /* defined(AP) && !defined(WLP2P) */ #if defined(SOFTAP) if (ap_fw_loaded == TRUE) { dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); @@ -1727,12 +1754,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, sizeof(scan_unassoc_time), TRUE, 0); - /* Set ARP offload */ - bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* add a default packet filter pattern */ str = "pkt_filter_add"; str_len = strlen(str); @@ -1786,9 +1807,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef ARP_OFFLOAD_SUPPORT /* Set and enable ARP offload feature for STA only */ - if (dhd_arp_enable && !ap_fw_loaded) { + if (arpoe && !ap_fw_loaded) { dhd_arp_offload_set(dhd, dhd_arp_mode); - dhd_arp_offload_enable(dhd, dhd_arp_enable); + dhd_arp_offload_enable(dhd, arpoe); } else { dhd_arp_offload_set(dhd, 0); dhd_arp_offload_enable(dhd, FALSE); -- cgit v1.2.3 From efcf89c8eb62b7c0c5976cb94f892c891afea199 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 17 Aug 2011 18:31:58 -0500 Subject: panic: Add board ID to panic output At times, it is necessary for boards to provide some additional information as part of panic logs. Provide information on the board hardware as part of panic logs. It is safer to print this information at the very end in case something bad happens as part of the information retrieval itself. To use this, set global mach_panic_string to an appropriate string in the board file. Change-Id: Id12cdda87b0cd2940dd01d52db97e6162f671b4d Signed-off-by: Nishanth Menon --- include/linux/kernel.h | 3 +++ kernel/panic.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 953352a8833..47e8dbea85c 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -736,4 +736,7 @@ extern int __build_bug_on_failed; # define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD #endif +/* To identify board information in panic logs, set this */ +extern char *mach_panic_string; + #endif diff --git a/kernel/panic.c b/kernel/panic.c index 5578d0adc27..a136da2f396 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -27,6 +27,9 @@ #define PANIC_TIMER_STEP 100 #define PANIC_BLINK_SPD 18 +/* Machine specific panic information string */ +char *mach_panic_string; + int panic_on_oops; static unsigned long tainted_mask; static int pause_on_oops; @@ -345,6 +348,11 @@ late_initcall(init_oops_id); void print_oops_end_marker(void) { init_oops_id(); + + if (mach_panic_string) + printk(KERN_WARNING "Board Information: %s\n", + mach_panic_string); + printk(KERN_WARNING "---[ end trace %016llx ]---\n", (unsigned long long)oops_id); } -- cgit v1.2.3