aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2006-08-31 17:52:17 -0400
committerDavid S. Miller <davem@davemloft.net>2006-08-31 17:52:17 -0400
commit99c7bc0133b875280fdd2bf78e4ffbd58cc609e3 (patch)
treebf66fa8252c23145730e6efceffe19af4c7b002c /net
parentdd1a47c21ee4f4f682285ad9d4624d2cec436f93 (diff)
[IPV6]: Fix kernel OOPs when setting sticky socket options.
Bug noticed by Remi Denis-Courmont <rdenis@simphalempin.com>. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/exthdrs.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 9d0ee7f0eeb5..86dac106873b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -635,14 +635,17 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
635 struct ipv6_txoptions *opt2; 635 struct ipv6_txoptions *opt2;
636 int err; 636 int err;
637 637
638 if (newtype != IPV6_HOPOPTS && opt->hopopt) 638 if (opt) {
639 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); 639 if (newtype != IPV6_HOPOPTS && opt->hopopt)
640 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) 640 tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
641 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); 641 if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
642 if (newtype != IPV6_RTHDR && opt->srcrt) 642 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
643 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); 643 if (newtype != IPV6_RTHDR && opt->srcrt)
644 if (newtype != IPV6_DSTOPTS && opt->dst1opt) 644 tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
645 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); 645 if (newtype != IPV6_DSTOPTS && opt->dst1opt)
646 tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
647 }
648
646 if (newopt && newoptlen) 649 if (newopt && newoptlen)
647 tot_len += CMSG_ALIGN(newoptlen); 650 tot_len += CMSG_ALIGN(newoptlen);
648 651
@@ -659,25 +662,25 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
659 opt2->tot_len = tot_len; 662 opt2->tot_len = tot_len;
660 p = (char *)(opt2 + 1); 663 p = (char *)(opt2 + 1);
661 664
662 err = ipv6_renew_option(opt->hopopt, newopt, newoptlen, 665 err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,
663 newtype != IPV6_HOPOPTS, 666 newtype != IPV6_HOPOPTS,
664 &opt2->hopopt, &p); 667 &opt2->hopopt, &p);
665 if (err) 668 if (err)
666 goto out; 669 goto out;
667 670
668 err = ipv6_renew_option(opt->dst0opt, newopt, newoptlen, 671 err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,
669 newtype != IPV6_RTHDRDSTOPTS, 672 newtype != IPV6_RTHDRDSTOPTS,
670 &opt2->dst0opt, &p); 673 &opt2->dst0opt, &p);
671 if (err) 674 if (err)
672 goto out; 675 goto out;
673 676
674 err = ipv6_renew_option(opt->srcrt, newopt, newoptlen, 677 err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,
675 newtype != IPV6_RTHDR, 678 newtype != IPV6_RTHDR,
676 (struct ipv6_opt_hdr **)opt2->srcrt, &p); 679 (struct ipv6_opt_hdr **)&opt2->srcrt, &p);
677 if (err) 680 if (err)
678 goto out; 681 goto out;
679 682
680 err = ipv6_renew_option(opt->dst1opt, newopt, newoptlen, 683 err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,
681 newtype != IPV6_DSTOPTS, 684 newtype != IPV6_DSTOPTS,
682 &opt2->dst1opt, &p); 685 &opt2->dst1opt, &p);
683 if (err) 686 if (err)
_raw_read_lock); #endif #ifndef CONFIG_INLINE_READ_LOCK_IRQSAVE unsigned long __lockfunc _raw_read_lock_irqsave(rwlock_t *lock) { return __raw_read_lock_irqsave(lock); } EXPORT_SYMBOL(_raw_read_lock_irqsave); #endif #ifndef CONFIG_INLINE_READ_LOCK_IRQ void __lockfunc _raw_read_lock_irq(rwlock_t *lock) { __raw_read_lock_irq(lock); } EXPORT_SYMBOL(_raw_read_lock_irq); #endif #ifndef CONFIG_INLINE_READ_LOCK_BH void __lockfunc _raw_read_lock_bh(rwlock_t *lock) { __raw_read_lock_bh(lock); } EXPORT_SYMBOL(_raw_read_lock_bh); #endif #ifndef CONFIG_INLINE_READ_UNLOCK void __lockfunc _raw_read_unlock(rwlock_t *lock) { __raw_read_unlock(lock); } EXPORT_SYMBOL(_raw_read_unlock); #endif #ifndef CONFIG_INLINE_READ_UNLOCK_IRQRESTORE void __lockfunc _raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { __raw_read_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_raw_read_unlock_irqrestore); #endif #ifndef CONFIG_INLINE_READ_UNLOCK_IRQ void __lockfunc _raw_read_unlock_irq(rwlock_t *lock) { __raw_read_unlock_irq(lock); } EXPORT_SYMBOL(_raw_read_unlock_irq); #endif #ifndef CONFIG_INLINE_READ_UNLOCK_BH void __lockfunc _raw_read_unlock_bh(rwlock_t *lock) { __raw_read_unlock_bh(lock); } EXPORT_SYMBOL(_raw_read_unlock_bh); #endif #ifndef CONFIG_INLINE_WRITE_TRYLOCK int __lockfunc _raw_write_trylock(rwlock_t *lock) { return __raw_write_trylock(lock); } EXPORT_SYMBOL(_raw_write_trylock); #endif #ifndef CONFIG_INLINE_WRITE_LOCK void __lockfunc _raw_write_lock(rwlock_t *lock) { __raw_write_lock(lock); } EXPORT_SYMBOL(_raw_write_lock); #endif #ifndef CONFIG_INLINE_WRITE_LOCK_IRQSAVE unsigned long __lockfunc _raw_write_lock_irqsave(rwlock_t *lock) { return __raw_write_lock_irqsave(lock); } EXPORT_SYMBOL(_raw_write_lock_irqsave); #endif #ifndef CONFIG_INLINE_WRITE_LOCK_IRQ void __lockfunc _raw_write_lock_irq(rwlock_t *lock) { __raw_write_lock_irq(lock); } EXPORT_SYMBOL(_raw_write_lock_irq); #endif #ifndef CONFIG_INLINE_WRITE_LOCK_BH void __lockfunc _raw_write_lock_bh(rwlock_t *lock) { __raw_write_lock_bh(lock); } EXPORT_SYMBOL(_raw_write_lock_bh); #endif #ifndef CONFIG_INLINE_WRITE_UNLOCK void __lockfunc _raw_write_unlock(rwlock_t *lock) { __raw_write_unlock(lock); } EXPORT_SYMBOL(_raw_write_unlock); #endif #ifndef CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE void __lockfunc _raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) { __raw_write_unlock_irqrestore(lock, flags); } EXPORT_SYMBOL(_raw_write_unlock_irqrestore); #endif #ifndef CONFIG_INLINE_WRITE_UNLOCK_IRQ void __lockfunc _raw_write_unlock_irq(rwlock_t *lock) { __raw_write_unlock_irq(lock); } EXPORT_SYMBOL(_raw_write_unlock_irq); #endif #ifndef CONFIG_INLINE_WRITE_UNLOCK_BH void __lockfunc _raw_write_unlock_bh(rwlock_t *lock) { __raw_write_unlock_bh(lock); } EXPORT_SYMBOL(_raw_write_unlock_bh); #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC void __lockfunc _raw_spin_lock_nested(raw_spinlock_t *lock, int subclass) { preempt_disable(); spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); } EXPORT_SYMBOL(_raw_spin_lock_nested); unsigned long __lockfunc _raw_spin_lock_irqsave_nested(raw_spinlock_t *lock, int subclass) { unsigned long flags; local_irq_save(flags); preempt_disable(); spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_); LOCK_CONTENDED_FLAGS(lock, do_raw_spin_trylock, do_raw_spin_lock, do_raw_spin_lock_flags, &flags); return flags; } EXPORT_SYMBOL(_raw_spin_lock_irqsave_nested); void __lockfunc _raw_spin_lock_nest_lock(raw_spinlock_t *lock, struct lockdep_map *nest_lock) { preempt_disable(); spin_acquire_nest(&lock->dep_map, 0, 0, nest_lock, _RET_IP_); LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); } EXPORT_SYMBOL(_raw_spin_lock_nest_lock); #endif notrace int in_lock_functions(unsigned long addr) { /* Linker adds these: start and end of __lockfunc functions */ extern char __lock_text_start[], __lock_text_end[]; return addr >= (unsigned long)__lock_text_start && addr < (unsigned long)__lock_text_end; } EXPORT_SYMBOL(in_lock_functions);