aboutsummaryrefslogtreecommitdiffstats
path: root/main/linux-grsec
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2009-08-31 07:35:42 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2009-08-31 08:29:35 +0000
commitfd16ce4706d108cc9e35140095edaa28394396aa (patch)
treeaaa04b8e25b25aa64dee13ea85f7cecf866233b0 /main/linux-grsec
parent8bdd83b2b95988041898a40d9476832c049fb8ad (diff)
downloadaports-fd16ce4706d108cc9e35140095edaa28394396aa.tar.bz2
aports-fd16ce4706d108cc9e35140095edaa28394396aa.tar.xz
main/*-grsec: updated grsec kernel to 200908281917
Diffstat (limited to 'main/linux-grsec')
-rw-r--r--main/linux-grsec/APKBUILD9
-rw-r--r--main/linux-grsec/grsecurity-2.1.14-2.6.30.5-200908281917.patch (renamed from main/linux-grsec/grsecurity-2.1.14-2.6.30.5-200908261614.patch)137
-rw-r--r--main/linux-grsec/linux-nbma-mroute-v4-2.6.30.diff258
3 files changed, 131 insertions, 273 deletions
diff --git a/main/linux-grsec/APKBUILD b/main/linux-grsec/APKBUILD
index caac111b88..9543b34651 100644
--- a/main/linux-grsec/APKBUILD
+++ b/main/linux-grsec/APKBUILD
@@ -4,7 +4,7 @@ _flavor=grsec
pkgname=linux-${_flavor}
pkgver=2.6.30.5
_kernver=2.6.30
-pkgrel=0
+pkgrel=1
pkgdesc="Linux kernel with grsecurity"
url=http://grsecurity.net
depends="mkinitfs"
@@ -13,8 +13,7 @@ _config=${config:-kernelconfig}
install="$pkgname.post-install $pkgname.post-upgrade"
source="ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-$_kernver.tar.bz2
ftp://ftp.kernel.org/pub/linux/kernel/v2.6/patch-$pkgver.bz2
- grsecurity-2.1.14-2.6.30.5-200908261614.patch
- linux-nbma-mroute-v4-2.6.30.diff
+ grsecurity-2.1.14-2.6.30.5-200908281917.patch
net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch
$_config
"
@@ -30,6 +29,7 @@ _prepare() {
fi
for i in ../*.diff ../*.patch; do
+ [ -f $i ] || continue
msg "Applying $i..."
patch -p1 -N < $i || return 1
done
@@ -112,7 +112,6 @@ dev() {
md5sums="7a80058a6382e5108cdb5554d1609615 linux-2.6.30.tar.bz2
47841c7ff5c81a7b349a79f2fa8e9138 patch-2.6.30.5.bz2
-a725c0779f365787127c71810877586d grsecurity-2.1.14-2.6.30.5-200908261614.patch
-7420c0b1095335990313656b114e1379 linux-nbma-mroute-v4-2.6.30.diff
+dee5a6292fb12018eb3bd3d014f89407 grsecurity-2.1.14-2.6.30.5-200908281917.patch
ca05fd252783b82e01610e775cf56498 net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch
ede34b2613f54cf1eae8f37a61d0e085 kernelconfig"
diff --git a/main/linux-grsec/grsecurity-2.1.14-2.6.30.5-200908261614.patch b/main/linux-grsec/grsecurity-2.1.14-2.6.30.5-200908281917.patch
index f653790e89..cc232fbe5d 100644
--- a/main/linux-grsec/grsecurity-2.1.14-2.6.30.5-200908261614.patch
+++ b/main/linux-grsec/grsecurity-2.1.14-2.6.30.5-200908281917.patch
@@ -2937,7 +2937,7 @@ diff -urNp linux-2.6.30.5/arch/sparc/Makefile linux-2.6.30.5/arch/sparc/Makefile
diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_32.c linux-2.6.30.5/arch/sparc/mm/fault_32.c
--- linux-2.6.30.5/arch/sparc/mm/fault_32.c 2009-07-24 17:47:51.000000000 -0400
-+++ linux-2.6.30.5/arch/sparc/mm/fault_32.c 2009-07-30 09:48:09.913853340 -0400
++++ linux-2.6.30.5/arch/sparc/mm/fault_32.c 2009-08-27 21:11:25.299108429 -0400
@@ -21,6 +21,9 @@
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -2948,7 +2948,7 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_32.c linux-2.6.30.5/arch/sparc/mm/
#include <asm/system.h>
#include <asm/page.h>
-@@ -167,6 +170,249 @@ static unsigned long compute_si_addr(str
+@@ -167,6 +170,264 @@ static unsigned long compute_si_addr(str
return safe_compute_effective_address(regs, insn);
}
@@ -3150,6 +3150,21 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_32.c linux-2.6.30.5/arch/sparc/mm/
+ regs->npc = addr+4;
+ return 3;
+ }
++
++ /* PaX: newer glibc/binutils generate sethi/jmp instead of save/call */
++ if ((save & 0xFFC00000U) == 0x05000000U &&
++ (call & 0xFFFFE000U) == 0x85C0A000U &&
++ nop == 0x01000000U)
++ {
++ unsigned long addr;
++
++ addr = (save & 0x003FFFFFU) << 10;
++ regs->u_regs[UREG_G2] = addr;
++ addr += (((call | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U);
++ regs->pc = addr;
++ regs->npc = addr+4;
++ return 3;
++ }
+ }
+ } while (0);
+
@@ -3198,7 +3213,7 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_32.c linux-2.6.30.5/arch/sparc/mm/
asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address)
{
-@@ -231,6 +477,24 @@ good_area:
+@@ -231,6 +492,24 @@ good_area:
if(!(vma->vm_flags & VM_WRITE))
goto bad_area;
} else {
@@ -3225,7 +3240,7 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_32.c linux-2.6.30.5/arch/sparc/mm/
goto bad_area;
diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/fault_64.c
--- linux-2.6.30.5/arch/sparc/mm/fault_64.c 2009-07-24 17:47:51.000000000 -0400
-+++ linux-2.6.30.5/arch/sparc/mm/fault_64.c 2009-07-30 09:48:09.913853340 -0400
++++ linux-2.6.30.5/arch/sparc/mm/fault_64.c 2009-08-27 21:11:25.310208001 -0400
@@ -20,6 +20,9 @@
#include <linux/kprobes.h>
#include <linux/kdebug.h>
@@ -3236,7 +3251,7 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
#include <asm/page.h>
#include <asm/pgtable.h>
-@@ -249,6 +252,367 @@ static void noinline bogus_32bit_fault_a
+@@ -249,6 +252,404 @@ static void noinline bogus_32bit_fault_a
show_regs(regs);
}
@@ -3320,6 +3335,10 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
+ regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10;
+ addr = regs->u_regs[UREG_G1];
+ addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL);
++
++ if (test_thread_flag(TIF_32BIT))
++ addr &= 0xFFFFFFFFUL;
++
+ regs->tpc = addr;
+ regs->tnpc = addr+4;
+ return 2;
@@ -3335,6 +3354,10 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
+ unsigned long addr;
+
+ addr = regs->tpc + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2);
++
++ if (test_thread_flag(TIF_32BIT))
++ addr &= 0xFFFFFFFFUL;
++
+ regs->tpc = addr;
+ regs->tnpc = addr+4;
+ return 2;
@@ -3360,6 +3383,10 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
+ addr = (sethi & 0x003FFFFFU) << 10;
+ regs->u_regs[UREG_G1] = addr;
+ addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL);
++
++ if (test_thread_flag(TIF_32BIT))
++ addr &= 0xFFFFFFFFUL;
++
+ regs->tpc = addr;
+ regs->tnpc = addr+4;
+ return 2;
@@ -3503,6 +3530,9 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
+ else
+ addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2);
+
++ if (test_thread_flag(TIF_32BIT))
++ addr &= 0xFFFFFFFFUL;
++
+ err = get_user(save, (unsigned int *)addr);
+ err |= get_user(call, (unsigned int *)(addr+4));
+ err |= get_user(nop, (unsigned int *)(addr+8));
@@ -3556,6 +3586,25 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
+ regs->tnpc = addr+4;
+ return 3;
+ }
++
++ /* PaX: newer glibc/binutils generate sethi/jmp instead of save/call */
++ if ((save & 0xFFC00000U) == 0x05000000U &&
++ (call & 0xFFFFE000U) == 0x85C0A000U &&
++ nop == 0x01000000U)
++ {
++ unsigned long addr;
++
++ addr = (save & 0x003FFFFFU) << 10;
++ regs->u_regs[UREG_G2] = addr;
++ addr += (((call | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL);
++
++ if (test_thread_flag(TIF_32BIT))
++ addr &= 0xFFFFFFFFUL;
++
++ regs->tpc = addr;
++ regs->tnpc = addr+4;
++ return 3;
++ }
+ }
+ } while (0);
+
@@ -3574,6 +3623,9 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
+ {
+ unsigned long dl_resolve = regs->tpc + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2);
+
++ if (test_thread_flag(TIF_32BIT))
++ dl_resolve &= 0xFFFFFFFFUL;
++
+ regs->u_regs[UREG_RETPC] = regs->tpc;
+ regs->tpc = dl_resolve;
+ regs->tnpc = dl_resolve+4;
@@ -3604,7 +3656,7 @@ diff -urNp linux-2.6.30.5/arch/sparc/mm/fault_64.c linux-2.6.30.5/arch/sparc/mm/
asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
{
struct mm_struct *mm = current->mm;
-@@ -315,6 +679,29 @@ asmlinkage void __kprobes do_sparc64_fau
+@@ -315,6 +716,29 @@ asmlinkage void __kprobes do_sparc64_fau
if (!vma)
goto bad_area;
@@ -11293,7 +11345,7 @@ diff -urNp linux-2.6.30.5/arch/x86/kernel/vmi_32.c linux-2.6.30.5/arch/x86/kerne
* to convert VMI_IRET to a call instead of a jump; so we have
diff -urNp linux-2.6.30.5/arch/x86/kernel/vmlinux_32.lds.S linux-2.6.30.5/arch/x86/kernel/vmlinux_32.lds.S
--- linux-2.6.30.5/arch/x86/kernel/vmlinux_32.lds.S 2009-07-24 17:47:51.000000000 -0400
-+++ linux-2.6.30.5/arch/x86/kernel/vmlinux_32.lds.S 2009-07-30 09:48:09.962543704 -0400
++++ linux-2.6.30.5/arch/x86/kernel/vmlinux_32.lds.S 2009-08-27 21:11:25.322527521 -0400
@@ -15,6 +15,20 @@
#include <asm/page_types.h>
#include <asm/cache.h>
@@ -11523,7 +11575,7 @@ diff -urNp linux-2.6.30.5/arch/x86/kernel/vmlinux_32.lds.S linux-2.6.30.5/arch/x
+ .module.text : AT(ADDR(.module.text) - LOAD_OFFSET) {
+ MODULES_VADDR = .;
+ BYTE(0)
-+ . += (6 * 1024 * 1024);
++ . += (8 * 1024 * 1024);
+ . = ALIGN(PMD_SIZE);
+ MODULES_END = . - 1;
+ }
@@ -40886,7 +40938,7 @@ diff -urNp linux-2.6.30.5/mm/memory.c linux-2.6.30.5/mm/memory.c
* Dumping its contents makes post-mortem fully interpretable later
diff -urNp linux-2.6.30.5/mm/mempolicy.c linux-2.6.30.5/mm/mempolicy.c
--- linux-2.6.30.5/mm/mempolicy.c 2009-07-24 17:47:51.000000000 -0400
-+++ linux-2.6.30.5/mm/mempolicy.c 2009-07-30 09:48:10.145161384 -0400
++++ linux-2.6.30.5/mm/mempolicy.c 2009-08-28 19:17:19.665274493 -0400
@@ -551,6 +551,10 @@ static int mbind_range(struct vm_area_st
struct vm_area_struct *next;
int err;
@@ -40933,7 +40985,32 @@ diff -urNp linux-2.6.30.5/mm/mempolicy.c linux-2.6.30.5/mm/mempolicy.c
if (end == start)
return 0;
-@@ -2290,7 +2315,7 @@ int show_numa_map(struct seq_file *m, vo
+@@ -1142,6 +1167,14 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pi
+ if (!mm)
+ return -EINVAL;
+
++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
++ if (mm != current->mm &&
++ (mm->pax_flags & MF_PAX_RANDMMAP || mm->pax_flags & MF_PAX_SEGMEXEC)) {
++ err = -EPERM;
++ goto out;
++ }
++#endif
++
+ /*
+ * Check if this process has the right to modify the specified
+ * process. The right exists if the process has administrative
+@@ -1151,8 +1184,7 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pi
+ rcu_read_lock();
+ tcred = __task_cred(task);
+ if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
+- cred->uid != tcred->suid && cred->uid != tcred->uid &&
+- !capable(CAP_SYS_NICE)) {
++ cred->uid != tcred->suid && !capable(CAP_SYS_NICE)) {
+ rcu_read_unlock();
+ err = -EPERM;
+ goto out;
+@@ -2290,7 +2322,7 @@ int show_numa_map(struct seq_file *m, vo
if (file) {
seq_printf(m, " file=");
@@ -40942,6 +41019,34 @@ diff -urNp linux-2.6.30.5/mm/mempolicy.c linux-2.6.30.5/mm/mempolicy.c
} else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
seq_printf(m, " heap");
} else if (vma->vm_start <= mm->start_stack &&
+diff -urNp linux-2.6.30.5/mm/migrate.c linux-2.6.30.5/mm/migrate.c
+--- linux-2.6.30.5/mm/migrate.c 2009-07-24 17:47:51.000000000 -0400
++++ linux-2.6.30.5/mm/migrate.c 2009-08-28 19:16:52.585127596 -0400
+@@ -1085,6 +1085,14 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid,
+ if (!mm)
+ return -EINVAL;
+
++#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP
++ if (mm != current->mm &&
++ (mm->pax_flags & MF_PAX_RANDMMAP || mm->pax_flags & MF_PAX_SEGMEXEC)) {
++ err = -EPERM;
++ goto out;
++ }
++#endif
++
+ /*
+ * Check if this process has the right to modify the specified
+ * process. The right exists if the process has administrative
+@@ -1094,8 +1102,7 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid,
+ rcu_read_lock();
+ tcred = __task_cred(task);
+ if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
+- cred->uid != tcred->suid && cred->uid != tcred->uid &&
+- !capable(CAP_SYS_NICE)) {
++ cred->uid != tcred->suid && !capable(CAP_SYS_NICE)) {
+ rcu_read_unlock();
+ err = -EPERM;
+ goto out;
diff -urNp linux-2.6.30.5/mm/mlock.c linux-2.6.30.5/mm/mlock.c
--- linux-2.6.30.5/mm/mlock.c 2009-07-24 17:47:51.000000000 -0400
+++ linux-2.6.30.5/mm/mlock.c 2009-07-30 11:10:49.799565380 -0400
@@ -43474,6 +43579,18 @@ diff -urNp linux-2.6.30.5/net/ipv4/inet_hashtables.c linux-2.6.30.5/net/ipv4/ine
if (tw) {
inet_twsk_deschedule(tw, death_row);
inet_twsk_put(tw);
+diff -urNp linux-2.6.30.5/net/ipv4/ip_output.c linux-2.6.30.5/net/ipv4/ip_output.c
+--- linux-2.6.30.5/net/ipv4/ip_output.c 2009-07-24 17:47:51.000000000 -0400
++++ linux-2.6.30.5/net/ipv4/ip_output.c 2009-08-28 18:54:39.383265912 -0400
+@@ -814,6 +814,8 @@ int ip_append_data(struct sock *sk,
+ inet->cork.addr = ipc->addr;
+ }
+ rt = *rtp;
++ if (unlikely(rt == NULL))
++ return -EFAULT;
+ /*
+ * We steal reference to this route, caller should not release it
+ */
diff -urNp linux-2.6.30.5/net/ipv4/netfilter/nf_nat_snmp_basic.c linux-2.6.30.5/net/ipv4/netfilter/nf_nat_snmp_basic.c
--- linux-2.6.30.5/net/ipv4/netfilter/nf_nat_snmp_basic.c 2009-07-24 17:47:51.000000000 -0400
+++ linux-2.6.30.5/net/ipv4/netfilter/nf_nat_snmp_basic.c 2009-07-30 09:48:10.155784268 -0400
diff --git a/main/linux-grsec/linux-nbma-mroute-v4-2.6.30.diff b/main/linux-grsec/linux-nbma-mroute-v4-2.6.30.diff
deleted file mode 100644
index 636d807a53..0000000000
--- a/main/linux-grsec/linux-nbma-mroute-v4-2.6.30.diff
+++ /dev/null
@@ -1,258 +0,0 @@
-diff --git a/include/linux/mroute.h b/include/linux/mroute.h
-index 0d45b4e..406ef6f 100644
---- a/include/linux/mroute.h
-+++ b/include/linux/mroute.h
-@@ -33,7 +33,7 @@
- #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1)
- #define SIOCGETRPF (SIOCPROTOPRIVATE+2)
-
--#define MAXVIFS 32
-+#define MAXVIFS 256
- typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */
- typedef unsigned short vifi_t;
- #define ALL_VIFS ((vifi_t)(-1))
-@@ -66,6 +66,7 @@ struct vifctl {
- #define VIFF_TUNNEL 0x1 /* IPIP tunnel */
- #define VIFF_SRCRT 0x2 /* NI */
- #define VIFF_REGISTER 0x4 /* register vif */
-+#define VIFF_NBMA 0x10
-
- /*
- * Cache manipulation structures for mrouted and PIMd
-diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
-index 13e9dd3..43c988b 100644
---- a/net/ipv4/ipmr.c
-+++ b/net/ipv4/ipmr.c
-@@ -105,6 +105,31 @@ static struct net_protocol pim_protocol;
-
- static struct timer_list ipmr_expire_timer;
-
-+static __be32 ipmr_get_skb_nbma(struct sk_buff *skb)
-+{
-+ union {
-+ char addr[MAX_ADDR_LEN];
-+ __be32 inaddr;
-+ } u;
-+
-+ if (dev_parse_header(skb, u.addr) != 4)
-+ return INADDR_ANY;
-+
-+ return u.inaddr;
-+}
-+
-+static int ip_mr_match_vif_skb(struct vif_device *vif, struct sk_buff *skb)
-+{
-+ if (vif->dev != skb->dev)
-+ return 0;
-+
-+ if (vif->flags & VIFF_NBMA)
-+ return ipmr_get_skb_nbma(skb) == vif->remote;
-+
-+ return 1;
-+}
-+
-+
- /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
-
- static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
-@@ -470,6 +495,7 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
- return err;
- }
- break;
-+ case VIFF_NBMA:
- case 0:
- dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
- if (!dev)
-@@ -504,7 +530,7 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
- v->pkt_in = 0;
- v->pkt_out = 0;
- v->link = dev->ifindex;
-- if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
-+ if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER|VIFF_NBMA))
- v->link = dev->iflink;
-
- /* And finish update writing critical data */
-@@ -1212,12 +1238,15 @@ static inline int ipmr_forward_finish(struct sk_buff *skb)
- {
- struct ip_options * opt = &(IPCB(skb)->opt);
-
-- IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
-+ IP_INC_STATS_BH(dev_net(skb->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
-
- if (unlikely(opt->optlen))
- ip_forward_options(skb);
-
-- return dst_output(skb);
-+ if (skb->dst != NULL)
-+ return dst_output(skb);
-+ else
-+ return dev_queue_xmit(skb);
- }
-
- /*
-@@ -1230,7 +1259,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
- const struct iphdr *iph = ip_hdr(skb);
- struct vif_device *vif = &net->ipv4.vif_table[vifi];
- struct net_device *dev;
-- struct rtable *rt;
-+ struct net_device *fromdev = skb->dev;
-+ struct rtable *rt = NULL;
- int encap = 0;
-
- if (vif->dev == NULL)
-@@ -1257,6 +1287,19 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
- if (ip_route_output_key(net, &rt, &fl))
- goto out_free;
- encap = sizeof(struct iphdr);
-+ dev = rt->u.dst.dev;
-+ } else if (vif->flags&VIFF_NBMA) {
-+ /* Fixme, we should take tunnel source address from the
-+ * tunnel device binding if it exists */
-+ struct flowi fl = { .oif = vif->link,
-+ .nl_u = { .ip4_u =
-+ { .daddr = vif->remote,
-+ .tos = RT_TOS(iph->tos) } },
-+ .proto = IPPROTO_GRE };
-+ if (ip_route_output_key(&init_net, &rt, &fl))
-+ goto out_free;
-+ encap = LL_RESERVED_SPACE(rt->u.dst.dev);
-+ dev = vif->dev;
- } else {
- struct flowi fl = { .oif = vif->link,
- .nl_u = { .ip4_u =
-@@ -1265,34 +1308,39 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
- .proto = IPPROTO_IPIP };
- if (ip_route_output_key(net, &rt, &fl))
- goto out_free;
-+ dev = rt->u.dst.dev;
- }
-
-- dev = rt->u.dst.dev;
-+ if (!(vif->flags & VIFF_NBMA)) {
-+ if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
-+ /* Do not fragment multicasts. Alas, IPv4 does not
-+ allow to send ICMP, so that packets will disappear
-+ to blackhole.
-+ */
-
-- if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
-- /* Do not fragment multicasts. Alas, IPv4 does not
-- allow to send ICMP, so that packets will disappear
-- to blackhole.
-- */
--
-- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
-- ip_rt_put(rt);
-- goto out_free;
-+ IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
-+ goto out_free_rt;
-+ }
- }
-
- encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
-
-- if (skb_cow(skb, encap)) {
-- ip_rt_put(rt);
-- goto out_free;
-- }
-+ if (skb_cow(skb, encap))
-+ goto out_free_rt;
-
- vif->pkt_out++;
- vif->bytes_out += skb->len;
-
- dst_release(skb->dst);
-- skb->dst = &rt->u.dst;
-+ if (vif->flags & VIFF_NBMA) {
-+ ip_rt_put(rt);
-+ skb->dst = NULL;
-+ rt = NULL;
-+ } else {
-+ skb->dst = &rt->u.dst;
-+ }
- ip_decrease_ttl(ip_hdr(skb));
-+ skb->dev = dev;
-
- /* FIXME: forward and output firewalls used to be called here.
- * What do we do with netfilter? -- RR */
-@@ -1301,6 +1349,10 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
- /* FIXME: extra output firewall step used to be here. --RR */
- vif->dev->stats.tx_packets++;
- vif->dev->stats.tx_bytes += skb->len;
-+ } else if (vif->flags & VIFF_NBMA) {
-+ if (dev_hard_header(skb, dev, ntohs(skb->protocol),
-+ &vif->remote, NULL, 4) < 0)
-+ goto out_free_rt;
- }
-
- IPCB(skb)->flags |= IPSKB_FORWARDED;
-@@ -1316,21 +1368,30 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
- * not mrouter) cannot join to more than one interface - it will
- * result in receiving multiple packets.
- */
-- NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
-+ NF_HOOK(PF_INET, NF_INET_FORWARD, skb, fromdev, dev,
- ipmr_forward_finish);
- return;
-
-+out_free_rt:
-+ if (rt != NULL)
-+ ip_rt_put(rt);
- out_free:
- kfree_skb(skb);
- return;
- }
-
--static int ipmr_find_vif(struct net_device *dev)
-+static int ipmr_find_vif(struct net_device *dev, __be32 nbma_origin)
- {
- struct net *net = dev_net(dev);
- int ct;
- for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
-- if (net->ipv4.vif_table[ct].dev == dev)
-+ if (net->ipv4.vif_table[ct].dev != dev)
-+ continue;
-+
-+ if (net->ipv4.vif_table[ct].flags & VIFF_NBMA) {
-+ if (net->ipv4.vif_table[ct].remote == nbma_origin)
-+ break;
-+ } else if (nbma_origin == INADDR_ANY)
- break;
- }
- return ct;
-@@ -1351,7 +1412,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
- /*
- * Wrong interface: drop packet and (maybe) send PIM assert.
- */
-- if (net->ipv4.vif_table[vif].dev != skb->dev) {
-+ if (!ip_mr_match_vif_skb(&net->ipv4.vif_table[vif], skb)) {
- int true_vifi;
-
- if (skb->rtable->fl.iif == 0) {
-@@ -1370,7 +1431,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
- }
-
- cache->mfc_un.res.wrong_if++;
-- true_vifi = ipmr_find_vif(skb->dev);
-+ true_vifi = ipmr_find_vif(skb->dev, ipmr_get_skb_nbma(skb));
-
- if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
- /* pimsm uses asserts, when switching from RPT to SPT,
-@@ -1479,7 +1540,7 @@ int ip_mr_input(struct sk_buff *skb)
- skb = skb2;
- }
-
-- vif = ipmr_find_vif(skb->dev);
-+ vif = ipmr_find_vif(skb->dev, ipmr_get_skb_nbma(skb));
- if (vif >= 0) {
- int err = ipmr_cache_unresolved(net, vif, skb);
- read_unlock(&mrt_lock);
-@@ -1663,7 +1724,7 @@ int ipmr_get_route(struct net *net,
- }
-
- dev = skb->dev;
-- if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
-+ if (dev == NULL || (vif = ipmr_find_vif(dev, INADDR_ANY)) < 0) {
- read_unlock(&mrt_lock);
- return -ENODEV;
- }