lkml.org 
[lkml]   [2007]   [Aug]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    From
    SubjectKernel oops during netfilter memory allocation
    Date
    Hey there,

    I'm currently debugging a kernel oops with kernel 2.6.21.7 that occurs
    from time to time with our netfilter accounting module ipt_ACCOUNT
    (http://www.intra2net.com/de/produkte/opensource/ipt_account/).

    What basically happens is that the module allocates memory
    inside an interrupt handler like many other netfilter modules do.
    Except that it does it very often if you have a large, busy network.

    To me it looks like I found a bug in the kernel memory handler.
    I've written a minimalistic netfilter module ipt_CRASH that
    just allocates and frees memory to demonstrate the problem.

    Here's a screenshot of the oops:
    http://img231.imageshack.us/img231/9064/kerneloopsiptcrashzb1.jpg

    Another shot of it with a "tainted" kernel:
    http://img529.imageshack.us/img529/6681/kerneloopsey1.jpg

    I would have included the backtrace as text, but unfortunately
    the USB serial console dies before it outputs anything useful.

    You need a fast machine with lots of RAM to reproduce it, I used a 3 Ghz
    machine with 3 GB of RAM. ipt_CRASH allocates and frees memory for every
    packet, a packet generator like "sendip" might help:
    http://www.earth.li/projectpurple/progs/sendip.html

    The machine dies after 15-30 minutes or as soon as I try to reboot it.

    Please CC: answers, I'm only on netfilter-devel.

    Thanks in advance,
    Thomas
    [unhandled content-type:application/x-shellscript]/* Shared library add-on to iptables to add CRASH support.
    Author: Intra2net AG <opensource@intra2net.com>
    Licensed under the GPL v2.
    */

    #include <stdio.h>
    #include <netdb.h>
    #include <string.h>
    #include <stdlib.h>
    #include <syslog.h>
    #include <getopt.h>
    #include <iptables.h>
    #include <linux/netfilter_ipv4/ip_tables.h>
    #include <linux/netfilter_ipv4/ipt_CRASH.h>

    static struct option opts[] = {
    { .name = 0 }
    };

    /* Function which prints out usage message. */
    static void help(void)
    {
    printf(
    "CRASH v%s options:\n", IPTABLES_VERSION);
    }

    /* Initialize the target. */
    static void
    init(struct ipt_entry_target *t, unsigned int *nfcache)
    {
    /* Can't cache this */
    *nfcache |= NFC_UNKNOWN;
    }

    /* Function which parses command options; returns true if it
    ate an option */
    static int
    parse(int c, char **argv, int invert, unsigned int *flags,
    const struct ipt_entry *entry,
    struct ipt_entry_target **target)
    {
    return 0;
    }

    /* Final check; nothing. */
    static void final_check(unsigned int flags)
    {
    }

    static void print_it(const struct ipt_ip *ip,
    const struct ipt_entry_target *target, char do_prefix)
    {
    if (!do_prefix)
    printf("CRASH ");
    }

    /* Prints out the targinfo. */
    static void
    print(const struct ipt_ip *ip,
    const struct ipt_entry_target *target,
    int numeric)
    {
    print_it (ip, target, 0);
    }

    /* Saves the union ipt_targinfo in parsable form to stdout. */
    static void
    save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
    {
    print_it(ip, target, 1);
    }

    static
    struct iptables_target crash
    = {
    .next = NULL,
    .name = "CRASH",
    .version = IPTABLES_VERSION,
    .size = IPT_ALIGN(sizeof(struct ipt_crash_info)),
    .userspacesize = IPT_ALIGN(sizeof(struct ipt_crash_info)),
    .help = &help,
    .init = &init,
    .parse = &parse,
    .final_check = &final_check,
    .print = &print,
    .save = &save,
    .extra_opts = opts
    };

    void _init(void)
    {
    register_target(&crash);
    }
    /***************************************************************************
    * Copyright (C) 2007 by Intra2net AG *
    * opensource@intra2net.com *
    * *
    * This program is free software; you can redistribute it and/or modify *
    * it under the terms of the GNU General Public License *
    * version 2 as published by the Free Software Foundation; *
    * *
    ***************************************************************************/

    #include <linux/module.h>
    #include <linux/version.h>
    #include <linux/skbuff.h>
    #include <linux/ip.h>
    #include <net/icmp.h>
    #include <net/udp.h>
    #include <net/tcp.h>
    #include <linux/netfilter_ipv4/ip_tables.h>
    #include <linux/netfilter_ipv4/ipt_CRASH.h>
    #include <asm/semaphore.h>
    #include <linux/kernel.h>
    #include <linux/mm.h>
    #include <linux/string.h>
    #include <linux/spinlock.h>
    #include <asm/uaccess.h>

    /* Spinlock used during memory allocation */
    static DEFINE_SPINLOCK(ipt_crash_lock);

    static unsigned int ipt_crash_target(struct sk_buff **pskb,
    const struct net_device *in,
    const struct net_device *out,
    unsigned int hooknum,
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
    const struct xt_target *target,
    #endif
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
    const void *targinfo)
    #else
    const void *targinfo,
    void *userinfo)
    #endif
    {
    char *data;

    spin_lock_bh(&ipt_crash_lock);

    if ((data = (char *)get_zeroed_page(GFP_ATOMIC)) == NULL) {
    printk("ipt_CRASH: Out of memory!\n");
    } else {
    // Fill memory with pattern
    int i, j = 123;
    for (i = 0; i < PAGE_SIZE; i++) {
    data[i] = j;
    j++;
    }

    free_page((unsigned long)data);
    }

    spin_unlock_bh(&ipt_crash_lock);

    return IPT_CONTINUE;
    }

    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
    static struct xt_target xt_crash_reg = {
    #else
    static struct ipt_target ipt_crash_reg = {
    #endif
    .name = "CRASH",
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
    .family = AF_INET,
    #endif
    .target = ipt_crash_target,
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
    .targetsize = sizeof(struct ipt_crash_info),
    #endif
    .me = THIS_MODULE
    };

    static int __init init(void)
    {
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
    if (xt_register_target(&xt_crash_reg))
    #else
    if (ipt_register_target(&ipt_crash_reg))
    #endif
    return -EINVAL;

    return 0;
    }

    static void __exit fini(void)
    {
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
    xt_unregister_target(&xt_crash_reg);
    #else
    ipt_unregister_target(&ipt_crash_reg);
    #endif
    }

    module_init(init);
    module_exit(fini);
    MODULE_LICENSE("GPL");
    /***************************************************************************
    * Copyright (C) 2004-2005 by Intra2net AG *
    * opensource@intra2net.com *
    * *
    * This program is free software; you can redistribute it and/or modify *
    * it under the terms of the GNU General Public License *
    * version 2 as published by the Free Software Foundation; *
    * *
    ***************************************************************************/

    #ifndef _IPT_CRASH_H
    #define _IPT_CRASH_H

    /* Structure for the userspace part of ipt_CRASH */
    struct ipt_crash_info {
    };

    #endif /*_IPT_CRASH_H*/
    \
     
     \ /
      Last update: 2007-08-20 18:57    [W:0.031 / U:89.912 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site