diff --git a/[refs] b/[refs] index 34117b6c0190..fe881896e569 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 7e4720201ad44ace85a443f41d668a62a737e7d0 +refs/heads/master: c32a8fd7cb33f30bcd855188dc8e243b144c5cee diff --git a/trunk/Documentation/networking/dccp.txt b/trunk/Documentation/networking/dccp.txt index 74563b38ffd9..c45daabd3bfe 100644 --- a/trunk/Documentation/networking/dccp.txt +++ b/trunk/Documentation/networking/dccp.txt @@ -1,6 +1,7 @@ DCCP protocol ============ +Last updated: 10 November 2005 Contents ======== @@ -41,11 +42,8 @@ Socket options DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for calculations. -DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of -service codes (RFC 4340, sec. 8.1.2); if this socket option is not set, -the socket will fall back to 0 (which means that no meaningful service code -is present). Connecting sockets set at most one service option; for -listening sockets, multiple service codes can be specified. +DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the +specification. If you don't set it you will get EPROTO. Notes ===== diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 23348c0d37bc..16af51ba44a5 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2031,13 +2031,6 @@ L: netfilter@lists.netfilter.org L: netfilter-devel@lists.netfilter.org S: Supported -NETLABEL -P: Paul Moore -M: paul.moore@hp.com -W: http://netlabel.sf.net -L: netdev@vger.kernel.org -S: Supported - NETROM NETWORK LAYER P: Ralf Baechle M: ralf@linux-mips.org diff --git a/trunk/arch/i386/kernel/smpboot.c b/trunk/arch/i386/kernel/smpboot.c index efe07990e7fc..f948419c888a 100644 --- a/trunk/arch/i386/kernel/smpboot.c +++ b/trunk/arch/i386/kernel/smpboot.c @@ -642,13 +642,9 @@ static void map_cpu_to_logical_apicid(void) { int cpu = smp_processor_id(); int apicid = logical_smp_processor_id(); - int node = apicid_to_node(apicid); - - if (!node_online(node)) - node = first_online_node; cpu_2_logical_apicid[cpu] = apicid; - map_cpu_to_node(cpu, node); + map_cpu_to_node(cpu, apicid_to_node(apicid)); } static void unmap_cpu_to_logical_apicid(int cpu) diff --git a/trunk/arch/i386/mm/boot_ioremap.c b/trunk/arch/i386/mm/boot_ioremap.c index 4de11f508c3a..5d44f4f5ff59 100644 --- a/trunk/arch/i386/mm/boot_ioremap.c +++ b/trunk/arch/i386/mm/boot_ioremap.c @@ -29,11 +29,8 @@ */ #define BOOT_PTE_PTRS (PTRS_PER_PTE*2) - -static unsigned long boot_pte_index(unsigned long vaddr) -{ - return __pa(vaddr) >> PAGE_SHIFT; -} +#define boot_pte_index(address) \ + (((address) >> PAGE_SHIFT) & (BOOT_PTE_PTRS - 1)) static inline boot_pte_t* boot_vaddr_to_pte(void *address) { diff --git a/trunk/arch/ia64/kernel/acpi.c b/trunk/arch/ia64/kernel/acpi.c index 32c3abededc6..0176556aeecc 100644 --- a/trunk/arch/ia64/kernel/acpi.c +++ b/trunk/arch/ia64/kernel/acpi.c @@ -771,19 +771,16 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, long physid) { #ifdef CONFIG_ACPI_NUMA int pxm_id; - int nid; pxm_id = acpi_get_pxm(handle); + /* - * We don't have cpu-only-node hotadd. But if the system equips - * SRAT table, pxm is already found and node is ready. - * So, just pxm_to_nid(pxm) is OK. - * This code here is for the system which doesn't have full SRAT - * table for possible cpus. + * Assuming that the container driver would have set the proximity + * domain and would have initialized pxm_to_node(pxm_id) && pxm_flag */ - nid = acpi_map_pxm_to_node(pxm_id); + node_cpuid[cpu].nid = (pxm_id < 0) ? 0 : pxm_to_node(pxm_id); + node_cpuid[cpu].phys_id = physid; - node_cpuid[cpu].nid = nid; #endif return (0); } diff --git a/trunk/arch/ia64/kernel/numa.c b/trunk/arch/ia64/kernel/numa.c index 20340631179f..1cc360c83e7a 100644 --- a/trunk/arch/ia64/kernel/numa.c +++ b/trunk/arch/ia64/kernel/numa.c @@ -29,36 +29,6 @@ EXPORT_SYMBOL(cpu_to_node_map); cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; -void __cpuinit map_cpu_to_node(int cpu, int nid) -{ - int oldnid; - if (nid < 0) { /* just initialize by zero */ - cpu_to_node_map[cpu] = 0; - return; - } - /* sanity check first */ - oldnid = cpu_to_node_map[cpu]; - if (cpu_isset(cpu, node_to_cpu_mask[oldnid])) { - return; /* nothing to do */ - } - /* we don't have cpu-driven node hot add yet... - In usual case, node is created from SRAT at boot time. */ - if (!node_online(nid)) - nid = first_online_node; - cpu_to_node_map[cpu] = nid; - cpu_set(cpu, node_to_cpu_mask[nid]); - return; -} - -void __cpuinit unmap_cpu_from_node(int cpu, int nid) -{ - WARN_ON(!cpu_isset(cpu, node_to_cpu_mask[nid])); - WARN_ON(cpu_to_node_map[cpu] != nid); - cpu_to_node_map[cpu] = 0; - cpu_clear(cpu, node_to_cpu_mask[nid]); -} - - /** * build_cpu_to_node_map - setup cpu to node and node to cpumask arrays * @@ -79,6 +49,8 @@ void __init build_cpu_to_node_map(void) node = node_cpuid[i].nid; break; } - map_cpu_to_node(cpu, node); + cpu_to_node_map[cpu] = (node >= 0) ? node : 0; + if (node >= 0) + cpu_set(cpu, node_to_cpu_mask[node]); } } diff --git a/trunk/arch/ia64/kernel/topology.c b/trunk/arch/ia64/kernel/topology.c index 05bdf7affb43..f648c610b10c 100644 --- a/trunk/arch/ia64/kernel/topology.c +++ b/trunk/arch/ia64/kernel/topology.c @@ -36,9 +36,6 @@ int arch_register_cpu(int num) */ if (!can_cpei_retarget() && is_cpu_cpei_target(num)) sysfs_cpus[num].cpu.no_control = 1; -#ifdef CONFIG_NUMA - map_cpu_to_node(num, node_cpuid[num].nid); -#endif #endif return register_cpu(&sysfs_cpus[num].cpu, num); @@ -48,8 +45,7 @@ int arch_register_cpu(int num) void arch_unregister_cpu(int num) { - unregister_cpu(&sysfs_cpus[num].cpu); - unmap_cpu_from_node(num, cpu_to_node(num)); + return unregister_cpu(&sysfs_cpus[num].cpu); } EXPORT_SYMBOL(arch_register_cpu); EXPORT_SYMBOL(arch_unregister_cpu); diff --git a/trunk/arch/sparc64/solaris/misc.c b/trunk/arch/sparc64/solaris/misc.c index 642541769a17..8135ec322c9c 100644 --- a/trunk/arch/sparc64/solaris/misc.c +++ b/trunk/arch/sparc64/solaris/misc.c @@ -736,15 +736,20 @@ struct exec_domain solaris_exec_domain = { extern int init_socksys(void); +#ifdef MODULE + MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)"); MODULE_DESCRIPTION("Solaris binary emulation module"); MODULE_LICENSE("GPL"); +#ifdef __sparc_v9__ extern u32 tl0_solaris[8]; #define update_ttable(x) \ tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000; \ wmb(); \ __asm__ __volatile__ ("flush %0" : : "r" (&tl0_solaris[3])) +#else +#endif extern u32 solaris_sparc_syscall[]; extern u32 solaris_syscall[]; @@ -752,7 +757,7 @@ extern void cleanup_socksys(void); extern u32 entry64_personality_patch; -static int __init solaris_init(void) +int init_module(void) { int ret; @@ -772,12 +777,19 @@ static int __init solaris_init(void) return 0; } -static void __exit solaris_exit(void) +void cleanup_module(void) { update_ttable(solaris_syscall); cleanup_socksys(); unregister_exec_domain(&solaris_exec_domain); } -module_init(solaris_init); -module_exit(solaris_exit); +#else +int init_solaris_emul(void) +{ + register_exec_domain(&solaris_exec_domain); + init_socksys(); + return 0; +} +#endif + diff --git a/trunk/arch/sparc64/solaris/socksys.c b/trunk/arch/sparc64/solaris/socksys.c index 7c90e41fd3be..bc3df95bc057 100644 --- a/trunk/arch/sparc64/solaris/socksys.c +++ b/trunk/arch/sparc64/solaris/socksys.c @@ -168,7 +168,8 @@ static struct file_operations socksys_fops = { .release = socksys_release, }; -int __init init_socksys(void) +int __init +init_socksys(void) { int ret; struct file * file; @@ -198,7 +199,8 @@ int __init init_socksys(void) return 0; } -void __exit cleanup_socksys(void) +void +cleanup_socksys(void) { if (unregister_chrdev(30, "socksys")) printk ("Couldn't unregister socksys character device\n"); diff --git a/trunk/drivers/ata/ata_piix.c b/trunk/drivers/ata/ata_piix.c index ab2ecccf7798..ffa111eea9da 100644 --- a/trunk/drivers/ata/ata_piix.c +++ b/trunk/drivers/ata/ata_piix.c @@ -851,7 +851,7 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) * @ap: Port whose timings we are configuring * @adev: Drive in question * @udma: udma mode, 0 - 6 - * @is_ich: set if the chip is an ICH device + * @isich: set if the chip is an ICH device * * Set UDMA mode for device, in host controller PCI config space. * diff --git a/trunk/drivers/atm/he.c b/trunk/drivers/atm/he.c index f2511b42dba2..41e052fecd7f 100644 --- a/trunk/drivers/atm/he.c +++ b/trunk/drivers/atm/he.c @@ -454,7 +454,7 @@ rate_to_atmf(unsigned rate) /* cps to atm forum format */ return (NONZERO | (exp << 9) | (rate & 0x1ff)); } -static void __devinit +static void __init he_init_rx_lbfp0(struct he_dev *he_dev) { unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; @@ -485,7 +485,7 @@ he_init_rx_lbfp0(struct he_dev *he_dev) he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); } -static void __devinit +static void __init he_init_rx_lbfp1(struct he_dev *he_dev) { unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; @@ -516,7 +516,7 @@ he_init_rx_lbfp1(struct he_dev *he_dev) he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); } -static void __devinit +static void __init he_init_tx_lbfp(struct he_dev *he_dev) { unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; @@ -546,7 +546,7 @@ he_init_tx_lbfp(struct he_dev *he_dev) he_writel(he_dev, lbufd_index - 1, TLBF_T); } -static int __devinit +static int __init he_init_tpdrq(struct he_dev *he_dev) { he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev, @@ -568,7 +568,7 @@ he_init_tpdrq(struct he_dev *he_dev) return 0; } -static void __devinit +static void __init he_init_cs_block(struct he_dev *he_dev) { unsigned clock, rate, delta; @@ -664,7 +664,7 @@ he_init_cs_block(struct he_dev *he_dev) } -static int __devinit +static int __init he_init_cs_block_rcm(struct he_dev *he_dev) { unsigned (*rategrid)[16][16]; @@ -785,7 +785,7 @@ he_init_cs_block_rcm(struct he_dev *he_dev) return 0; } -static int __devinit +static int __init he_init_group(struct he_dev *he_dev, int group) { int i; @@ -955,7 +955,7 @@ he_init_group(struct he_dev *he_dev, int group) return 0; } -static int __devinit +static int __init he_init_irq(struct he_dev *he_dev) { int i; diff --git a/trunk/drivers/char/rtc.c b/trunk/drivers/char/rtc.c index ab6429b4a84e..6e6a7c7a7eff 100644 --- a/trunk/drivers/char/rtc.c +++ b/trunk/drivers/char/rtc.c @@ -209,12 +209,11 @@ static const unsigned char days_in_mo[] = */ static inline unsigned char rtc_is_updating(void) { - unsigned long flags; unsigned char uip; - spin_lock_irqsave(&rtc_lock, flags); + spin_lock_irq(&rtc_lock); uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irqrestore(&rtc_lock, flags); + spin_unlock_irq(&rtc_lock); return uip; } diff --git a/trunk/drivers/media/video/videodev.c b/trunk/drivers/media/video/videodev.c index edd7b83c3464..88bf2af2a0e7 100644 --- a/trunk/drivers/media/video/videodev.c +++ b/trunk/drivers/media/video/videodev.c @@ -836,7 +836,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; } - if (index < 0 || index >= vfd->tvnormsize) { + if (index<=0 || index >= vfd->tvnormsize) { ret=-EINVAL; break; } diff --git a/trunk/drivers/net/sunlance.c b/trunk/drivers/net/sunlance.c index feb42db10ee1..77670741e101 100644 --- a/trunk/drivers/net/sunlance.c +++ b/trunk/drivers/net/sunlance.c @@ -1323,9 +1323,9 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = { .get_link = sparc_lance_get_link, }; -static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, - struct sbus_dma *ledma, - struct sbus_dev *lebuffer) +static int __init sparc_lance_probe_one(struct sbus_dev *sdev, + struct sbus_dma *ledma, + struct sbus_dev *lebuffer) { static unsigned version_printed; struct net_device *dev; @@ -1515,7 +1515,7 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev, } /* On 4m, find the associated dma for the lance chip */ -static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev) +static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev) { struct sbus_dma *p; @@ -1533,7 +1533,7 @@ static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev) /* Find all the lance cards on the system and initialize them */ static struct sbus_dev sun4_sdev; -static int __devinit sparc_lance_init(void) +static int __init sparc_lance_init(void) { if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) || (idprom->id_machtype == (SM_SUN4|SM_4_470))) { diff --git a/trunk/drivers/video/fbsysfs.c b/trunk/drivers/video/fbsysfs.c index c151dcf68786..4f78f234473d 100644 --- a/trunk/drivers/video/fbsysfs.c +++ b/trunk/drivers/video/fbsysfs.c @@ -397,12 +397,6 @@ static ssize_t store_bl_curve(struct class_device *class_device, u8 tmp_curve[FB_BACKLIGHT_LEVELS]; unsigned int i; - /* Some drivers don't use framebuffer_alloc(), but those also - * don't have backlights. - */ - if (!fb_info || !fb_info->bl_dev) - return -ENODEV; - if (count != (FB_BACKLIGHT_LEVELS / 8 * 24)) return -EINVAL; @@ -436,12 +430,6 @@ static ssize_t show_bl_curve(struct class_device *class_device, char *buf) ssize_t len = 0; unsigned int i; - /* Some drivers don't use framebuffer_alloc(), but those also - * don't have backlights. - */ - if (!fb_info || !fb_info->bl_dev) - return -ENODEV; - mutex_lock(&fb_info->bl_mutex); for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) len += snprintf(&buf[len], PAGE_SIZE, diff --git a/trunk/fs/autofs4/expire.c b/trunk/fs/autofs4/expire.c index d96e5c14a9ca..8dbd44f10e9d 100644 --- a/trunk/fs/autofs4/expire.c +++ b/trunk/fs/autofs4/expire.c @@ -32,7 +32,7 @@ static inline int autofs4_can_expire(struct dentry *dentry, if (!do_now) { /* Too young to die */ - if (!timeout || time_after(ino->last_used + timeout, now)) + if (time_after(ino->last_used + timeout, now)) return 0; /* update last_used here :- @@ -253,7 +253,7 @@ static struct dentry *autofs4_expire_direct(struct super_block *sb, struct dentry *root = dget(sb->s_root); int do_now = how & AUTOFS_EXP_IMMEDIATE; - if (!root) + if (!sbi->exp_timeout || !root) return NULL; now = jiffies; @@ -293,7 +293,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb, int do_now = how & AUTOFS_EXP_IMMEDIATE; int exp_leaves = how & AUTOFS_EXP_LEAVES; - if (!root) + if ( !sbi->exp_timeout || !root ) return NULL; now = jiffies; diff --git a/trunk/include/asm-ia64/numa.h b/trunk/include/asm-ia64/numa.h index e0a1d173e42d..e5a8260593a5 100644 --- a/trunk/include/asm-ia64/numa.h +++ b/trunk/include/asm-ia64/numa.h @@ -64,10 +64,6 @@ extern int paddr_to_nid(unsigned long paddr); #define local_nodeid (cpu_to_node_map[smp_processor_id()]) -extern void map_cpu_to_node(int cpu, int nid); -extern void unmap_cpu_from_node(int cpu, int nid); - - #else /* !CONFIG_NUMA */ #define paddr_to_nid(addr) 0 diff --git a/trunk/include/linux/dccp.h b/trunk/include/linux/dccp.h index d6f4ec467a4b..2d7671c92c0b 100644 --- a/trunk/include/linux/dccp.h +++ b/trunk/include/linux/dccp.h @@ -169,12 +169,6 @@ enum { DCCPO_MAX_CCID_SPECIFIC = 255, }; -/* DCCP CCIDS */ -enum { - DCCPC_CCID2 = 2, - DCCPC_CCID3 = 3, -}; - /* DCCP features */ enum { DCCPF_RESERVED = 0, @@ -326,7 +320,7 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) /* initial values for each feature */ #define DCCPF_INITIAL_SEQUENCE_WINDOW 100 #define DCCPF_INITIAL_ACK_RATIO 2 -#define DCCPF_INITIAL_CCID DCCPC_CCID2 +#define DCCPF_INITIAL_CCID 2 #define DCCPF_INITIAL_SEND_ACK_VECTOR 1 /* FIXME: for now we're default to 1 but it should really be 0 */ #define DCCPF_INITIAL_SEND_NDP_COUNT 1 @@ -410,7 +404,6 @@ struct dccp_service_list { }; #define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1) -#define DCCP_SERVICE_CODE_IS_ABSENT 0 static inline int dccp_list_has_service(const struct dccp_service_list *sl, const __be32 service) @@ -491,6 +484,11 @@ static inline struct dccp_minisock *dccp_msk(const struct sock *sk) return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock; } +static inline int dccp_service_not_initialized(const struct sock *sk) +{ + return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE; +} + static inline const char *dccp_role(const struct sock *sk) { switch (dccp_sk(sk)->dccps_role) { diff --git a/trunk/include/linux/netfilter/Kbuild b/trunk/include/linux/netfilter/Kbuild index 312bd2ffee33..9a285cecf249 100644 --- a/trunk/include/linux/netfilter/Kbuild +++ b/trunk/include/linux/netfilter/Kbuild @@ -10,8 +10,6 @@ header-y += xt_connmark.h header-y += xt_CONNMARK.h header-y += xt_conntrack.h header-y += xt_dccp.h -header-y += xt_dscp.h -header-y += xt_DSCP.h header-y += xt_esp.h header-y += xt_helper.h header-y += xt_length.h diff --git a/trunk/include/net/cipso_ipv4.h b/trunk/include/net/cipso_ipv4.h index 2d72496c2029..59406e0dc5b2 100644 --- a/trunk/include/net/cipso_ipv4.h +++ b/trunk/include/net/cipso_ipv4.h @@ -130,9 +130,8 @@ extern int cipso_v4_rbm_strictvalid; int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head)); struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); -int cipso_v4_doi_walk(u32 *skip_cnt, - int (*callback) (struct cipso_v4_doi *doi_def, void *arg), - void *cb_arg); +struct sk_buff *cipso_v4_doi_dump_all(size_t headroom); +struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom); int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain); int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, const char *domain); @@ -153,11 +152,14 @@ static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) return NULL; } -static inline int cipso_v4_doi_walk(u32 *skip_cnt, - int (*callback) (struct cipso_v4_doi *doi_def, void *arg), - void *cb_arg) +static inline struct sk_buff *cipso_v4_doi_dump_all(size_t headroom) { - return 0; + return NULL; +} + +static inline struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom) +{ + return NULL; } static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, @@ -203,7 +205,6 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); int cipso_v4_socket_setattr(const struct socket *sock, const struct cipso_v4_doi *doi_def, const struct netlbl_lsm_secattr *secattr); -int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); int cipso_v4_socket_getattr(const struct socket *sock, struct netlbl_lsm_secattr *secattr); int cipso_v4_skbuff_getattr(const struct sk_buff *skb, @@ -224,12 +225,6 @@ static inline int cipso_v4_socket_setattr(const struct socket *sock, return -ENOSYS; } -static inline int cipso_v4_sock_getattr(struct sock *sk, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - static inline int cipso_v4_socket_getattr(const struct socket *sock, struct netlbl_lsm_secattr *secattr) { diff --git a/trunk/include/net/netlabel.h b/trunk/include/net/netlabel.h index 6692430063fd..dd5780b36919 100644 --- a/trunk/include/net/netlabel.h +++ b/trunk/include/net/netlabel.h @@ -57,8 +57,9 @@ * The payload is dependent on the subsystem specified in the * 'nlmsghdr->nlmsg_type' and should be defined below, supporting functions * should be defined in the corresponding net/netlabel/netlabel_.h|c - * file. All of the fields in the NetLabel payload are NETLINK attributes, see - * the include/net/netlink.h file for more information on NETLINK attributes. + * file. All of the fields in the NetLabel payload are NETLINK attributes, the + * length of each field is the length of the NETLINK attribute payload, see + * include/net/netlink.h for more information on NETLINK attributes. * */ @@ -81,6 +82,50 @@ #define NETLBL_NLTYPE_UNLABELED 5 #define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" +/* NetLabel return codes */ +#define NETLBL_E_OK 0 + +/* + * Helper functions + */ + +#define NETLBL_LEN_U8 nla_total_size(sizeof(u8)) +#define NETLBL_LEN_U16 nla_total_size(sizeof(u16)) +#define NETLBL_LEN_U32 nla_total_size(sizeof(u32)) + +/** + * netlbl_netlink_alloc_skb - Allocate a NETLINK message buffer + * @head: the amount of headroom in bytes + * @body: the desired size (minus headroom) in bytes + * @gfp_flags: the alloc flags to pass to alloc_skb() + * + * Description: + * Allocate a NETLINK message buffer based on the sizes given in @head and + * @body. If @head is greater than zero skb_reserve() is called to reserve + * @head bytes at the start of the buffer. Returns a valid sk_buff pointer on + * success, NULL on failure. + * + */ +static inline struct sk_buff *netlbl_netlink_alloc_skb(size_t head, + size_t body, + gfp_t gfp_flags) +{ + struct sk_buff *skb; + + skb = alloc_skb(NLMSG_ALIGN(head + body), gfp_flags); + if (skb == NULL) + return NULL; + if (head > 0) { + skb_reserve(skb, head); + if (skb_tailroom(skb) < body) { + kfree_skb(skb); + return NULL; + } + } + + return skb; +} + /* * NetLabel - Kernel API for accessing the network packet label mappings. * @@ -193,8 +238,6 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr, #ifdef CONFIG_NETLABEL int netlbl_socket_setattr(const struct socket *sock, const struct netlbl_lsm_secattr *secattr); -int netlbl_sock_getattr(struct sock *sk, - struct netlbl_lsm_secattr *secattr); int netlbl_socket_getattr(const struct socket *sock, struct netlbl_lsm_secattr *secattr); int netlbl_skbuff_getattr(const struct sk_buff *skb, @@ -207,12 +250,6 @@ static inline int netlbl_socket_setattr(const struct socket *sock, return -ENOSYS; } -static inline int netlbl_sock_getattr(struct sock *sk, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - static inline int netlbl_socket_getattr(const struct socket *sock, struct netlbl_lsm_secattr *secattr) { diff --git a/trunk/include/net/netlink.h b/trunk/include/net/netlink.h index 4ab68a7a636a..11dc2e7f679a 100644 --- a/trunk/include/net/netlink.h +++ b/trunk/include/net/netlink.h @@ -146,13 +146,11 @@ * nla_ok(nla, remaining) does nla fit into remaining bytes? * nla_next(nla, remaining) get next netlink attribute * nla_validate() validate a stream of attributes - * nla_validate_nested() validate a stream of nested attributes * nla_find() find attribute in stream of attributes * nla_find_nested() find attribute in nested attributes * nla_parse() parse and validate stream of attrs * nla_parse_nested() parse nested attribuets * nla_for_each_attr() loop over all attributes - * nla_for_each_nested() loop over the nested attributes *========================================================================= */ @@ -951,24 +949,6 @@ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) return nlmsg_trim(skb, start); } -/** - * nla_validate_nested - Validate a stream of nested attributes - * @start: container attribute - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - * - * Validates all attributes in the nested attribute stream against the - * specified policy. Attributes with a type exceeding maxtype will be - * ignored. See documenation of struct nla_policy for more details. - * - * Returns 0 on success or a negative error code. - */ -static inline int nla_validate_nested(struct nlattr *start, int maxtype, - struct nla_policy *policy) -{ - return nla_validate(nla_data(start), nla_len(start), maxtype, policy); -} - /** * nla_for_each_attr - iterate over a stream of attributes * @pos: loop counter, set to current attribute diff --git a/trunk/kernel/module.c b/trunk/kernel/module.c index b7fe6e840963..2a19cd47c046 100644 --- a/trunk/kernel/module.c +++ b/trunk/kernel/module.c @@ -1054,12 +1054,6 @@ static int mod_sysfs_setup(struct module *mod, { int err; - if (!module_subsys.kset.subsys) { - printk(KERN_ERR "%s: module_subsys not initialized\n", - mod->name); - err = -EINVAL; - goto out; - } memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name); if (err) diff --git a/trunk/mm/page_alloc.c b/trunk/mm/page_alloc.c index 8a52ba9fe693..3b5358a0561f 100644 --- a/trunk/mm/page_alloc.c +++ b/trunk/mm/page_alloc.c @@ -1845,10 +1845,8 @@ static inline void free_zone_pagesets(int cpu) for_each_zone(zone) { struct per_cpu_pageset *pset = zone_pcp(zone, cpu); - /* Free per_cpu_pageset if it is slab allocated */ - if (pset != &boot_pageset[cpu]) - kfree(pset); zone_pcp(zone, cpu) = NULL; + kfree(pset); } } diff --git a/trunk/net/dccp/Kconfig b/trunk/net/dccp/Kconfig index e2a095d0fd80..859e3359fcda 100644 --- a/trunk/net/dccp/Kconfig +++ b/trunk/net/dccp/Kconfig @@ -40,22 +40,6 @@ config IP_DCCP_DEBUG Just say N. -config NET_DCCPPROBE - tristate "DCCP connection probing" - depends on PROC_FS && KPROBES - ---help--- - This module allows for capturing the changes to DCCP connection - state in response to incoming packets. It is used for debugging - DCCP congestion avoidance modules. If you don't understand - what was just said, you don't need it: say N. - - Documentation on how to use the packet generator can be found - at http://linux-net.osdl.org/index.php/DccpProbe - - To compile this code as a module, choose M here: the - module will be called dccp_probe. - - endmenu endmenu diff --git a/trunk/net/dccp/Makefile b/trunk/net/dccp/Makefile index 17ed99c46617..7696e219b05d 100644 --- a/trunk/net/dccp/Makefile +++ b/trunk/net/dccp/Makefile @@ -11,11 +11,9 @@ dccp_ipv4-y := ipv4.o dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o -obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o dccp-$(CONFIG_SYSCTL) += sysctl.o dccp_diag-y := diag.o -dccp_probe-y := probe.o obj-y += ccids/ diff --git a/trunk/net/dccp/ccids/ccid2.c b/trunk/net/dccp/ccids/ccid2.c index 2efb505aeb35..457dd3db7f41 100644 --- a/trunk/net/dccp/ccids/ccid2.c +++ b/trunk/net/dccp/ccids/ccid2.c @@ -808,7 +808,7 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) } static struct ccid_operations ccid2 = { - .ccid_id = DCCPC_CCID2, + .ccid_id = 2, .ccid_name = "ccid2", .ccid_owner = THIS_MODULE, .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), diff --git a/trunk/net/dccp/ccids/ccid3.c b/trunk/net/dccp/ccids/ccid3.c index 67d2dc0e7c67..195aa9566228 100644 --- a/trunk/net/dccp/ccids/ccid3.c +++ b/trunk/net/dccp/ccids/ccid3.c @@ -1240,7 +1240,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, } static struct ccid_operations ccid3 = { - .ccid_id = DCCPC_CCID3, + .ccid_id = 3, .ccid_name = "ccid3", .ccid_owner = THIS_MODULE, .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock), diff --git a/trunk/net/dccp/ipv4.c b/trunk/net/dccp/ipv4.c index 66be29b6f508..9a1a76a7dc41 100644 --- a/trunk/net/dccp/ipv4.c +++ b/trunk/net/dccp/ipv4.c @@ -56,6 +56,9 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) dp->dccps_role = DCCP_ROLE_CLIENT; + if (dccp_service_not_initialized(sk)) + return -EPROTO; + if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; diff --git a/trunk/net/dccp/probe.c b/trunk/net/dccp/probe.c deleted file mode 100644 index 146496fce2e2..000000000000 --- a/trunk/net/dccp/probe.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * dccp_probe - Observe the DCCP flow with kprobes. - * - * The idea for this came from Werner Almesberger's umlsim - * Copyright (C) 2004, Stephen Hemminger - * - * Modified for DCCP from Stephen Hemminger's code - * Copyright (C) 2006, Ian McDonald - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dccp.h" -#include "ccid.h" -#include "ccids/ccid3.h" - -static int port; - -static int bufsize = 64 * 1024; - -static const char procname[] = "dccpprobe"; - -struct { - struct kfifo *fifo; - spinlock_t lock; - wait_queue_head_t wait; - struct timeval tstart; -} dccpw; - -static void printl(const char *fmt, ...) -{ - va_list args; - int len; - struct timeval now; - char tbuf[256]; - - va_start(args, fmt); - do_gettimeofday(&now); - - now.tv_sec -= dccpw.tstart.tv_sec; - now.tv_usec -= dccpw.tstart.tv_usec; - if (now.tv_usec < 0) { - --now.tv_sec; - now.tv_usec += 1000000; - } - - len = sprintf(tbuf, "%lu.%06lu ", - (unsigned long) now.tv_sec, - (unsigned long) now.tv_usec); - len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args); - va_end(args); - - kfifo_put(dccpw.fifo, tbuf, len); - wake_up(&dccpw.wait); -} - -static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t size) -{ - const struct dccp_minisock *dmsk = dccp_msk(sk); - const struct inet_sock *inet = inet_sk(sk); - const struct ccid3_hc_tx_sock *hctx; - - if (dmsk->dccpms_tx_ccid == DCCPC_CCID3) - hctx = ccid3_hc_tx_sk(sk); - else - hctx = NULL; - - if (port == 0 || ntohs(inet->dport) == port || - ntohs(inet->sport) == port) { - if (hctx) - printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %d\n", - NIPQUAD(inet->saddr), ntohs(inet->sport), - NIPQUAD(inet->daddr), ntohs(inet->dport), size, - hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, - hctx->ccid3hctx_p, hctx->ccid3hctx_t_ipi); - else - printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n", - NIPQUAD(inet->saddr), ntohs(inet->sport), - NIPQUAD(inet->daddr), ntohs(inet->dport), size); - } - - jprobe_return(); - return 0; -} - -static struct jprobe dccp_send_probe = { - .kp = { .addr = (kprobe_opcode_t *)&dccp_sendmsg, }, - .entry = (kprobe_opcode_t *)&jdccp_sendmsg, -}; - -static int dccpprobe_open(struct inode *inode, struct file *file) -{ - kfifo_reset(dccpw.fifo); - do_gettimeofday(&dccpw.tstart); - return 0; -} - -static ssize_t dccpprobe_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos) -{ - int error = 0, cnt = 0; - unsigned char *tbuf; - - if (!buf || len < 0) - return -EINVAL; - - if (len == 0) - return 0; - - tbuf = vmalloc(len); - if (!tbuf) - return -ENOMEM; - - error = wait_event_interruptible(dccpw.wait, - __kfifo_len(dccpw.fifo) != 0); - if (error) - goto out_free; - - cnt = kfifo_get(dccpw.fifo, tbuf, len); - error = copy_to_user(buf, tbuf, cnt); - -out_free: - vfree(tbuf); - - return error ? error : cnt; -} - -static struct file_operations dccpprobe_fops = { - .owner = THIS_MODULE, - .open = dccpprobe_open, - .read = dccpprobe_read, -}; - -static __init int dccpprobe_init(void) -{ - int ret = -ENOMEM; - - init_waitqueue_head(&dccpw.wait); - spin_lock_init(&dccpw.lock); - dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock); - - if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops)) - goto err0; - - ret = register_jprobe(&dccp_send_probe); - if (ret) - goto err1; - - pr_info("DCCP watch registered (port=%d)\n", port); - return 0; -err1: - proc_net_remove(procname); -err0: - kfifo_free(dccpw.fifo); - return ret; -} -module_init(dccpprobe_init); - -static __exit void dccpprobe_exit(void) -{ - kfifo_free(dccpw.fifo); - proc_net_remove(procname); - unregister_jprobe(&dccp_send_probe); - -} -module_exit(dccpprobe_exit); - -MODULE_PARM_DESC(port, "Port to match (0=all)"); -module_param(port, int, 0); - -MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)"); -module_param(bufsize, int, 0); - -MODULE_AUTHOR("Ian McDonald "); -MODULE_DESCRIPTION("DCCP snooper"); -MODULE_LICENSE("GPL"); diff --git a/trunk/net/dccp/proto.c b/trunk/net/dccp/proto.c index 72cbdcfc2c65..962df0ea31aa 100644 --- a/trunk/net/dccp/proto.c +++ b/trunk/net/dccp/proto.c @@ -217,7 +217,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) icsk->icsk_sync_mss = dccp_sync_mss; dp->dccps_mss_cache = 536; dp->dccps_role = DCCP_ROLE_UNDEFINED; - dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; + dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; return 0; @@ -267,6 +267,12 @@ static inline int dccp_listen_start(struct sock *sk) struct dccp_sock *dp = dccp_sk(sk); dp->dccps_role = DCCP_ROLE_LISTEN; + /* + * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE) + * before calling listen() + */ + if (dccp_service_not_initialized(sk)) + return -EPROTO; return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); } @@ -534,6 +540,9 @@ static int dccp_getsockopt_service(struct sock *sk, int len, int err = -ENOENT, slen = 0, total_len = sizeof(u32); lock_sock(sk); + if (dccp_service_not_initialized(sk)) + goto out; + if ((sl = dp->dccps_service_list) != NULL) { slen = sl->dccpsl_nr * sizeof(u32); total_len += slen; diff --git a/trunk/net/ipv4/Kconfig b/trunk/net/ipv4/Kconfig index 30af4a4dfcc8..1650b64415aa 100644 --- a/trunk/net/ipv4/Kconfig +++ b/trunk/net/ipv4/Kconfig @@ -448,22 +448,24 @@ config INET_TCP_DIAG depends on INET_DIAG def_tristate INET_DIAG -menuconfig TCP_CONG_ADVANCED +config TCP_CONG_ADVANCED bool "TCP: advanced congestion control" ---help--- Support for selection of various TCP congestion control modules. Nearly all users can safely say no here, and a safe default - selection will be made (CUBIC with new Reno as a fallback). + selection will be made (BIC-TCP with new Reno as a fallback). If unsure, say N. -if TCP_CONG_ADVANCED +# TCP Reno is builtin (required as fallback) +menu "TCP congestion control" + depends on TCP_CONG_ADVANCED config TCP_CONG_BIC tristate "Binary Increase Congestion (BIC) control" - default m + default y ---help--- BIC-TCP is a sender-side only change that ensures a linear RTT fairness under large windows while offering both scalability and @@ -477,7 +479,7 @@ config TCP_CONG_BIC config TCP_CONG_CUBIC tristate "CUBIC TCP" - default y + default m ---help--- This is version 2.0 of BIC-TCP which uses a cubic growth function among other techniques. @@ -572,49 +574,12 @@ config TCP_CONG_VENO loss packets. See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf -choice - prompt "Default TCP congestion control" - default DEFAULT_CUBIC - help - Select the TCP congestion control that will be used by default - for all connections. - - config DEFAULT_BIC - bool "Bic" if TCP_CONG_BIC=y - - config DEFAULT_CUBIC - bool "Cubic" if TCP_CONG_CUBIC=y - - config DEFAULT_HTCP - bool "Htcp" if TCP_CONG_HTCP=y - - config DEFAULT_VEGAS - bool "Vegas" if TCP_CONG_VEGAS=y +endmenu - config DEFAULT_WESTWOOD - bool "Westwood" if TCP_CONG_WESTWOOD=y - - config DEFAULT_RENO - bool "Reno" - -endchoice - -endif - -config TCP_CONG_CUBIC +config TCP_CONG_BIC tristate depends on !TCP_CONG_ADVANCED default y -config DEFAULT_TCP_CONG - string - default "bic" if DEFAULT_BIC - default "cubic" if DEFAULT_CUBIC - default "htcp" if DEFAULT_HTCP - default "vegas" if DEFAULT_VEGAS - default "westwood" if DEFAULT_WESTWOOD - default "reno" if DEFAULT_RENO - default "cubic" - source "net/ipv4/ipvs/Kconfig" diff --git a/trunk/net/ipv4/cipso_ipv4.c b/trunk/net/ipv4/cipso_ipv4.c index e6ce0b3ba62a..80a2a0911b49 100644 --- a/trunk/net/ipv4/cipso_ipv4.c +++ b/trunk/net/ipv4/cipso_ipv4.c @@ -259,7 +259,7 @@ void cipso_v4_cache_invalidate(void) u32 iter; for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) { - spin_lock_bh(&cipso_v4_cache[iter].lock); + spin_lock(&cipso_v4_cache[iter].lock); list_for_each_entry_safe(entry, tmp_entry, &cipso_v4_cache[iter].list, list) { @@ -267,7 +267,7 @@ void cipso_v4_cache_invalidate(void) cipso_v4_cache_entry_free(entry); } cipso_v4_cache[iter].size = 0; - spin_unlock_bh(&cipso_v4_cache[iter].lock); + spin_unlock(&cipso_v4_cache[iter].lock); } return; @@ -309,7 +309,7 @@ static int cipso_v4_cache_check(const unsigned char *key, hash = cipso_v4_map_cache_hash(key, key_len); bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); - spin_lock_bh(&cipso_v4_cache[bkt].lock); + spin_lock(&cipso_v4_cache[bkt].lock); list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) { if (entry->hash == hash && entry->key_len == key_len && @@ -318,7 +318,7 @@ static int cipso_v4_cache_check(const unsigned char *key, secattr->cache.free = entry->lsm_data.free; secattr->cache.data = entry->lsm_data.data; if (prev_entry == NULL) { - spin_unlock_bh(&cipso_v4_cache[bkt].lock); + spin_unlock(&cipso_v4_cache[bkt].lock); return 0; } @@ -333,12 +333,12 @@ static int cipso_v4_cache_check(const unsigned char *key, &prev_entry->list); } - spin_unlock_bh(&cipso_v4_cache[bkt].lock); + spin_unlock(&cipso_v4_cache[bkt].lock); return 0; } prev_entry = entry; } - spin_unlock_bh(&cipso_v4_cache[bkt].lock); + spin_unlock(&cipso_v4_cache[bkt].lock); return -ENOENT; } @@ -387,7 +387,7 @@ int cipso_v4_cache_add(const struct sk_buff *skb, entry->lsm_data.data = secattr->cache.data; bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); - spin_lock_bh(&cipso_v4_cache[bkt].lock); + spin_lock(&cipso_v4_cache[bkt].lock); if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) { list_add(&entry->list, &cipso_v4_cache[bkt].list); cipso_v4_cache[bkt].size += 1; @@ -398,7 +398,7 @@ int cipso_v4_cache_add(const struct sk_buff *skb, list_add(&entry->list, &cipso_v4_cache[bkt].list); cipso_v4_cache_entry_free(old_entry); } - spin_unlock_bh(&cipso_v4_cache[bkt].lock); + spin_unlock(&cipso_v4_cache[bkt].lock); return 0; @@ -530,42 +530,197 @@ struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) } /** - * cipso_v4_doi_walk - Iterate through the DOI definitions - * @skip_cnt: skip past this number of DOI definitions, updated - * @callback: callback for each DOI definition - * @cb_arg: argument for the callback function + * cipso_v4_doi_dump_all - Dump all the CIPSO DOI definitions into a sk_buff + * @headroom: the amount of headroom to allocate for the sk_buff * * Description: - * Iterate over the DOI definition list, skipping the first @skip_cnt entries. - * For each entry call @callback, if @callback returns a negative value stop - * 'walking' through the list and return. Updates the value in @skip_cnt upon - * return. Returns zero on success, negative values on failure. + * Dump a list of all the configured DOI values into a sk_buff. The returned + * sk_buff has room at the front of the sk_buff for @headroom bytes. See + * net/netlabel/netlabel_cipso_v4.h for the LISTALL message format. This + * function may fail if another process is changing the DOI list at the same + * time. Returns a pointer to a sk_buff on success, NULL on error. * */ -int cipso_v4_doi_walk(u32 *skip_cnt, - int (*callback) (struct cipso_v4_doi *doi_def, void *arg), - void *cb_arg) +struct sk_buff *cipso_v4_doi_dump_all(size_t headroom) { - int ret_val = -ENOENT; + struct sk_buff *skb = NULL; + struct cipso_v4_doi *iter; u32 doi_cnt = 0; - struct cipso_v4_doi *iter_doi; + ssize_t buf_len; + buf_len = NETLBL_LEN_U32; rcu_read_lock(); - list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list) - if (iter_doi->valid) { - if (doi_cnt++ < *skip_cnt) - continue; - ret_val = callback(iter_doi, cb_arg); - if (ret_val < 0) { - doi_cnt--; - goto doi_walk_return; + list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) + if (iter->valid) { + doi_cnt += 1; + buf_len += 2 * NETLBL_LEN_U32; + } + + skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); + if (skb == NULL) + goto doi_dump_all_failure; + + if (nla_put_u32(skb, NLA_U32, doi_cnt) != 0) + goto doi_dump_all_failure; + buf_len -= NETLBL_LEN_U32; + list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) + if (iter->valid) { + if (buf_len < 2 * NETLBL_LEN_U32) + goto doi_dump_all_failure; + if (nla_put_u32(skb, NLA_U32, iter->doi) != 0) + goto doi_dump_all_failure; + if (nla_put_u32(skb, NLA_U32, iter->type) != 0) + goto doi_dump_all_failure; + buf_len -= 2 * NETLBL_LEN_U32; + } + rcu_read_unlock(); + + return skb; + +doi_dump_all_failure: + rcu_read_unlock(); + kfree(skb); + return NULL; +} + +/** + * cipso_v4_doi_dump - Dump a CIPSO DOI definition into a sk_buff + * @doi: the DOI value + * @headroom: the amount of headroom to allocate for the sk_buff + * + * Description: + * Lookup the DOI definition matching @doi and dump it's contents into a + * sk_buff. The returned sk_buff has room at the front of the sk_buff for + * @headroom bytes. See net/netlabel/netlabel_cipso_v4.h for the LIST message + * format. This function may fail if another process is changing the DOI list + * at the same time. Returns a pointer to a sk_buff on success, NULL on error. + * + */ +struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom) +{ + struct sk_buff *skb = NULL; + struct cipso_v4_doi *iter; + u32 tag_cnt = 0; + u32 lvl_cnt = 0; + u32 cat_cnt = 0; + ssize_t buf_len; + ssize_t tmp; + + rcu_read_lock(); + iter = cipso_v4_doi_getdef(doi); + if (iter == NULL) + goto doi_dump_failure; + buf_len = NETLBL_LEN_U32; + switch (iter->type) { + case CIPSO_V4_MAP_PASS: + buf_len += NETLBL_LEN_U32; + while(tag_cnt < CIPSO_V4_TAG_MAXCNT && + iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) { + tag_cnt += 1; + buf_len += NETLBL_LEN_U8; + } + break; + case CIPSO_V4_MAP_STD: + buf_len += 3 * NETLBL_LEN_U32; + while (tag_cnt < CIPSO_V4_TAG_MAXCNT && + iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) { + tag_cnt += 1; + buf_len += NETLBL_LEN_U8; + } + for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++) + if (iter->map.std->lvl.local[tmp] != + CIPSO_V4_INV_LVL) { + lvl_cnt += 1; + buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U8; + } + for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++) + if (iter->map.std->cat.local[tmp] != + CIPSO_V4_INV_CAT) { + cat_cnt += 1; + buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U16; } + break; + } + + skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); + if (skb == NULL) + goto doi_dump_failure; + + if (nla_put_u32(skb, NLA_U32, iter->type) != 0) + goto doi_dump_failure; + buf_len -= NETLBL_LEN_U32; + if (iter != cipso_v4_doi_getdef(doi)) + goto doi_dump_failure; + switch (iter->type) { + case CIPSO_V4_MAP_PASS: + if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0) + goto doi_dump_failure; + buf_len -= NETLBL_LEN_U32; + for (tmp = 0; + tmp < CIPSO_V4_TAG_MAXCNT && + iter->tags[tmp] != CIPSO_V4_TAG_INVALID; + tmp++) { + if (buf_len < NETLBL_LEN_U8) + goto doi_dump_failure; + if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0) + goto doi_dump_failure; + buf_len -= NETLBL_LEN_U8; } + break; + case CIPSO_V4_MAP_STD: + if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0) + goto doi_dump_failure; + if (nla_put_u32(skb, NLA_U32, lvl_cnt) != 0) + goto doi_dump_failure; + if (nla_put_u32(skb, NLA_U32, cat_cnt) != 0) + goto doi_dump_failure; + buf_len -= 3 * NETLBL_LEN_U32; + for (tmp = 0; + tmp < CIPSO_V4_TAG_MAXCNT && + iter->tags[tmp] != CIPSO_V4_TAG_INVALID; + tmp++) { + if (buf_len < NETLBL_LEN_U8) + goto doi_dump_failure; + if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0) + goto doi_dump_failure; + buf_len -= NETLBL_LEN_U8; + } + for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++) + if (iter->map.std->lvl.local[tmp] != + CIPSO_V4_INV_LVL) { + if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U8) + goto doi_dump_failure; + if (nla_put_u32(skb, NLA_U32, tmp) != 0) + goto doi_dump_failure; + if (nla_put_u8(skb, + NLA_U8, + iter->map.std->lvl.local[tmp]) != 0) + goto doi_dump_failure; + buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U8; + } + for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++) + if (iter->map.std->cat.local[tmp] != + CIPSO_V4_INV_CAT) { + if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U16) + goto doi_dump_failure; + if (nla_put_u32(skb, NLA_U32, tmp) != 0) + goto doi_dump_failure; + if (nla_put_u16(skb, + NLA_U16, + iter->map.std->cat.local[tmp]) != 0) + goto doi_dump_failure; + buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U16; + } + break; + } + rcu_read_unlock(); + + return skb; -doi_walk_return: +doi_dump_failure: rcu_read_unlock(); - *skip_cnt = doi_cnt; - return ret_val; + kfree(skb); + return NULL; } /** @@ -1331,40 +1486,43 @@ int cipso_v4_socket_setattr(const struct socket *sock, } /** - * cipso_v4_sock_getattr - Get the security attributes from a sock - * @sk: the sock + * cipso_v4_socket_getattr - Get the security attributes from a socket + * @sock: the socket * @secattr: the security attributes * * Description: - * Query @sk to see if there is a CIPSO option attached to the sock and if - * there is return the CIPSO security attributes in @secattr. This function - * requires that @sk be locked, or privately held, but it does not do any - * locking itself. Returns zero on success and negative values on failure. + * Query @sock to see if there is a CIPSO option attached to the socket and if + * there is return the CIPSO security attributes in @secattr. Returns zero on + * success and negative values on failure. * */ -int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) +int cipso_v4_socket_getattr(const struct socket *sock, + struct netlbl_lsm_secattr *secattr) { int ret_val = -ENOMSG; + struct sock *sk; struct inet_sock *sk_inet; unsigned char *cipso_ptr; u32 doi; struct cipso_v4_doi *doi_def; + sk = sock->sk; + lock_sock(sk); sk_inet = inet_sk(sk); if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0) - return -ENOMSG; + goto socket_getattr_return; cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso - sizeof(struct iphdr); ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr); if (ret_val == 0) - return ret_val; + goto socket_getattr_return; doi = ntohl(*(u32 *)&cipso_ptr[2]); rcu_read_lock(); doi_def = cipso_v4_doi_getdef(doi); if (doi_def == NULL) { rcu_read_unlock(); - return -ENOMSG; + goto socket_getattr_return; } switch (cipso_ptr[6]) { case CIPSO_V4_TAG_RBITMAP: @@ -1375,29 +1533,8 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) } rcu_read_unlock(); - return ret_val; -} - -/** - * cipso_v4_socket_getattr - Get the security attributes from a socket - * @sock: the socket - * @secattr: the security attributes - * - * Description: - * Query @sock to see if there is a CIPSO option attached to the socket and if - * there is return the CIPSO security attributes in @secattr. Returns zero on - * success and negative values on failure. - * - */ -int cipso_v4_socket_getattr(const struct socket *sock, - struct netlbl_lsm_secattr *secattr) -{ - int ret_val; - - lock_sock(sock->sk); - ret_val = cipso_v4_sock_getattr(sock->sk, secattr); - release_sock(sock->sk); - +socket_getattr_return: + release_sock(sk); return ret_val; } diff --git a/trunk/net/ipv4/sysctl_net_ipv4.c b/trunk/net/ipv4/sysctl_net_ipv4.c index e82a5be894b5..19b2071ff319 100644 --- a/trunk/net/ipv4/sysctl_net_ipv4.c +++ b/trunk/net/ipv4/sysctl_net_ipv4.c @@ -129,12 +129,6 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, return ret; } -static int __init tcp_congestion_default(void) -{ - return tcp_set_default_congestion_control(CONFIG_DEFAULT_TCP_CONG); -} - -late_initcall(tcp_congestion_default); ctl_table ipv4_table[] = { { diff --git a/trunk/net/ipv4/tcp_cong.c b/trunk/net/ipv4/tcp_cong.c index af0aca1e6be6..7ff2e4273a7c 100644 --- a/trunk/net/ipv4/tcp_cong.c +++ b/trunk/net/ipv4/tcp_cong.c @@ -48,7 +48,7 @@ int tcp_register_congestion_control(struct tcp_congestion_ops *ca) printk(KERN_NOTICE "TCP %s already registered\n", ca->name); ret = -EEXIST; } else { - list_add_tail_rcu(&ca->list, &tcp_cong_list); + list_add_rcu(&ca->list, &tcp_cong_list); printk(KERN_INFO "TCP %s registered\n", ca->name); } spin_unlock(&tcp_cong_list_lock); diff --git a/trunk/net/netlabel/Kconfig b/trunk/net/netlabel/Kconfig index 9f7121ae13e9..fe23cb7f1e87 100644 --- a/trunk/net/netlabel/Kconfig +++ b/trunk/net/netlabel/Kconfig @@ -9,9 +9,6 @@ config NETLABEL ---help--- NetLabel provides support for explicit network packet labeling protocols such as CIPSO and RIPSO. For more information see - Documentation/netlabel as well as the NetLabel SourceForge project - for configuration tools and additional documentation. - - * http://netlabel.sf.net + Documentation/netlabel. If you are unsure, say N. diff --git a/trunk/net/netlabel/netlabel_cipso_v4.c b/trunk/net/netlabel/netlabel_cipso_v4.c index 4125a55f469f..a4f40adc447b 100644 --- a/trunk/net/netlabel/netlabel_cipso_v4.c +++ b/trunk/net/netlabel/netlabel_cipso_v4.c @@ -41,37 +41,15 @@ #include "netlabel_user.h" #include "netlabel_cipso_v4.h" -/* Argument struct for cipso_v4_doi_walk() */ -struct netlbl_cipsov4_doiwalk_arg { - struct netlink_callback *nl_cb; - struct sk_buff *skb; - u32 seq; -}; - /* NetLabel Generic NETLINK CIPSOv4 family */ static struct genl_family netlbl_cipsov4_gnl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = NETLBL_NLTYPE_CIPSOV4_NAME, .version = NETLBL_PROTO_VERSION, - .maxattr = NLBL_CIPSOV4_A_MAX, + .maxattr = 0, }; -/* NetLabel Netlink attribute policy */ -static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = { - [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 }, - [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 }, - [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 }, - [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED }, - [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 }, - [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 }, - [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED }, - [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED }, - [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 }, - [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 }, - [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED }, - [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED }, -}; /* * Helper Functions @@ -103,41 +81,6 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry) kfree(ptr); } -/** - * netlbl_cipsov4_add_common - Parse the common sections of a ADD message - * @info: the Generic NETLINK info block - * @doi_def: the CIPSO V4 DOI definition - * - * Description: - * Parse the common sections of a ADD message and fill in the related values - * in @doi_def. Returns zero on success, negative values on failure. - * - */ -static int netlbl_cipsov4_add_common(struct genl_info *info, - struct cipso_v4_doi *doi_def) -{ - struct nlattr *nla; - int nla_rem; - u32 iter = 0; - - doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); - - if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST], - NLBL_CIPSOV4_A_MAX, - netlbl_cipsov4_genl_policy) != 0) - return -EINVAL; - - nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem) - if (nla->nla_type == NLBL_CIPSOV4_A_TAG) { - if (iter > CIPSO_V4_TAG_MAXCNT) - return -EINVAL; - doi_def->tags[iter++] = nla_get_u8(nla); - } - if (iter < CIPSO_V4_TAG_MAXCNT) - doi_def->tags[iter] = CIPSO_V4_TAG_INVALID; - - return 0; -} /* * NetLabel Command Handlers @@ -145,7 +88,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, /** * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition - * @info: the Generic NETLINK info block + * @doi: the DOI value + * @msg: the ADD message data + * @msg_size: the size of the ADD message buffer * * Description: * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message @@ -153,28 +98,29 @@ static int netlbl_cipsov4_add_common(struct genl_info *info, * error. * */ -static int netlbl_cipsov4_add_std(struct genl_info *info) +static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size) { int ret_val = -EINVAL; + int msg_len = msg_size; + u32 num_tags; + u32 num_lvls; + u32 num_cats; struct cipso_v4_doi *doi_def = NULL; - struct nlattr *nla_a; - struct nlattr *nla_b; - int nla_a_rem; - int nla_b_rem; - - if (!info->attrs[NLBL_CIPSOV4_A_DOI] || - !info->attrs[NLBL_CIPSOV4_A_TAGLST] || - !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST]) - return -EINVAL; + u32 iter; + u32 tmp_val_a; + u32 tmp_val_b; - if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], - NLBL_CIPSOV4_A_MAX, - netlbl_cipsov4_genl_policy) != 0) - return -EINVAL; + if (msg_len < NETLBL_LEN_U32) + goto add_std_failure; + num_tags = netlbl_getinc_u32(&msg, &msg_len); + if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT) + goto add_std_failure; doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); - if (doi_def == NULL) - return -ENOMEM; + if (doi_def == NULL) { + ret_val = -ENOMEM; + goto add_std_failure; + } doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL); if (doi_def->map.std == NULL) { ret_val = -ENOMEM; @@ -182,32 +128,28 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) } doi_def->type = CIPSO_V4_MAP_STD; - ret_val = netlbl_cipsov4_add_common(info, doi_def); - if (ret_val != 0) + for (iter = 0; iter < num_tags; iter++) { + if (msg_len < NETLBL_LEN_U8) + goto add_std_failure; + doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len); + switch (doi_def->tags[iter]) { + case CIPSO_V4_TAG_RBITMAP: + break; + default: + goto add_std_failure; + } + } + if (iter < CIPSO_V4_TAG_MAXCNT) + doi_def->tags[iter] = CIPSO_V4_TAG_INVALID; + + if (msg_len < 6 * NETLBL_LEN_U32) goto add_std_failure; - nla_for_each_nested(nla_a, - info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], - nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) { - nla_for_each_nested(nla_b, nla_a, nla_b_rem) - switch (nla_b->nla_type) { - case NLBL_CIPSOV4_A_MLSLVLLOC: - if (nla_get_u32(nla_b) >= - doi_def->map.std->lvl.local_size) - doi_def->map.std->lvl.local_size = - nla_get_u32(nla_b) + 1; - break; - case NLBL_CIPSOV4_A_MLSLVLREM: - if (nla_get_u32(nla_b) >= - doi_def->map.std->lvl.cipso_size) - doi_def->map.std->lvl.cipso_size = - nla_get_u32(nla_b) + 1; - break; - } - } - if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS || - doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS) + num_lvls = netlbl_getinc_u32(&msg, &msg_len); + if (num_lvls == 0) + goto add_std_failure; + doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg, &msg_len); + if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS) goto add_std_failure; doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size, sizeof(u32), @@ -216,6 +158,9 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) ret_val = -ENOMEM; goto add_std_failure; } + doi_def->map.std->lvl.cipso_size = netlbl_getinc_u8(&msg, &msg_len); + if (doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS) + goto add_std_failure; doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size, sizeof(u32), GFP_KERNEL); @@ -223,101 +168,68 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) ret_val = -ENOMEM; goto add_std_failure; } - nla_for_each_nested(nla_a, - info->attrs[NLBL_CIPSOV4_A_MLSLVLLST], - nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) { - struct nlattr *lvl_loc; - struct nlattr *lvl_rem; - - if (nla_validate_nested(nla_a, - NLBL_CIPSOV4_A_MAX, - netlbl_cipsov4_genl_policy) != 0) - goto add_std_failure; - - lvl_loc = nla_find_nested(nla_a, - NLBL_CIPSOV4_A_MLSLVLLOC); - lvl_rem = nla_find_nested(nla_a, - NLBL_CIPSOV4_A_MLSLVLREM); - if (lvl_loc == NULL || lvl_rem == NULL) - goto add_std_failure; - doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] = - nla_get_u32(lvl_rem); - doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] = - nla_get_u32(lvl_loc); - } - if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) { - if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST], - NLBL_CIPSOV4_A_MAX, - netlbl_cipsov4_genl_policy) != 0) - goto add_std_failure; - - nla_for_each_nested(nla_a, - info->attrs[NLBL_CIPSOV4_A_MLSCATLST], - nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) { - if (nla_validate_nested(nla_a, - NLBL_CIPSOV4_A_MAX, - netlbl_cipsov4_genl_policy) != 0) - goto add_std_failure; - nla_for_each_nested(nla_b, nla_a, nla_b_rem) - switch (nla_b->nla_type) { - case NLBL_CIPSOV4_A_MLSCATLOC: - if (nla_get_u32(nla_b) >= - doi_def->map.std->cat.local_size) - doi_def->map.std->cat.local_size = - nla_get_u32(nla_b) + 1; - break; - case NLBL_CIPSOV4_A_MLSCATREM: - if (nla_get_u32(nla_b) >= - doi_def->map.std->cat.cipso_size) - doi_def->map.std->cat.cipso_size = - nla_get_u32(nla_b) + 1; - break; - } - } - if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS || - doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS) - goto add_std_failure; - doi_def->map.std->cat.local = kcalloc( - doi_def->map.std->cat.local_size, + num_cats = netlbl_getinc_u32(&msg, &msg_len); + doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len); + if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS) + goto add_std_failure; + doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size, sizeof(u32), GFP_KERNEL); - if (doi_def->map.std->cat.local == NULL) { - ret_val = -ENOMEM; - goto add_std_failure; - } - doi_def->map.std->cat.cipso = kcalloc( - doi_def->map.std->cat.cipso_size, + if (doi_def->map.std->cat.local == NULL) { + ret_val = -ENOMEM; + goto add_std_failure; + } + doi_def->map.std->cat.cipso_size = netlbl_getinc_u16(&msg, &msg_len); + if (doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS) + goto add_std_failure; + doi_def->map.std->cat.cipso = kcalloc(doi_def->map.std->cat.cipso_size, sizeof(u32), GFP_KERNEL); - if (doi_def->map.std->cat.cipso == NULL) { - ret_val = -ENOMEM; + if (doi_def->map.std->cat.cipso == NULL) { + ret_val = -ENOMEM; + goto add_std_failure; + } + + if (msg_len < + num_lvls * (NETLBL_LEN_U32 + NETLBL_LEN_U8) + + num_cats * (NETLBL_LEN_U32 + NETLBL_LEN_U16)) + goto add_std_failure; + + for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++) + doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL; + for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++) + doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL; + for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++) + doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT; + for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++) + doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT; + + for (iter = 0; iter < num_lvls; iter++) { + tmp_val_a = netlbl_getinc_u32(&msg, &msg_len); + tmp_val_b = netlbl_getinc_u8(&msg, &msg_len); + + if (tmp_val_a >= doi_def->map.std->lvl.local_size || + tmp_val_b >= doi_def->map.std->lvl.cipso_size) goto add_std_failure; - } - nla_for_each_nested(nla_a, - info->attrs[NLBL_CIPSOV4_A_MLSCATLST], - nla_a_rem) - if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) { - struct nlattr *cat_loc; - struct nlattr *cat_rem; - - cat_loc = nla_find_nested(nla_a, - NLBL_CIPSOV4_A_MLSCATLOC); - cat_rem = nla_find_nested(nla_a, - NLBL_CIPSOV4_A_MLSCATREM); - if (cat_loc == NULL || cat_rem == NULL) - goto add_std_failure; - doi_def->map.std->cat.local[ - nla_get_u32(cat_loc)] = - nla_get_u32(cat_rem); - doi_def->map.std->cat.cipso[ - nla_get_u32(cat_rem)] = - nla_get_u32(cat_loc); - } + + doi_def->map.std->lvl.cipso[tmp_val_b] = tmp_val_a; + doi_def->map.std->lvl.local[tmp_val_a] = tmp_val_b; } + for (iter = 0; iter < num_cats; iter++) { + tmp_val_a = netlbl_getinc_u32(&msg, &msg_len); + tmp_val_b = netlbl_getinc_u16(&msg, &msg_len); + + if (tmp_val_a >= doi_def->map.std->cat.local_size || + tmp_val_b >= doi_def->map.std->cat.cipso_size) + goto add_std_failure; + + doi_def->map.std->cat.cipso[tmp_val_b] = tmp_val_a; + doi_def->map.std->cat.local[tmp_val_a] = tmp_val_b; + } + + doi_def->doi = doi; ret_val = cipso_v4_doi_add(doi_def); if (ret_val != 0) goto add_std_failure; @@ -331,7 +243,9 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) /** * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition - * @info: the Generic NETLINK info block + * @doi: the DOI value + * @msg: the ADD message data + * @msg_size: the size of the ADD message buffer * * Description: * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message @@ -339,31 +253,52 @@ static int netlbl_cipsov4_add_std(struct genl_info *info) * error. * */ -static int netlbl_cipsov4_add_pass(struct genl_info *info) +static int netlbl_cipsov4_add_pass(u32 doi, + struct nlattr *msg, + size_t msg_size) { - int ret_val; + int ret_val = -EINVAL; + int msg_len = msg_size; + u32 num_tags; struct cipso_v4_doi *doi_def = NULL; + u32 iter; - if (!info->attrs[NLBL_CIPSOV4_A_DOI] || - !info->attrs[NLBL_CIPSOV4_A_TAGLST]) - return -EINVAL; + if (msg_len < NETLBL_LEN_U32) + goto add_pass_failure; + num_tags = netlbl_getinc_u32(&msg, &msg_len); + if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT) + goto add_pass_failure; doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); - if (doi_def == NULL) - return -ENOMEM; + if (doi_def == NULL) { + ret_val = -ENOMEM; + goto add_pass_failure; + } doi_def->type = CIPSO_V4_MAP_PASS; - ret_val = netlbl_cipsov4_add_common(info, doi_def); - if (ret_val != 0) - goto add_pass_failure; + for (iter = 0; iter < num_tags; iter++) { + if (msg_len < NETLBL_LEN_U8) + goto add_pass_failure; + doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len); + switch (doi_def->tags[iter]) { + case CIPSO_V4_TAG_RBITMAP: + break; + default: + goto add_pass_failure; + } + } + if (iter < CIPSO_V4_TAG_MAXCNT) + doi_def->tags[iter] = CIPSO_V4_TAG_INVALID; + doi_def->doi = doi; ret_val = cipso_v4_doi_add(doi_def); if (ret_val != 0) goto add_pass_failure; return 0; add_pass_failure: - netlbl_cipsov4_doi_free(&doi_def->rcu); + if (doi_def) + netlbl_cipsov4_doi_free(&doi_def->rcu); return ret_val; } @@ -381,21 +316,34 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; + u32 doi; u32 map_type; + int msg_len = netlbl_netlink_payload_len(skb); + struct nlattr *msg = netlbl_netlink_payload_data(skb); + + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) + goto add_return; - if (!info->attrs[NLBL_CIPSOV4_A_MTYPE]) - return -EINVAL; + if (msg_len < 2 * NETLBL_LEN_U32) + goto add_return; - map_type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]); + doi = netlbl_getinc_u32(&msg, &msg_len); + map_type = netlbl_getinc_u32(&msg, &msg_len); switch (map_type) { case CIPSO_V4_MAP_STD: - ret_val = netlbl_cipsov4_add_std(info); + ret_val = netlbl_cipsov4_add_std(doi, msg, msg_len); break; case CIPSO_V4_MAP_PASS: - ret_val = netlbl_cipsov4_add_pass(info); + ret_val = netlbl_cipsov4_add_pass(doi, msg, msg_len); break; } +add_return: + netlbl_netlink_send_ack(info, + netlbl_cipsov4_gnl_family.id, + NLBL_CIPSOV4_C_ACK, + -ret_val); return ret_val; } @@ -405,239 +353,84 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) * @info: the Generic NETLINK info block * * Description: - * Process a user generated LIST message and respond accordingly. While the - * response message generated by the kernel is straightforward, determining - * before hand the size of the buffer to allocate is not (we have to generate - * the message to know the size). In order to keep this function sane what we - * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in - * that size, if we fail then we restart with a larger buffer and try again. - * We continue in this manner until we hit a limit of failed attempts then we - * give up and just send an error message. Returns zero on success and - * negative values on error. + * Process a user generated LIST message and respond accordingly. Returns + * zero on success and negative values on error. * */ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) { - int ret_val; - struct sk_buff *ans_skb = NULL; - u32 nlsze_mult = 1; - void *data; + int ret_val = -EINVAL; u32 doi; - struct nlattr *nla_a; - struct nlattr *nla_b; - struct cipso_v4_doi *doi_def; - u32 iter; + struct nlattr *msg = netlbl_netlink_payload_data(skb); + struct sk_buff *ans_skb; - if (!info->attrs[NLBL_CIPSOV4_A_DOI]) { - ret_val = -EINVAL; + if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) goto list_failure; - } -list_start: - ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL); + doi = nla_get_u32(msg); + ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN)); if (ans_skb == NULL) { ret_val = -ENOMEM; goto list_failure; } - data = netlbl_netlink_hdr_put(ans_skb, - info->snd_pid, - info->snd_seq, - netlbl_cipsov4_gnl_family.id, - 0, - NLBL_CIPSOV4_C_LIST); - if (data == NULL) { - ret_val = -ENOMEM; - goto list_failure; - } - - doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); - - rcu_read_lock(); - doi_def = cipso_v4_doi_getdef(doi); - if (doi_def == NULL) { - ret_val = -EINVAL; - goto list_failure; - } - - ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type); - if (ret_val != 0) - goto list_failure_lock; - - nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST); - if (nla_a == NULL) { - ret_val = -ENOMEM; - goto list_failure_lock; - } - for (iter = 0; - iter < CIPSO_V4_TAG_MAXCNT && - doi_def->tags[iter] != CIPSO_V4_TAG_INVALID; - iter++) { - ret_val = nla_put_u8(ans_skb, - NLBL_CIPSOV4_A_TAG, - doi_def->tags[iter]); - if (ret_val != 0) - goto list_failure_lock; - } - nla_nest_end(ans_skb, nla_a); - - switch (doi_def->type) { - case CIPSO_V4_MAP_STD: - nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST); - if (nla_a == NULL) { - ret_val = -ENOMEM; - goto list_failure_lock; - } - for (iter = 0; - iter < doi_def->map.std->lvl.local_size; - iter++) { - if (doi_def->map.std->lvl.local[iter] == - CIPSO_V4_INV_LVL) - continue; - - nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL); - if (nla_b == NULL) { - ret_val = -ENOMEM; - goto list_retry; - } - ret_val = nla_put_u32(ans_skb, - NLBL_CIPSOV4_A_MLSLVLLOC, - iter); - if (ret_val != 0) - goto list_retry; - ret_val = nla_put_u32(ans_skb, - NLBL_CIPSOV4_A_MLSLVLREM, - doi_def->map.std->lvl.local[iter]); - if (ret_val != 0) - goto list_retry; - nla_nest_end(ans_skb, nla_b); - } - nla_nest_end(ans_skb, nla_a); - - nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST); - if (nla_a == NULL) { - ret_val = -ENOMEM; - goto list_retry; - } - for (iter = 0; - iter < doi_def->map.std->cat.local_size; - iter++) { - if (doi_def->map.std->cat.local[iter] == - CIPSO_V4_INV_CAT) - continue; - - nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT); - if (nla_b == NULL) { - ret_val = -ENOMEM; - goto list_retry; - } - ret_val = nla_put_u32(ans_skb, - NLBL_CIPSOV4_A_MLSCATLOC, - iter); - if (ret_val != 0) - goto list_retry; - ret_val = nla_put_u32(ans_skb, - NLBL_CIPSOV4_A_MLSCATREM, - doi_def->map.std->cat.local[iter]); - if (ret_val != 0) - goto list_retry; - nla_nest_end(ans_skb, nla_b); - } - nla_nest_end(ans_skb, nla_a); - - break; - } - rcu_read_unlock(); + netlbl_netlink_hdr_push(ans_skb, + info->snd_pid, + 0, + netlbl_cipsov4_gnl_family.id, + NLBL_CIPSOV4_C_LIST); - genlmsg_end(ans_skb, data); - - ret_val = genlmsg_unicast(ans_skb, info->snd_pid); + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); if (ret_val != 0) goto list_failure; return 0; -list_retry: - /* XXX - this limit is a guesstimate */ - if (nlsze_mult < 4) { - rcu_read_unlock(); - kfree_skb(ans_skb); - nlsze_mult++; - goto list_start; - } -list_failure_lock: - rcu_read_unlock(); list_failure: - kfree_skb(ans_skb); - return ret_val; -} - -/** - * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL - * @doi_def: the CIPSOv4 DOI definition - * @arg: the netlbl_cipsov4_doiwalk_arg structure - * - * Description: - * This function is designed to be used as a callback to the - * cipso_v4_doi_walk() function for use in generating a response for a LISTALL - * message. Returns the size of the message on success, negative values on - * failure. - * - */ -static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg) -{ - int ret_val = -ENOMEM; - struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg; - void *data; - - data = netlbl_netlink_hdr_put(cb_arg->skb, - NETLINK_CB(cb_arg->nl_cb->skb).pid, - cb_arg->seq, - netlbl_cipsov4_gnl_family.id, - NLM_F_MULTI, - NLBL_CIPSOV4_C_LISTALL); - if (data == NULL) - goto listall_cb_failure; - - ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi); - if (ret_val != 0) - goto listall_cb_failure; - ret_val = nla_put_u32(cb_arg->skb, - NLBL_CIPSOV4_A_MTYPE, - doi_def->type); - if (ret_val != 0) - goto listall_cb_failure; - - return genlmsg_end(cb_arg->skb, data); - -listall_cb_failure: - genlmsg_cancel(cb_arg->skb, data); + netlbl_netlink_send_ack(info, + netlbl_cipsov4_gnl_family.id, + NLBL_CIPSOV4_C_ACK, + -ret_val); return ret_val; } /** * netlbl_cipsov4_listall - Handle a LISTALL message * @skb: the NETLINK buffer - * @cb: the NETLINK callback + * @info: the Generic NETLINK info block * * Description: * Process a user generated LISTALL message and respond accordingly. Returns * zero on success and negative values on error. * */ -static int netlbl_cipsov4_listall(struct sk_buff *skb, - struct netlink_callback *cb) +static int netlbl_cipsov4_listall(struct sk_buff *skb, struct genl_info *info) { - struct netlbl_cipsov4_doiwalk_arg cb_arg; - int doi_skip = cb->args[0]; + int ret_val = -EINVAL; + struct sk_buff *ans_skb; - cb_arg.nl_cb = cb; - cb_arg.skb = skb; - cb_arg.seq = cb->nlh->nlmsg_seq; + ans_skb = cipso_v4_doi_dump_all(NLMSG_SPACE(GENL_HDRLEN)); + if (ans_skb == NULL) { + ret_val = -ENOMEM; + goto listall_failure; + } + netlbl_netlink_hdr_push(ans_skb, + info->snd_pid, + 0, + netlbl_cipsov4_gnl_family.id, + NLBL_CIPSOV4_C_LISTALL); - cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg); + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); + if (ret_val != 0) + goto listall_failure; + + return 0; - cb->args[0] = doi_skip; - return skb->len; +listall_failure: + netlbl_netlink_send_ack(info, + netlbl_cipsov4_gnl_family.id, + NLBL_CIPSOV4_C_ACK, + -ret_val); + return ret_val; } /** @@ -652,14 +445,27 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, */ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) { - int ret_val = -EINVAL; + int ret_val; u32 doi; + struct nlattr *msg = netlbl_netlink_payload_data(skb); - if (info->attrs[NLBL_CIPSOV4_A_DOI]) { - doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]); - ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free); + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) + goto remove_return; + + if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) { + ret_val = -EINVAL; + goto remove_return; } + doi = nla_get_u32(msg); + ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free); + +remove_return: + netlbl_netlink_send_ack(info, + netlbl_cipsov4_gnl_family.id, + NLBL_CIPSOV4_C_ACK, + -ret_val); return ret_val; } @@ -669,16 +475,14 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) static struct genl_ops netlbl_cipsov4_genl_c_add = { .cmd = NLBL_CIPSOV4_C_ADD, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_cipsov4_genl_policy, + .flags = 0, .doit = netlbl_cipsov4_add, .dumpit = NULL, }; static struct genl_ops netlbl_cipsov4_genl_c_remove = { .cmd = NLBL_CIPSOV4_C_REMOVE, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_cipsov4_genl_policy, + .flags = 0, .doit = netlbl_cipsov4_remove, .dumpit = NULL, }; @@ -686,7 +490,6 @@ static struct genl_ops netlbl_cipsov4_genl_c_remove = { static struct genl_ops netlbl_cipsov4_genl_c_list = { .cmd = NLBL_CIPSOV4_C_LIST, .flags = 0, - .policy = netlbl_cipsov4_genl_policy, .doit = netlbl_cipsov4_list, .dumpit = NULL, }; @@ -694,9 +497,8 @@ static struct genl_ops netlbl_cipsov4_genl_c_list = { static struct genl_ops netlbl_cipsov4_genl_c_listall = { .cmd = NLBL_CIPSOV4_C_LISTALL, .flags = 0, - .policy = netlbl_cipsov4_genl_policy, - .doit = NULL, - .dumpit = netlbl_cipsov4_listall, + .doit = netlbl_cipsov4_listall, + .dumpit = NULL, }; /* diff --git a/trunk/net/netlabel/netlabel_cipso_v4.h b/trunk/net/netlabel/netlabel_cipso_v4.h index f03cf9b78286..4c6ff4b93004 100644 --- a/trunk/net/netlabel/netlabel_cipso_v4.h +++ b/trunk/net/netlabel/netlabel_cipso_v4.h @@ -34,71 +34,175 @@ #include /* - * The following NetLabel payloads are supported by the CIPSO subsystem. + * The following NetLabel payloads are supported by the CIPSO subsystem, all + * of which are preceeded by the nlmsghdr struct. * - * o ADD: - * Sent by an application to add a new DOI mapping table. - * - * Required attributes: + * o ACK: + * Sent by the kernel in response to an applications message, applications + * should never send this message. * - * NLBL_CIPSOV4_A_DOI - * NLBL_CIPSOV4_A_MTYPE - * NLBL_CIPSOV4_A_TAGLST + * +----------------------+-----------------------+ + * | seq number (32 bits) | return code (32 bits) | + * +----------------------+-----------------------+ * - * If using CIPSO_V4_MAP_STD the following attributes are required: + * seq number: the sequence number of the original message, taken from the + * nlmsghdr structure + * return code: return value, based on errno values * - * NLBL_CIPSOV4_A_MLSLVLLST - * NLBL_CIPSOV4_A_MLSCATLST - * - * If using CIPSO_V4_MAP_PASS no additional attributes are required. + * o ADD: + * Sent by an application to add a new DOI mapping table, after completion + * of the task the kernel should ACK this message. + * + * +---------------+--------------------+---------------------+ + * | DOI (32 bits) | map type (32 bits) | tag count (32 bits) | ... + * +---------------+--------------------+---------------------+ + * + * +-----------------+ + * | tag #X (8 bits) | ... repeated + * +-----------------+ + * + * +-------------- ---- --- -- - + * | mapping data + * +-------------- ---- --- -- - + * + * DOI: the DOI value + * map type: the mapping table type (defined in the cipso_ipv4.h header + * as CIPSO_V4_MAP_*) + * tag count: the number of tags, must be greater than zero + * tag: the CIPSO tag for the DOI, tags listed first are given + * higher priorirty when sending packets + * mapping data: specific to the map type (see below) + * + * CIPSO_V4_MAP_STD + * + * +------------------+-----------------------+----------------------+ + * | levels (32 bits) | max l level (32 bits) | max r level (8 bits) | ... + * +------------------+-----------------------+----------------------+ + * + * +----------------------+---------------------+---------------------+ + * | categories (32 bits) | max l cat (32 bits) | max r cat (16 bits) | ... + * +----------------------+---------------------+---------------------+ + * + * +--------------------------+-------------------------+ + * | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated + * +--------------------------+-------------------------+ + * + * +-----------------------------+-----------------------------+ + * | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated + * +-----------------------------+-----------------------------+ + * + * levels: the number of level mappings + * max l level: the highest local level + * max r level: the highest remote/CIPSO level + * categories: the number of category mappings + * max l cat: the highest local category + * max r cat: the highest remote/CIPSO category + * local level: the local part of a level mapping + * CIPSO level: the remote/CIPSO part of a level mapping + * local category: the local part of a category mapping + * CIPSO category: the remote/CIPSO part of a category mapping + * + * CIPSO_V4_MAP_PASS + * + * No mapping data is needed for this map type. * * o REMOVE: * Sent by an application to remove a specific DOI mapping table from the - * CIPSO V4 system. + * CIPSO V4 system. The kernel should ACK this message. * - * Required attributes: + * +---------------+ + * | DOI (32 bits) | + * +---------------+ * - * NLBL_CIPSOV4_A_DOI + * DOI: the DOI value * * o LIST: - * Sent by an application to list the details of a DOI definition. On - * success the kernel should send a response using the following format. + * Sent by an application to list the details of a DOI definition. The + * kernel should send an ACK on error or a response as indicated below. The + * application generated message format is shown below. * - * Required attributes: + * +---------------+ + * | DOI (32 bits) | + * +---------------+ * - * NLBL_CIPSOV4_A_DOI + * DOI: the DOI value * * The valid response message format depends on the type of the DOI mapping, - * the defined formats are shown below. + * the known formats are shown below. + * + * +--------------------+ + * | map type (32 bits) | ... + * +--------------------+ + * + * map type: the DOI mapping table type (defined in the cipso_ipv4.h + * header as CIPSO_V4_MAP_*) + * + * (map type == CIPSO_V4_MAP_STD) + * + * +----------------+------------------+----------------------+ + * | tags (32 bits) | levels (32 bits) | categories (32 bits) | ... + * +----------------+------------------+----------------------+ * - * Required attributes: + * +-----------------+ + * | tag #X (8 bits) | ... repeated + * +-----------------+ * - * NLBL_CIPSOV4_A_MTYPE - * NLBL_CIPSOV4_A_TAGLST + * +--------------------------+-------------------------+ + * | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated + * +--------------------------+-------------------------+ * - * If using CIPSO_V4_MAP_STD the following attributes are required: + * +-----------------------------+-----------------------------+ + * | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated + * +-----------------------------+-----------------------------+ * - * NLBL_CIPSOV4_A_MLSLVLLST - * NLBL_CIPSOV4_A_MLSCATLST + * tags: the number of CIPSO tag types + * levels: the number of level mappings + * categories: the number of category mappings + * tag: the tag number, tags listed first are given higher + * priority when sending packets + * local level: the local part of a level mapping + * CIPSO level: the remote/CIPSO part of a level mapping + * local category: the local part of a category mapping + * CIPSO category: the remote/CIPSO part of a category mapping * - * If using CIPSO_V4_MAP_PASS no additional attributes are required. + * (map type == CIPSO_V4_MAP_PASS) + * + * +----------------+ + * | tags (32 bits) | ... + * +----------------+ + * + * +-----------------+ + * | tag #X (8 bits) | ... repeated + * +-----------------+ + * + * tags: the number of CIPSO tag types + * tag: the tag number, tags listed first are given higher + * priority when sending packets * * o LISTALL: * This message is sent by an application to list the valid DOIs on the - * system. When sent by an application there is no payload and the - * NLM_F_DUMP flag should be set. The kernel should respond with a series of - * the following messages. + * system. There is no payload and the kernel should respond with an ACK + * or the following message. + * + * +---------------------+------------------+-----------------------+ + * | DOI count (32 bits) | DOI #X (32 bits) | map type #X (32 bits) | + * +---------------------+------------------+-----------------------+ * - * Required attributes: + * +-----------------------+ + * | map type #X (32 bits) | ... + * +-----------------------+ * - * NLBL_CIPSOV4_A_DOI - * NLBL_CIPSOV4_A_MTYPE + * DOI count: the number of DOIs + * DOI: the DOI value + * map type: the DOI mapping table type (defined in the cipso_ipv4.h + * header as CIPSO_V4_MAP_*) * */ /* NetLabel CIPSOv4 commands */ enum { NLBL_CIPSOV4_C_UNSPEC, + NLBL_CIPSOV4_C_ACK, NLBL_CIPSOV4_C_ADD, NLBL_CIPSOV4_C_REMOVE, NLBL_CIPSOV4_C_LIST, @@ -107,59 +211,6 @@ enum { }; #define NLBL_CIPSOV4_C_MAX (__NLBL_CIPSOV4_C_MAX - 1) -/* NetLabel CIPSOv4 attributes */ -enum { - NLBL_CIPSOV4_A_UNSPEC, - NLBL_CIPSOV4_A_DOI, - /* (NLA_U32) - * the DOI value */ - NLBL_CIPSOV4_A_MTYPE, - /* (NLA_U32) - * the mapping table type (defined in the cipso_ipv4.h header as - * CIPSO_V4_MAP_*) */ - NLBL_CIPSOV4_A_TAG, - /* (NLA_U8) - * a CIPSO tag type, meant to be used within a NLBL_CIPSOV4_A_TAGLST - * attribute */ - NLBL_CIPSOV4_A_TAGLST, - /* (NLA_NESTED) - * the CIPSO tag list for the DOI, there must be at least one - * NLBL_CIPSOV4_A_TAG attribute, tags listed first are given higher - * priorirty when sending packets */ - NLBL_CIPSOV4_A_MLSLVLLOC, - /* (NLA_U32) - * the local MLS sensitivity level */ - NLBL_CIPSOV4_A_MLSLVLREM, - /* (NLA_U32) - * the remote MLS sensitivity level */ - NLBL_CIPSOV4_A_MLSLVL, - /* (NLA_NESTED) - * a MLS sensitivity level mapping, must contain only one attribute of - * each of the following types: NLBL_CIPSOV4_A_MLSLVLLOC and - * NLBL_CIPSOV4_A_MLSLVLREM */ - NLBL_CIPSOV4_A_MLSLVLLST, - /* (NLA_NESTED) - * the CIPSO level mappings, there must be at least one - * NLBL_CIPSOV4_A_MLSLVL attribute */ - NLBL_CIPSOV4_A_MLSCATLOC, - /* (NLA_U32) - * the local MLS category */ - NLBL_CIPSOV4_A_MLSCATREM, - /* (NLA_U32) - * the remote MLS category */ - NLBL_CIPSOV4_A_MLSCAT, - /* (NLA_NESTED) - * a MLS category mapping, must contain only one attribute of each of - * the following types: NLBL_CIPSOV4_A_MLSCATLOC and - * NLBL_CIPSOV4_A_MLSCATREM */ - NLBL_CIPSOV4_A_MLSCATLST, - /* (NLA_NESTED) - * the CIPSO category mappings, there must be at least one - * NLBL_CIPSOV4_A_MLSCAT attribute */ - __NLBL_CIPSOV4_A_MAX, -}; -#define NLBL_CIPSOV4_A_MAX (__NLBL_CIPSOV4_A_MAX - 1) - /* NetLabel protocol functions */ int netlbl_cipsov4_genl_init(void); diff --git a/trunk/net/netlabel/netlabel_domainhash.c b/trunk/net/netlabel/netlabel_domainhash.c index f56d7a8ac7b7..0489a1378101 100644 --- a/trunk/net/netlabel/netlabel_domainhash.c +++ b/trunk/net/netlabel/netlabel_domainhash.c @@ -354,51 +354,160 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) } /** - * netlbl_domhsh_walk - Iterate through the domain mapping hash table - * @skip_bkt: the number of buckets to skip at the start - * @skip_chain: the number of entries to skip in the first iterated bucket - * @callback: callback for each entry - * @cb_arg: argument for the callback function + * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff * * Description: - * Interate over the domain mapping hash table, skipping the first @skip_bkt - * buckets and @skip_chain entries. For each entry in the table call - * @callback, if @callback returns a negative value stop 'walking' through the - * table and return. Updates the values in @skip_bkt and @skip_chain on - * return. Returns zero on succcess, negative values on failure. + * Dump the domain hash table into a buffer suitable for returning to an + * application in response to a NetLabel management DOMAIN message. This + * function may fail if another process is growing the hash table at the same + * time. The returned sk_buff has room at the front of the sk_buff for + * @headroom bytes. See netlabel.h for the DOMAIN message format. Returns a + * pointer to a sk_buff on success, NULL on error. * */ -int netlbl_domhsh_walk(u32 *skip_bkt, - u32 *skip_chain, - int (*callback) (struct netlbl_dom_map *entry, void *arg), - void *cb_arg) +struct sk_buff *netlbl_domhsh_dump(size_t headroom) { - int ret_val = -ENOENT; - u32 iter_bkt; - struct netlbl_dom_map *iter_entry; - u32 chain_cnt = 0; + struct sk_buff *skb = NULL; + ssize_t buf_len; + u32 bkt_iter; + u32 dom_cnt = 0; + struct netlbl_domhsh_tbl *hsh_tbl; + struct netlbl_dom_map *list_iter; + ssize_t tmp_len; + buf_len = NETLBL_LEN_U32; rcu_read_lock(); - for (iter_bkt = *skip_bkt; - iter_bkt < rcu_dereference(netlbl_domhsh)->size; - iter_bkt++, chain_cnt = 0) { - list_for_each_entry_rcu(iter_entry, - &netlbl_domhsh->tbl[iter_bkt], - list) - if (iter_entry->valid) { - if (chain_cnt++ < *skip_chain) - continue; - ret_val = callback(iter_entry, cb_arg); - if (ret_val < 0) { - chain_cnt--; - goto walk_return; - } + hsh_tbl = rcu_dereference(netlbl_domhsh); + for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++) + list_for_each_entry_rcu(list_iter, + &hsh_tbl->tbl[bkt_iter], list) { + buf_len += NETLBL_LEN_U32 + + nla_total_size(strlen(list_iter->domain) + 1); + switch (list_iter->type) { + case NETLBL_NLTYPE_UNLABELED: + break; + case NETLBL_NLTYPE_CIPSOV4: + buf_len += 2 * NETLBL_LEN_U32; + break; } - } + dom_cnt++; + } + + skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); + if (skb == NULL) + goto dump_failure; + + if (nla_put_u32(skb, NLA_U32, dom_cnt) != 0) + goto dump_failure; + buf_len -= NETLBL_LEN_U32; + hsh_tbl = rcu_dereference(netlbl_domhsh); + for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++) + list_for_each_entry_rcu(list_iter, + &hsh_tbl->tbl[bkt_iter], list) { + tmp_len = nla_total_size(strlen(list_iter->domain) + + 1); + if (buf_len < NETLBL_LEN_U32 + tmp_len) + goto dump_failure; + if (nla_put_string(skb, + NLA_STRING, + list_iter->domain) != 0) + goto dump_failure; + if (nla_put_u32(skb, NLA_U32, list_iter->type) != 0) + goto dump_failure; + buf_len -= NETLBL_LEN_U32 + tmp_len; + switch (list_iter->type) { + case NETLBL_NLTYPE_UNLABELED: + break; + case NETLBL_NLTYPE_CIPSOV4: + if (buf_len < 2 * NETLBL_LEN_U32) + goto dump_failure; + if (nla_put_u32(skb, + NLA_U32, + list_iter->type_def.cipsov4->type) != 0) + goto dump_failure; + if (nla_put_u32(skb, + NLA_U32, + list_iter->type_def.cipsov4->doi) != 0) + goto dump_failure; + buf_len -= 2 * NETLBL_LEN_U32; + break; + } + } + rcu_read_unlock(); -walk_return: + return skb; + +dump_failure: rcu_read_unlock(); - *skip_bkt = iter_bkt; - *skip_chain = chain_cnt; - return ret_val; + kfree_skb(skb); + return NULL; +} + +/** + * netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff + * + * Description: + * Dump the default domain mapping into a buffer suitable for returning to an + * application in response to a NetLabel management DEFDOMAIN message. This + * function may fail if another process is changing the default domain mapping + * at the same time. The returned sk_buff has room at the front of the + * skb_buff for @headroom bytes. See netlabel.h for the DEFDOMAIN message + * format. Returns a pointer to a sk_buff on success, NULL on error. + * + */ +struct sk_buff *netlbl_domhsh_dump_default(size_t headroom) +{ + struct sk_buff *skb; + ssize_t buf_len; + struct netlbl_dom_map *entry; + + buf_len = NETLBL_LEN_U32; + rcu_read_lock(); + entry = rcu_dereference(netlbl_domhsh_def); + if (entry != NULL) + switch (entry->type) { + case NETLBL_NLTYPE_UNLABELED: + break; + case NETLBL_NLTYPE_CIPSOV4: + buf_len += 2 * NETLBL_LEN_U32; + break; + } + + skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); + if (skb == NULL) + goto dump_default_failure; + + if (entry != rcu_dereference(netlbl_domhsh_def)) + goto dump_default_failure; + if (entry != NULL) { + if (nla_put_u32(skb, NLA_U32, entry->type) != 0) + goto dump_default_failure; + buf_len -= NETLBL_LEN_U32; + switch (entry->type) { + case NETLBL_NLTYPE_UNLABELED: + break; + case NETLBL_NLTYPE_CIPSOV4: + if (buf_len < 2 * NETLBL_LEN_U32) + goto dump_default_failure; + if (nla_put_u32(skb, + NLA_U32, + entry->type_def.cipsov4->type) != 0) + goto dump_default_failure; + if (nla_put_u32(skb, + NLA_U32, + entry->type_def.cipsov4->doi) != 0) + goto dump_default_failure; + buf_len -= 2 * NETLBL_LEN_U32; + break; + } + } else + nla_put_u32(skb, NLA_U32, NETLBL_NLTYPE_NONE); + rcu_read_unlock(); + + return skb; + +dump_default_failure: + rcu_read_unlock(); + kfree_skb(skb); + return NULL; } diff --git a/trunk/net/netlabel/netlabel_domainhash.h b/trunk/net/netlabel/netlabel_domainhash.h index 02af72a7877c..99a2287de246 100644 --- a/trunk/net/netlabel/netlabel_domainhash.h +++ b/trunk/net/netlabel/netlabel_domainhash.h @@ -61,9 +61,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry); int netlbl_domhsh_add_default(struct netlbl_dom_map *entry); int netlbl_domhsh_remove_default(void); struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); -int netlbl_domhsh_walk(u32 *skip_bkt, - u32 *skip_chain, - int (*callback) (struct netlbl_dom_map *entry, void *arg), - void *cb_arg); +struct sk_buff *netlbl_domhsh_dump(size_t headroom); +struct sk_buff *netlbl_domhsh_dump_default(size_t headroom); #endif diff --git a/trunk/net/netlabel/netlabel_kapi.c b/trunk/net/netlabel/netlabel_kapi.c index 54fb7de3c2b1..0fd8aaafe23f 100644 --- a/trunk/net/netlabel/netlabel_kapi.c +++ b/trunk/net/netlabel/netlabel_kapi.c @@ -84,29 +84,6 @@ int netlbl_socket_setattr(const struct socket *sock, return ret_val; } -/** - * netlbl_sock_getattr - Determine the security attributes of a sock - * @sk: the sock - * @secattr: the security attributes - * - * Description: - * Examines the given sock to see any NetLabel style labeling has been - * applied to the sock, if so it parses the socket label and returns the - * security attributes in @secattr. Returns zero on success, negative values - * on failure. - * - */ -int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) -{ - int ret_val; - - ret_val = cipso_v4_sock_getattr(sk, secattr); - if (ret_val == 0) - return 0; - - return netlbl_unlabel_getattr(secattr); -} - /** * netlbl_socket_getattr - Determine the security attributes of a socket * @sock: the socket diff --git a/trunk/net/netlabel/netlabel_mgmt.c b/trunk/net/netlabel/netlabel_mgmt.c index 8626c9f678eb..85bc11a1fc46 100644 --- a/trunk/net/netlabel/netlabel_mgmt.c +++ b/trunk/net/netlabel/netlabel_mgmt.c @@ -42,29 +42,15 @@ #include "netlabel_user.h" #include "netlabel_mgmt.h" -/* Argument struct for netlbl_domhsh_walk() */ -struct netlbl_domhsh_walk_arg { - struct netlink_callback *nl_cb; - struct sk_buff *skb; - u32 seq; -}; - /* NetLabel Generic NETLINK CIPSOv4 family */ static struct genl_family netlbl_mgmt_gnl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = NETLBL_NLTYPE_MGMT_NAME, .version = NETLBL_PROTO_VERSION, - .maxattr = NLBL_MGMT_A_MAX, + .maxattr = 0, }; -/* NetLabel Netlink attribute policy */ -static struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { - [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING }, - [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, - [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, - [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, -}; /* * NetLabel Command Handlers @@ -84,62 +70,97 @@ static struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; + struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb); + int msg_len = netlbl_netlink_payload_len(skb); + u32 count; struct netlbl_dom_map *entry = NULL; - size_t tmp_size; + u32 iter; u32 tmp_val; + int tmp_size; - if (!info->attrs[NLBL_MGMT_A_DOMAIN] || - !info->attrs[NLBL_MGMT_A_PROTOCOL]) + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) goto add_failure; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (entry == NULL) { - ret_val = -ENOMEM; - goto add_failure; - } - tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); - entry->domain = kmalloc(tmp_size, GFP_KERNEL); - if (entry->domain == NULL) { - ret_val = -ENOMEM; + if (msg_len < NETLBL_LEN_U32) goto add_failure; - } - entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); - nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); + count = netlbl_getinc_u32(&msg_ptr, &msg_len); - switch (entry->type) { - case NETLBL_NLTYPE_UNLABELED: - ret_val = netlbl_domhsh_add(entry); - break; - case NETLBL_NLTYPE_CIPSOV4: - if (!info->attrs[NLBL_MGMT_A_CV4DOI]) + for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) { + if (msg_len <= 0) { + ret_val = -EINVAL; goto add_failure; + } + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (entry == NULL) { + ret_val = -ENOMEM; + goto add_failure; + } + tmp_size = nla_len(msg_ptr); + if (tmp_size <= 0 || tmp_size > msg_len) { + ret_val = -EINVAL; + goto add_failure; + } + entry->domain = kmalloc(tmp_size, GFP_KERNEL); + if (entry->domain == NULL) { + ret_val = -ENOMEM; + goto add_failure; + } + nla_strlcpy(entry->domain, msg_ptr, tmp_size); + entry->domain[tmp_size - 1] = '\0'; + msg_ptr = nla_next(msg_ptr, &msg_len); - tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); - /* We should be holding a rcu_read_lock() here while we hold - * the result but since the entry will always be deleted when - * the CIPSO DOI is deleted we aren't going to keep the - * lock. */ - rcu_read_lock(); - entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); - if (entry->type_def.cipsov4 == NULL) { - rcu_read_unlock(); + if (msg_len < NETLBL_LEN_U32) { + ret_val = -EINVAL; goto add_failure; } - ret_val = netlbl_domhsh_add(entry); - rcu_read_unlock(); - break; - default: - goto add_failure; + tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); + entry->type = tmp_val; + switch (tmp_val) { + case NETLBL_NLTYPE_UNLABELED: + ret_val = netlbl_domhsh_add(entry); + break; + case NETLBL_NLTYPE_CIPSOV4: + if (msg_len < NETLBL_LEN_U32) { + ret_val = -EINVAL; + goto add_failure; + } + tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); + /* We should be holding a rcu_read_lock() here + * while we hold the result but since the entry + * will always be deleted when the CIPSO DOI + * is deleted we aren't going to keep the lock. */ + rcu_read_lock(); + entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); + if (entry->type_def.cipsov4 == NULL) { + rcu_read_unlock(); + ret_val = -EINVAL; + goto add_failure; + } + ret_val = netlbl_domhsh_add(entry); + rcu_read_unlock(); + break; + default: + ret_val = -EINVAL; + } + if (ret_val != 0) + goto add_failure; } - if (ret_val != 0) - goto add_failure; + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + NETLBL_E_OK); return 0; add_failure: if (entry) kfree(entry->domain); kfree(entry); + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); return ret_val; } @@ -155,98 +176,87 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) */ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) { - char *domain; - - if (!info->attrs[NLBL_MGMT_A_DOMAIN]) - return -EINVAL; + int ret_val = -EINVAL; + struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb); + int msg_len = netlbl_netlink_payload_len(skb); + u32 count; + u32 iter; + int tmp_size; + unsigned char *domain; + + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) + goto remove_return; - domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); - return netlbl_domhsh_remove(domain); -} + if (msg_len < NETLBL_LEN_U32) + goto remove_return; + count = netlbl_getinc_u32(&msg_ptr, &msg_len); -/** - * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL - * @entry: the domain mapping hash table entry - * @arg: the netlbl_domhsh_walk_arg structure - * - * Description: - * This function is designed to be used as a callback to the - * netlbl_domhsh_walk() function for use in generating a response for a LISTALL - * message. Returns the size of the message on success, negative values on - * failure. - * - */ -static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) -{ - int ret_val = -ENOMEM; - struct netlbl_domhsh_walk_arg *cb_arg = arg; - void *data; - - data = netlbl_netlink_hdr_put(cb_arg->skb, - NETLINK_CB(cb_arg->nl_cb->skb).pid, - cb_arg->seq, - netlbl_mgmt_gnl_family.id, - NLM_F_MULTI, - NLBL_MGMT_C_LISTALL); - if (data == NULL) - goto listall_cb_failure; - - ret_val = nla_put_string(cb_arg->skb, - NLBL_MGMT_A_DOMAIN, - entry->domain); - if (ret_val != 0) - goto listall_cb_failure; - ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type); - if (ret_val != 0) - goto listall_cb_failure; - switch (entry->type) { - case NETLBL_NLTYPE_CIPSOV4: - ret_val = nla_put_u32(cb_arg->skb, - NLBL_MGMT_A_CV4DOI, - entry->type_def.cipsov4->doi); + for (iter = 0; iter < count && msg_len > 0; iter++) { + if (msg_len <= 0) { + ret_val = -EINVAL; + goto remove_return; + } + tmp_size = nla_len(msg_ptr); + domain = nla_data(msg_ptr); + if (tmp_size <= 0 || tmp_size > msg_len || + domain[tmp_size - 1] != '\0') { + ret_val = -EINVAL; + goto remove_return; + } + ret_val = netlbl_domhsh_remove(domain); if (ret_val != 0) - goto listall_cb_failure; - break; + goto remove_return; + msg_ptr = nla_next(msg_ptr, &msg_len); } - cb_arg->seq++; - return genlmsg_end(cb_arg->skb, data); + ret_val = 0; -listall_cb_failure: - genlmsg_cancel(cb_arg->skb, data); +remove_return: + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); return ret_val; } /** - * netlbl_mgmt_listall - Handle a LISTALL message + * netlbl_mgmt_list - Handle a LIST message * @skb: the NETLINK buffer - * @cb: the NETLINK callback + * @info: the Generic NETLINK info block * * Description: - * Process a user generated LISTALL message and dumps the domain hash table in - * a form suitable for use in a kernel generated LISTALL message. Returns zero - * on success, negative values on failure. + * Process a user generated LIST message and dumps the domain hash table in a + * form suitable for use in a kernel generated LIST message. Returns zero on + * success, negative values on failure. * */ -static int netlbl_mgmt_listall(struct sk_buff *skb, - struct netlink_callback *cb) +static int netlbl_mgmt_list(struct sk_buff *skb, struct genl_info *info) { - struct netlbl_domhsh_walk_arg cb_arg; - u32 skip_bkt = cb->args[0]; - u32 skip_chain = cb->args[1]; - - cb_arg.nl_cb = cb; - cb_arg.skb = skb; - cb_arg.seq = cb->nlh->nlmsg_seq; - - netlbl_domhsh_walk(&skip_bkt, - &skip_chain, - netlbl_mgmt_listall_cb, - &cb_arg); - - cb->args[0] = skip_bkt; - cb->args[1] = skip_chain; - return skb->len; + int ret_val = -ENOMEM; + struct sk_buff *ans_skb; + + ans_skb = netlbl_domhsh_dump(NLMSG_SPACE(GENL_HDRLEN)); + if (ans_skb == NULL) + goto list_failure; + netlbl_netlink_hdr_push(ans_skb, + info->snd_pid, + 0, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_LIST); + + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); + if (ret_val != 0) + goto list_failure; + + return 0; + +list_failure: + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); + return ret_val; } /** @@ -262,51 +272,68 @@ static int netlbl_mgmt_listall(struct sk_buff *skb, static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) { int ret_val = -EINVAL; + struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb); + int msg_len = netlbl_netlink_payload_len(skb); struct netlbl_dom_map *entry = NULL; u32 tmp_val; - if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) + goto adddef_failure; + + if (msg_len < NETLBL_LEN_U32) goto adddef_failure; + tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) { ret_val = -ENOMEM; goto adddef_failure; } - entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); + entry->type = tmp_val; switch (entry->type) { case NETLBL_NLTYPE_UNLABELED: ret_val = netlbl_domhsh_add_default(entry); break; case NETLBL_NLTYPE_CIPSOV4: - if (!info->attrs[NLBL_MGMT_A_CV4DOI]) + if (msg_len < NETLBL_LEN_U32) { + ret_val = -EINVAL; goto adddef_failure; - - tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); - /* We should be holding a rcu_read_lock() here while we hold - * the result but since the entry will always be deleted when - * the CIPSO DOI is deleted we aren't going to keep the - * lock. */ + } + tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); + /* We should be holding a rcu_read_lock here while we + * hold the result but since the entry will always be + * deleted when the CIPSO DOI is deleted we are going + * to skip the lock. */ rcu_read_lock(); entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); if (entry->type_def.cipsov4 == NULL) { rcu_read_unlock(); + ret_val = -EINVAL; goto adddef_failure; } ret_val = netlbl_domhsh_add_default(entry); rcu_read_unlock(); break; default: - goto adddef_failure; + ret_val = -EINVAL; } if (ret_val != 0) goto adddef_failure; + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + NETLBL_E_OK); return 0; adddef_failure: kfree(entry); + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); return ret_val; } @@ -322,7 +349,20 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) */ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) { - return netlbl_domhsh_remove_default(); + int ret_val; + + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) + goto removedef_return; + + ret_val = netlbl_domhsh_remove_default(); + +removedef_return: + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); + return ret_val; } /** @@ -339,128 +379,85 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) { int ret_val = -ENOMEM; - struct sk_buff *ans_skb = NULL; - void *data; - struct netlbl_dom_map *entry; + struct sk_buff *ans_skb; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = netlbl_domhsh_dump_default(NLMSG_SPACE(GENL_HDRLEN)); if (ans_skb == NULL) - return -ENOMEM; - data = netlbl_netlink_hdr_put(ans_skb, - info->snd_pid, - info->snd_seq, - netlbl_mgmt_gnl_family.id, - 0, - NLBL_MGMT_C_LISTDEF); - if (data == NULL) goto listdef_failure; + netlbl_netlink_hdr_push(ans_skb, + info->snd_pid, + 0, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_LISTDEF); - rcu_read_lock(); - entry = netlbl_domhsh_getentry(NULL); - if (entry == NULL) { - ret_val = -ENOENT; - goto listdef_failure_lock; - } - ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); - if (ret_val != 0) - goto listdef_failure_lock; - switch (entry->type) { - case NETLBL_NLTYPE_CIPSOV4: - ret_val = nla_put_u32(ans_skb, - NLBL_MGMT_A_CV4DOI, - entry->type_def.cipsov4->doi); - if (ret_val != 0) - goto listdef_failure_lock; - break; - } - rcu_read_unlock(); - - genlmsg_end(ans_skb, data); - - ret_val = genlmsg_unicast(ans_skb, info->snd_pid); + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); if (ret_val != 0) goto listdef_failure; + return 0; -listdef_failure_lock: - rcu_read_unlock(); listdef_failure: - kfree_skb(ans_skb); + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); return ret_val; } /** - * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response - * @skb: the skb to write to - * @seq: the NETLINK sequence number - * @cb: the NETLINK callback - * @protocol: the NetLabel protocol to use in the message + * netlbl_mgmt_modules - Handle a MODULES message + * @skb: the NETLINK buffer + * @info: the Generic NETLINK info block * * Description: - * This function is to be used in conjunction with netlbl_mgmt_protocols() to - * answer a application's PROTOCOLS message. Returns the size of the message - * on success, negative values on failure. + * Process a user generated MODULES message and respond accordingly. * */ -static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, - struct netlink_callback *cb, - u32 protocol) +static int netlbl_mgmt_modules(struct sk_buff *skb, struct genl_info *info) { int ret_val = -ENOMEM; - void *data; - - data = netlbl_netlink_hdr_put(skb, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, - netlbl_mgmt_gnl_family.id, - NLM_F_MULTI, - NLBL_MGMT_C_PROTOCOLS); - if (data == NULL) - goto protocols_cb_failure; - - ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); - if (ret_val != 0) - goto protocols_cb_failure; + size_t data_size; + u32 mod_count; + struct sk_buff *ans_skb = NULL; - return genlmsg_end(skb, data); + /* unlabeled + cipsov4 */ + mod_count = 2; -protocols_cb_failure: - genlmsg_cancel(skb, data); - return ret_val; -} + data_size = GENL_HDRLEN + NETLBL_LEN_U32 + mod_count * NETLBL_LEN_U32; + ans_skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL); + if (ans_skb == NULL) + goto modules_failure; -/** - * netlbl_mgmt_protocols - Handle a PROTOCOLS message - * @skb: the NETLINK buffer - * @cb: the NETLINK callback - * - * Description: - * Process a user generated PROTOCOLS message and respond accordingly. - * - */ -static int netlbl_mgmt_protocols(struct sk_buff *skb, - struct netlink_callback *cb) -{ - u32 protos_sent = cb->args[0]; - - if (protos_sent == 0) { - if (netlbl_mgmt_protocols_cb(skb, - cb, - NETLBL_NLTYPE_UNLABELED) < 0) - goto protocols_return; - protos_sent++; - } - if (protos_sent == 1) { - if (netlbl_mgmt_protocols_cb(skb, - cb, - NETLBL_NLTYPE_CIPSOV4) < 0) - goto protocols_return; - protos_sent++; - } + if (netlbl_netlink_hdr_put(ans_skb, + info->snd_pid, + 0, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_MODULES) == NULL) + goto modules_failure; + + ret_val = nla_put_u32(ans_skb, NLA_U32, mod_count); + if (ret_val != 0) + goto modules_failure; + ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_UNLABELED); + if (ret_val != 0) + goto modules_failure; + ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_CIPSOV4); + if (ret_val != 0) + goto modules_failure; -protocols_return: - cb->args[0] = protos_sent; - return skb->len; + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); + if (ret_val != 0) + goto modules_failure; + + return 0; + +modules_failure: + kfree_skb(ans_skb); + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); + return ret_val; } /** @@ -477,35 +474,35 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) { int ret_val = -ENOMEM; struct sk_buff *ans_skb = NULL; - void *data; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = netlbl_netlink_alloc_skb(0, + GENL_HDRLEN + NETLBL_LEN_U32, + GFP_KERNEL); if (ans_skb == NULL) - return -ENOMEM; - data = netlbl_netlink_hdr_put(ans_skb, - info->snd_pid, - info->snd_seq, - netlbl_mgmt_gnl_family.id, - 0, - NLBL_MGMT_C_VERSION); - if (data == NULL) + goto version_failure; + if (netlbl_netlink_hdr_put(ans_skb, + info->snd_pid, + 0, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_VERSION) == NULL) goto version_failure; - ret_val = nla_put_u32(ans_skb, - NLBL_MGMT_A_VERSION, - NETLBL_PROTO_VERSION); + ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_PROTO_VERSION); if (ret_val != 0) goto version_failure; - genlmsg_end(ans_skb, data); - - ret_val = genlmsg_unicast(ans_skb, info->snd_pid); + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); if (ret_val != 0) goto version_failure; + return 0; version_failure: kfree_skb(ans_skb); + netlbl_netlink_send_ack(info, + netlbl_mgmt_gnl_family.id, + NLBL_MGMT_C_ACK, + -ret_val); return ret_val; } @@ -516,40 +513,35 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) static struct genl_ops netlbl_mgmt_genl_c_add = { .cmd = NLBL_MGMT_C_ADD, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_mgmt_genl_policy, + .flags = 0, .doit = netlbl_mgmt_add, .dumpit = NULL, }; static struct genl_ops netlbl_mgmt_genl_c_remove = { .cmd = NLBL_MGMT_C_REMOVE, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_mgmt_genl_policy, + .flags = 0, .doit = netlbl_mgmt_remove, .dumpit = NULL, }; -static struct genl_ops netlbl_mgmt_genl_c_listall = { - .cmd = NLBL_MGMT_C_LISTALL, +static struct genl_ops netlbl_mgmt_genl_c_list = { + .cmd = NLBL_MGMT_C_LIST, .flags = 0, - .policy = netlbl_mgmt_genl_policy, - .doit = NULL, - .dumpit = netlbl_mgmt_listall, + .doit = netlbl_mgmt_list, + .dumpit = NULL, }; static struct genl_ops netlbl_mgmt_genl_c_adddef = { .cmd = NLBL_MGMT_C_ADDDEF, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_mgmt_genl_policy, + .flags = 0, .doit = netlbl_mgmt_adddef, .dumpit = NULL, }; static struct genl_ops netlbl_mgmt_genl_c_removedef = { .cmd = NLBL_MGMT_C_REMOVEDEF, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_mgmt_genl_policy, + .flags = 0, .doit = netlbl_mgmt_removedef, .dumpit = NULL, }; @@ -557,23 +549,20 @@ static struct genl_ops netlbl_mgmt_genl_c_removedef = { static struct genl_ops netlbl_mgmt_genl_c_listdef = { .cmd = NLBL_MGMT_C_LISTDEF, .flags = 0, - .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_listdef, .dumpit = NULL, }; -static struct genl_ops netlbl_mgmt_genl_c_protocols = { - .cmd = NLBL_MGMT_C_PROTOCOLS, +static struct genl_ops netlbl_mgmt_genl_c_modules = { + .cmd = NLBL_MGMT_C_MODULES, .flags = 0, - .policy = netlbl_mgmt_genl_policy, - .doit = NULL, - .dumpit = netlbl_mgmt_protocols, + .doit = netlbl_mgmt_modules, + .dumpit = NULL, }; static struct genl_ops netlbl_mgmt_genl_c_version = { .cmd = NLBL_MGMT_C_VERSION, .flags = 0, - .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_version, .dumpit = NULL, }; @@ -607,7 +596,7 @@ int netlbl_mgmt_genl_init(void) if (ret_val != 0) return ret_val; ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_listall); + &netlbl_mgmt_genl_c_list); if (ret_val != 0) return ret_val; ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, @@ -623,7 +612,7 @@ int netlbl_mgmt_genl_init(void) if (ret_val != 0) return ret_val; ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_protocols); + &netlbl_mgmt_genl_c_modules); if (ret_val != 0) return ret_val; ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, diff --git a/trunk/net/netlabel/netlabel_mgmt.h b/trunk/net/netlabel/netlabel_mgmt.h index 3642d3bfc8eb..fd6c6acbfa08 100644 --- a/trunk/net/netlabel/netlabel_mgmt.h +++ b/trunk/net/netlabel/netlabel_mgmt.h @@ -34,137 +34,212 @@ #include /* - * The following NetLabel payloads are supported by the management interface. + * The following NetLabel payloads are supported by the management interface, + * all of which are preceeded by the nlmsghdr struct. + * + * o ACK: + * Sent by the kernel in response to an applications message, applications + * should never send this message. + * + * +----------------------+-----------------------+ + * | seq number (32 bits) | return code (32 bits) | + * +----------------------+-----------------------+ + * + * seq number: the sequence number of the original message, taken from the + * nlmsghdr structure + * return code: return value, based on errno values * * o ADD: * Sent by an application to add a domain mapping to the NetLabel system. + * The kernel should respond with an ACK. + * + * +-------------------+ + * | domains (32 bits) | ... + * +-------------------+ + * + * domains: the number of domains in the message + * + * +--------------------------+-------------------------+ + * | domain string (variable) | protocol type (32 bits) | ... + * +--------------------------+-------------------------+ * - * Required attributes: + * +-------------- ---- --- -- - + * | mapping data ... repeated + * +-------------- ---- --- -- - * - * NLBL_MGMT_A_DOMAIN - * NLBL_MGMT_A_PROTOCOL + * domain string: the domain string, NULL terminated + * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) + * mapping data: specific to the map type (see below) * - * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: + * NETLBL_NLTYPE_UNLABELED * - * NLBL_MGMT_A_CV4DOI + * No mapping data for this protocol type. * - * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. + * NETLBL_NLTYPE_CIPSOV4 + * + * +---------------+ + * | doi (32 bits) | + * +---------------+ + * + * doi: the CIPSO DOI value * * o REMOVE: * Sent by an application to remove a domain mapping from the NetLabel - * system. + * system. The kernel should ACK this message. + * + * +-------------------+ + * | domains (32 bits) | ... + * +-------------------+ * - * Required attributes: + * domains: the number of domains in the message * - * NLBL_MGMT_A_DOMAIN + * +--------------------------+ + * | domain string (variable) | ... + * +--------------------------+ * - * o LISTALL: + * domain string: the domain string, NULL terminated + * + * o LIST: * This message can be sent either from an application or by the kernel in - * response to an application generated LISTALL message. When sent by an - * application there is no payload and the NLM_F_DUMP flag should be set. - * The kernel should respond with a series of the following messages. + * response to an application generated LIST message. When sent by an + * application there is no payload. The kernel should respond to a LIST + * message either with a LIST message on success or an ACK message on + * failure. + * + * +-------------------+ + * | domains (32 bits) | ... + * +-------------------+ + * + * domains: the number of domains in the message * - * Required attributes: + * +--------------------------+ + * | domain string (variable) | ... + * +--------------------------+ * - * NLBL_MGMT_A_DOMAIN - * NLBL_MGMT_A_PROTOCOL + * +-------------------------+-------------- ---- --- -- - + * | protocol type (32 bits) | mapping data ... repeated + * +-------------------------+-------------- ---- --- -- - * - * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: + * domain string: the domain string, NULL terminated + * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) + * mapping data: specific to the map type (see below) * - * NLBL_MGMT_A_CV4DOI + * NETLBL_NLTYPE_UNLABELED * - * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. + * No mapping data for this protocol type. + * + * NETLBL_NLTYPE_CIPSOV4 + * + * +----------------+---------------+ + * | type (32 bits) | doi (32 bits) | + * +----------------+---------------+ + * + * type: the CIPSO mapping table type (defined in the cipso_ipv4.h header + * as CIPSO_V4_MAP_*) + * doi: the CIPSO DOI value * * o ADDDEF: * Sent by an application to set the default domain mapping for the NetLabel - * system. + * system. The kernel should respond with an ACK. * - * Required attributes: + * +-------------------------+-------------- ---- --- -- - + * | protocol type (32 bits) | mapping data ... repeated + * +-------------------------+-------------- ---- --- -- - * - * NLBL_MGMT_A_PROTOCOL + * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) + * mapping data: specific to the map type (see below) * - * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: + * NETLBL_NLTYPE_UNLABELED * - * NLBL_MGMT_A_CV4DOI + * No mapping data for this protocol type. * - * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. + * NETLBL_NLTYPE_CIPSOV4 + * + * +---------------+ + * | doi (32 bits) | + * +---------------+ + * + * doi: the CIPSO DOI value * * o REMOVEDEF: * Sent by an application to remove the default domain mapping from the - * NetLabel system, there is no payload. + * NetLabel system, there is no payload. The kernel should ACK this message. * * o LISTDEF: * This message can be sent either from an application or by the kernel in * response to an application generated LISTDEF message. When sent by an - * application there is no payload. On success the kernel should send a - * response using the following format. + * application there is no payload. The kernel should respond to a + * LISTDEF message either with a LISTDEF message on success or an ACK message + * on failure. + * + * +-------------------------+-------------- ---- --- -- - + * | protocol type (32 bits) | mapping data ... repeated + * +-------------------------+-------------- ---- --- -- - * - * Required attributes: + * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) + * mapping data: specific to the map type (see below) * - * NLBL_MGMT_A_PROTOCOL + * NETLBL_NLTYPE_UNLABELED * - * If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required: + * No mapping data for this protocol type. * - * NLBL_MGMT_A_CV4DOI + * NETLBL_NLTYPE_CIPSOV4 * - * If using NETLBL_NLTYPE_UNLABELED no other attributes are required. + * +----------------+---------------+ + * | type (32 bits) | doi (32 bits) | + * +----------------+---------------+ * - * o PROTOCOLS: - * Sent by an application to request a list of configured NetLabel protocols - * in the kernel. When sent by an application there is no payload and the - * NLM_F_DUMP flag should be set. The kernel should respond with a series of - * the following messages. + * type: the CIPSO mapping table type (defined in the cipso_ipv4.h header + * as CIPSO_V4_MAP_*) + * doi: the CIPSO DOI value * - * Required attributes: + * o MODULES: + * Sent by an application to request a list of configured NetLabel modules + * in the kernel. When sent by an application there is no payload. * - * NLBL_MGMT_A_PROTOCOL + * +-------------------+ + * | modules (32 bits) | ... + * +-------------------+ + * + * modules: the number of modules in the message, if this is an application + * generated message and the value is zero then return a list of + * the configured modules + * + * +------------------+ + * | module (32 bits) | ... repeated + * +------------------+ + * + * module: the module number as defined by NETLBL_NLTYPE_* * * o VERSION: - * Sent by an application to request the NetLabel version. When sent by an - * application there is no payload. This message type is also used by the - * kernel to respond to an VERSION request. + * Sent by an application to request the NetLabel version string. When sent + * by an application there is no payload. This message type is also used by + * the kernel to respond to an VERSION request. * - * Required attributes: + * +-------------------+ + * | version (32 bits) | + * +-------------------+ * - * NLBL_MGMT_A_VERSION + * version: the protocol version number * */ /* NetLabel Management commands */ enum { NLBL_MGMT_C_UNSPEC, + NLBL_MGMT_C_ACK, NLBL_MGMT_C_ADD, NLBL_MGMT_C_REMOVE, - NLBL_MGMT_C_LISTALL, + NLBL_MGMT_C_LIST, NLBL_MGMT_C_ADDDEF, NLBL_MGMT_C_REMOVEDEF, NLBL_MGMT_C_LISTDEF, - NLBL_MGMT_C_PROTOCOLS, + NLBL_MGMT_C_MODULES, NLBL_MGMT_C_VERSION, __NLBL_MGMT_C_MAX, }; #define NLBL_MGMT_C_MAX (__NLBL_MGMT_C_MAX - 1) -/* NetLabel Management attributes */ -enum { - NLBL_MGMT_A_UNSPEC, - NLBL_MGMT_A_DOMAIN, - /* (NLA_NUL_STRING) - * the NULL terminated LSM domain string */ - NLBL_MGMT_A_PROTOCOL, - /* (NLA_U32) - * the NetLabel protocol type (defined by NETLBL_NLTYPE_*) */ - NLBL_MGMT_A_VERSION, - /* (NLA_U32) - * the NetLabel protocol version number (defined by - * NETLBL_PROTO_VERSION) */ - NLBL_MGMT_A_CV4DOI, - /* (NLA_U32) - * the CIPSOv4 DOI value */ - __NLBL_MGMT_A_MAX, -}; -#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1) - /* NetLabel protocol functions */ int netlbl_mgmt_genl_init(void); diff --git a/trunk/net/netlabel/netlabel_unlabeled.c b/trunk/net/netlabel/netlabel_unlabeled.c index 440f5c4e1e2d..785f4960e0d3 100644 --- a/trunk/net/netlabel/netlabel_unlabeled.c +++ b/trunk/net/netlabel/netlabel_unlabeled.c @@ -55,13 +55,9 @@ static struct genl_family netlbl_unlabel_gnl_family = { .hdrsize = 0, .name = NETLBL_NLTYPE_UNLABELED_NAME, .version = NETLBL_PROTO_VERSION, - .maxattr = NLBL_UNLABEL_A_MAX, + .maxattr = 0, }; -/* NetLabel Netlink attribute policy */ -static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { - [NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 }, -}; /* * NetLabel Command Handlers @@ -79,18 +75,31 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = { */ static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info) { - int ret_val = -EINVAL; - u8 value; + int ret_val; + struct nlattr *data = netlbl_netlink_payload_data(skb); + u32 value; + + ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); + if (ret_val != 0) + return ret_val; - if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) { - value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]); + if (netlbl_netlink_payload_len(skb) == NETLBL_LEN_U32) { + value = nla_get_u32(data); if (value == 1 || value == 0) { atomic_set(&netlabel_unlabel_accept_flg, value); - ret_val = 0; + netlbl_netlink_send_ack(info, + netlbl_unlabel_gnl_family.id, + NLBL_UNLABEL_C_ACK, + NETLBL_E_OK); + return 0; } } - return ret_val; + netlbl_netlink_send_ack(info, + netlbl_unlabel_gnl_family.id, + NLBL_UNLABEL_C_ACK, + EINVAL); + return -EINVAL; } /** @@ -105,39 +114,39 @@ static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info) */ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) { - int ret_val = -EINVAL; + int ret_val = -ENOMEM; struct sk_buff *ans_skb; - void *data; - ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + ans_skb = netlbl_netlink_alloc_skb(0, + GENL_HDRLEN + NETLBL_LEN_U32, + GFP_KERNEL); if (ans_skb == NULL) goto list_failure; - data = netlbl_netlink_hdr_put(ans_skb, - info->snd_pid, - info->snd_seq, - netlbl_unlabel_gnl_family.id, - 0, - NLBL_UNLABEL_C_LIST); - if (data == NULL) { - ret_val = -ENOMEM; + + if (netlbl_netlink_hdr_put(ans_skb, + info->snd_pid, + 0, + netlbl_unlabel_gnl_family.id, + NLBL_UNLABEL_C_LIST) == NULL) goto list_failure; - } - ret_val = nla_put_u8(ans_skb, - NLBL_UNLABEL_A_ACPTFLG, - atomic_read(&netlabel_unlabel_accept_flg)); + ret_val = nla_put_u32(ans_skb, + NLA_U32, + atomic_read(&netlabel_unlabel_accept_flg)); if (ret_val != 0) goto list_failure; - genlmsg_end(ans_skb, data); - - ret_val = genlmsg_unicast(ans_skb, info->snd_pid); + ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); if (ret_val != 0) goto list_failure; + return 0; list_failure: - kfree(ans_skb); + netlbl_netlink_send_ack(info, + netlbl_unlabel_gnl_family.id, + NLBL_UNLABEL_C_ACK, + -ret_val); return ret_val; } @@ -148,8 +157,7 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) static struct genl_ops netlbl_unlabel_genl_c_accept = { .cmd = NLBL_UNLABEL_C_ACCEPT, - .flags = GENL_ADMIN_PERM, - .policy = netlbl_unlabel_genl_policy, + .flags = 0, .doit = netlbl_unlabel_accept, .dumpit = NULL, }; @@ -157,7 +165,6 @@ static struct genl_ops netlbl_unlabel_genl_c_accept = { static struct genl_ops netlbl_unlabel_genl_c_list = { .cmd = NLBL_UNLABEL_C_LIST, .flags = 0, - .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_list, .dumpit = NULL, }; @@ -211,8 +218,10 @@ int netlbl_unlabel_genl_init(void) */ int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr) { - if (atomic_read(&netlabel_unlabel_accept_flg) == 1) - return netlbl_secattr_init(secattr); + if (atomic_read(&netlabel_unlabel_accept_flg) == 1) { + memset(secattr, 0, sizeof(*secattr)); + return 0; + } return -ENOMSG; } diff --git a/trunk/net/netlabel/netlabel_unlabeled.h b/trunk/net/netlabel/netlabel_unlabeled.h index c2917fbb42cf..f300e54e14b6 100644 --- a/trunk/net/netlabel/netlabel_unlabeled.h +++ b/trunk/net/netlabel/netlabel_unlabeled.h @@ -36,47 +36,56 @@ /* * The following NetLabel payloads are supported by the Unlabeled subsystem. * + * o ACK: + * Sent by the kernel in response to an applications message, applications + * should never send this message. + * + * +----------------------+-----------------------+ + * | seq number (32 bits) | return code (32 bits) | + * +----------------------+-----------------------+ + * + * seq number: the sequence number of the original message, taken from the + * nlmsghdr structure + * return code: return value, based on errno values + * * o ACCEPT * This message is sent from an application to specify if the kernel should * allow unlabled packets to pass if they do not match any of the static * mappings defined in the unlabeled module. * - * Required attributes: + * +-----------------+ + * | allow (32 bits) | + * +-----------------+ * - * NLBL_UNLABEL_A_ACPTFLG + * allow: if true (1) then allow the packets to pass, if false (0) then + * reject the packets * * o LIST * This message can be sent either from an application or by the kernel in * response to an application generated LIST message. When sent by an * application there is no payload. The kernel should respond to a LIST - * message with a LIST message on success. + * message either with a LIST message on success or an ACK message on + * failure. * - * Required attributes: + * +-----------------------+ + * | accept flag (32 bits) | + * +-----------------------+ * - * NLBL_UNLABEL_A_ACPTFLG + * accept flag: if true (1) then unlabeled packets are allowed to pass, + * if false (0) then unlabeled packets are rejected * */ /* NetLabel Unlabeled commands */ enum { NLBL_UNLABEL_C_UNSPEC, + NLBL_UNLABEL_C_ACK, NLBL_UNLABEL_C_ACCEPT, NLBL_UNLABEL_C_LIST, __NLBL_UNLABEL_C_MAX, }; #define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1) -/* NetLabel Unlabeled attributes */ -enum { - NLBL_UNLABEL_A_UNSPEC, - NLBL_UNLABEL_A_ACPTFLG, - /* (NLA_U8) - * if true then unlabeled packets are allowed to pass, else unlabeled - * packets are rejected */ - __NLBL_UNLABEL_A_MAX, -}; -#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1) - /* NetLabel protocol functions */ int netlbl_unlabel_genl_init(void); diff --git a/trunk/net/netlabel/netlabel_user.c b/trunk/net/netlabel/netlabel_user.c index eeb7d768d2bb..73cbe66e42ff 100644 --- a/trunk/net/netlabel/netlabel_user.c +++ b/trunk/net/netlabel/netlabel_user.c @@ -74,3 +74,85 @@ int netlbl_netlink_init(void) return 0; } + +/* + * NetLabel Common Protocol Functions + */ + +/** + * netlbl_netlink_send_ack - Send an ACK message + * @info: the generic NETLINK information + * @genl_family: the generic NETLINK family ID value + * @ack_cmd: the generic NETLINK family ACK command value + * @ret_code: return code to use + * + * Description: + * This function sends an ACK message to the sender of the NETLINK message + * specified by @info. + * + */ +void netlbl_netlink_send_ack(const struct genl_info *info, + u32 genl_family, + u8 ack_cmd, + u32 ret_code) +{ + size_t data_size; + struct sk_buff *skb; + + data_size = GENL_HDRLEN + 2 * NETLBL_LEN_U32; + skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL); + if (skb == NULL) + return; + + if (netlbl_netlink_hdr_put(skb, + info->snd_pid, + 0, + genl_family, + ack_cmd) == NULL) + goto send_ack_failure; + + if (nla_put_u32(skb, NLA_U32, info->snd_seq) != 0) + goto send_ack_failure; + if (nla_put_u32(skb, NLA_U32, ret_code) != 0) + goto send_ack_failure; + + netlbl_netlink_snd(skb, info->snd_pid); + return; + +send_ack_failure: + kfree_skb(skb); +} + +/* + * NETLINK I/O Functions + */ + +/** + * netlbl_netlink_snd - Send a NetLabel message + * @skb: NetLabel message + * @pid: destination PID + * + * Description: + * Sends a unicast NetLabel message over the NETLINK socket. + * + */ +int netlbl_netlink_snd(struct sk_buff *skb, u32 pid) +{ + return genlmsg_unicast(skb, pid); +} + +/** + * netlbl_netlink_snd - Send a NetLabel message + * @skb: NetLabel message + * @pid: sending PID + * @group: multicast group id + * + * Description: + * Sends a multicast NetLabel message over the NETLINK socket to all members + * of @group except @pid. + * + */ +int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group) +{ + return genlmsg_multicast(skb, pid, group, GFP_KERNEL); +} diff --git a/trunk/net/netlabel/netlabel_user.h b/trunk/net/netlabel/netlabel_user.h index 3f9386b917df..385a6c7488c6 100644 --- a/trunk/net/netlabel/netlabel_user.h +++ b/trunk/net/netlabel/netlabel_user.h @@ -40,6 +40,72 @@ /* NetLabel NETLINK helper functions */ +/** + * netlbl_netlink_cap_check - Check the NETLINK msg capabilities + * @skb: the NETLINK buffer + * @req_cap: the required capability + * + * Description: + * Check the NETLINK buffer's capabilities against the required capabilities. + * Returns zero on success, negative values on failure. + * + */ +static inline int netlbl_netlink_cap_check(const struct sk_buff *skb, + kernel_cap_t req_cap) +{ + if (cap_raised(NETLINK_CB(skb).eff_cap, req_cap)) + return 0; + return -EPERM; +} + +/** + * netlbl_getinc_u8 - Read a u8 value from a nlattr stream and move on + * @nla: the attribute + * @rem_len: remaining length + * + * Description: + * Return a u8 value pointed to by @nla and advance it to the next attribute. + * + */ +static inline u8 netlbl_getinc_u8(struct nlattr **nla, int *rem_len) +{ + u8 val = nla_get_u8(*nla); + *nla = nla_next(*nla, rem_len); + return val; +} + +/** + * netlbl_getinc_u16 - Read a u16 value from a nlattr stream and move on + * @nla: the attribute + * @rem_len: remaining length + * + * Description: + * Return a u16 value pointed to by @nla and advance it to the next attribute. + * + */ +static inline u16 netlbl_getinc_u16(struct nlattr **nla, int *rem_len) +{ + u16 val = nla_get_u16(*nla); + *nla = nla_next(*nla, rem_len); + return val; +} + +/** + * netlbl_getinc_u32 - Read a u32 value from a nlattr stream and move on + * @nla: the attribute + * @rem_len: remaining length + * + * Description: + * Return a u32 value pointed to by @nla and advance it to the next attribute. + * + */ +static inline u32 netlbl_getinc_u32(struct nlattr **nla, int *rem_len) +{ + u32 val = nla_get_u32(*nla); + *nla = nla_next(*nla, rem_len); + return val; +} + /** * netlbl_netlink_hdr_put - Write the NETLINK buffers into a sk_buff * @skb: the packet @@ -58,7 +124,6 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int type, - int flags, u8 cmd) { return genlmsg_put(skb, @@ -66,13 +131,85 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb, seq, type, 0, - flags, + 0, cmd, NETLBL_PROTO_VERSION); } +/** + * netlbl_netlink_hdr_push - Write the NETLINK buffers into a sk_buff + * @skb: the packet + * @pid: the PID of the receipient + * @seq: the sequence number + * @type: the generic NETLINK message family type + * @cmd: command + * + * Description: + * Write both a NETLINK nlmsghdr structure and a Generic NETLINK genlmsghdr + * struct to the packet. + * + */ +static inline void netlbl_netlink_hdr_push(struct sk_buff *skb, + u32 pid, + u32 seq, + int type, + u8 cmd) + +{ + struct nlmsghdr *nlh; + struct genlmsghdr *hdr; + + nlh = (struct nlmsghdr *)skb_push(skb, NLMSG_SPACE(GENL_HDRLEN)); + nlh->nlmsg_type = type; + nlh->nlmsg_len = skb->len; + nlh->nlmsg_flags = 0; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = seq; + + hdr = nlmsg_data(nlh); + hdr->cmd = cmd; + hdr->version = NETLBL_PROTO_VERSION; + hdr->reserved = 0; +} + +/** + * netlbl_netlink_payload_len - Return the length of the payload + * @skb: the NETLINK buffer + * + * Description: + * This function returns the length of the NetLabel payload. + * + */ +static inline u32 netlbl_netlink_payload_len(const struct sk_buff *skb) +{ + return nlmsg_len((struct nlmsghdr *)skb->data) - GENL_HDRLEN; +} + +/** + * netlbl_netlink_payload_data - Returns a pointer to the start of the payload + * @skb: the NETLINK buffer + * + * Description: + * This function returns a pointer to the start of the NetLabel payload. + * + */ +static inline void *netlbl_netlink_payload_data(const struct sk_buff *skb) +{ + return (unsigned char *)nlmsg_data((struct nlmsghdr *)skb->data) + + GENL_HDRLEN; +} + +/* NetLabel common protocol functions */ + +void netlbl_netlink_send_ack(const struct genl_info *info, + u32 genl_family, + u8 ack_cmd, + u32 ret_code); + /* NetLabel NETLINK I/O functions */ int netlbl_netlink_init(void); +int netlbl_netlink_snd(struct sk_buff *skb, u32 pid); +int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group); #endif diff --git a/trunk/security/selinux/ss/services.c b/trunk/security/selinux/ss/services.c index 22ed17c17718..7eb69a602d8f 100644 --- a/trunk/security/selinux/ss/services.c +++ b/trunk/security/selinux/ss/services.c @@ -2502,24 +2502,14 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) { struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; struct sk_security_struct *sksec = sk->sk_security; - struct netlbl_lsm_secattr secattr; - u32 nlbl_peer_sid; sksec->sclass = isec->sclass; if (sk->sk_family != PF_INET) return; - netlbl_secattr_init(&secattr); - if (netlbl_sock_getattr(sk, &secattr) == 0 && - selinux_netlbl_secattr_to_sid(NULL, - &secattr, - sksec->sid, - &nlbl_peer_sid) == 0) - sksec->peer_sid = nlbl_peer_sid; - netlbl_secattr_destroy(&secattr, 0); - sksec->nlbl_state = NLBL_REQUIRE; + sksec->peer_sid = sksec->sid; /* Try to set the NetLabel on the socket to save time later, if we fail * here we will pick up the pieces in later calls to @@ -2611,7 +2601,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, u32 netlbl_sid; u32 recv_perm; - rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &netlbl_sid); + rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid); if (rc != 0) return rc; @@ -2620,13 +2610,13 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, switch (sksec->sclass) { case SECCLASS_UDP_SOCKET: - recv_perm = UDP_SOCKET__RECVFROM; + recv_perm = UDP_SOCKET__RECV_MSG; break; case SECCLASS_TCP_SOCKET: - recv_perm = TCP_SOCKET__RECVFROM; + recv_perm = TCP_SOCKET__RECV_MSG; break; default: - recv_perm = RAWIP_SOCKET__RECVFROM; + recv_perm = RAWIP_SOCKET__RECV_MSG; } rc = avc_has_perm(sksec->sid, diff --git a/trunk/sound/sparc/amd7930.c b/trunk/sound/sparc/amd7930.c index be0bd503f013..2bd8e40b8541 100644 --- a/trunk/sound/sparc/amd7930.c +++ b/trunk/sound/sparc/amd7930.c @@ -755,7 +755,7 @@ static struct snd_pcm_ops snd_amd7930_capture_ops = { .pointer = snd_amd7930_capture_pointer, }; -static int __devinit snd_amd7930_pcm(struct snd_amd7930 *amd) +static int __init snd_amd7930_pcm(struct snd_amd7930 *amd) { struct snd_pcm *pcm; int err; @@ -870,7 +870,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem return change; } -static struct snd_kcontrol_new amd7930_controls[] __devinitdata = { +static struct snd_kcontrol_new amd7930_controls[] __initdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Monitor Volume", @@ -900,7 +900,7 @@ static struct snd_kcontrol_new amd7930_controls[] __devinitdata = { }, }; -static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd) +static int __init snd_amd7930_mixer(struct snd_amd7930 *amd) { struct snd_card *card; int idx, err; @@ -945,11 +945,11 @@ static struct snd_device_ops snd_amd7930_dev_ops = { .dev_free = snd_amd7930_dev_free, }; -static int __devinit snd_amd7930_create(struct snd_card *card, - struct resource *rp, - unsigned int reg_size, - int irq, int dev, - struct snd_amd7930 **ramd) +static int __init snd_amd7930_create(struct snd_card *card, + struct resource *rp, + unsigned int reg_size, + int irq, int dev, + struct snd_amd7930 **ramd) { unsigned long flags; struct snd_amd7930 *amd; @@ -1013,7 +1013,7 @@ static int __devinit snd_amd7930_create(struct snd_card *card, return 0; } -static int __devinit amd7930_attach_common(struct resource *rp, int irq) +static int __init amd7930_attach_common(struct resource *rp, int irq) { static int dev_num; struct snd_card *card; @@ -1065,7 +1065,7 @@ static int __devinit amd7930_attach_common(struct resource *rp, int irq) return err; } -static int __devinit amd7930_obio_attach(struct device_node *dp) +static int __init amd7930_obio_attach(struct device_node *dp) { struct linux_prom_registers *regs; struct linux_prom_irqs *irqp;