Home » Mailing lists » Devel » [PATCH 1/2] iptables 32bit compat layer  
	
		
		
			| Re: [PATCH] iptables 32bit compat layer [message #2327 is a reply to message #2325] | 
			Wed, 29 March 2006 11:36    | 
		 
		
			
				
				
				
					
						  
						Mishin Dmitry
						 Messages: 112 Registered: February 2006 
						
					 | 
					Senior Member  | 
					 | 
		 
		 
	 | 
 
	
		On Wednesday 29 March 2006 13:28, Patrick McHardy wrote: 
> Dmitry Mishin wrote: 
> > This patch extends current iptables compatibility layer in order to get 
> > 32bit iptables to work on 64bit kernel. Current layer is insufficient due 
> > to alignment checks both in kernel and user space tools. 
> > 
> > Patch is for current net-2.6.17 with addition of move of 
> > ipt_entry_{match| target} definitions to xt_entry_{match|target}. 
> 
> Thanks, this looks good. Two small issues so far: 
> > diff --git a/net/compat.c b/net/compat.c 
> > index 13177a1..6a7028e 100644 
> > --- a/net/compat.c 
> > +++ b/net/compat.c 
> > @@ -476,8 +476,7 @@ asmlinkage long compat_sys_setsockopt(in 
> >  	int err; 
> >  	struct socket *sock; 
> > 
> > -	/* SO_SET_REPLACE seems to be the same in all levels */ 
> > -	if (optname == IPT_SO_SET_REPLACE) 
> > +	if (level == SOL_IPV6 && optname == IPT_SO_SET_REPLACE) 
> >  		return do_netfilter_replace(fd, level, optname, 
> >  					    optval, optlen); 
> 
> I don't understand the reason for this change. If its not a mistake, 
> it would make more sense to check for IP6T_SO_SET_REPLACE I guess .. 
IP6T_SO_SET_REPLACE == IPT_SO_SET_REPLACE == XT_SO_SET_REPLACE. 
Rename will require respective #include directive rename, so, I just leave  
this as it is. BTW, I'll make respective patch for IPV6 in the near future  
and this hunk will be removed at all. 
  
> 
> > +#ifdef CONFIG_COMPAT 
> > +void xt_compat_lock(int af) 
> > +{ 
> > +	down(&xt[af].compat_mutex); 
> > +} 
> > +EXPORT_SYMBOL_GPL(xt_compat_lock); 
> > + 
> > +void xt_compat_unlock(int af) 
> > +{ 
> > +	up(&xt[af].compat_mutex); 
> > +} 
> > +EXPORT_SYMBOL_GPL(xt_compat_unlock); 
> > +#endif 
> 
> Won't a seperate compat-mutex introduce races between compat- and 
> non-compat users? BTW, the up/down calls have been replaced by the 
> new mutex API in Linus' tree, please resend the patch against the 
> current tree. 
compat_mutex is always over xt[af].mutex and can't be taken under the last  
one, so, there should be no races. 
New patch is attached. 
 
--  
Thanks, 
Dmitry. 
 
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h 
index 1350e47..f6bdef8 100644 
--- a/include/linux/netfilter/x_tables.h 
+++ b/include/linux/netfilter/x_tables.h 
@@ -142,6 +142,12 @@ struct xt_counters_info 
 #define ASSERT_WRITE_LOCK(x) 
 #include <linux/netfilter_ipv4/listhelp.h> 
  
+#ifdef CONFIG_COMPAT 
+#define COMPAT_TO_USER		1 
+#define COMPAT_FROM_USER	-1 
+#define COMPAT_CALC_SIZE	0 
+#endif 
+ 
 struct xt_match 
 { 
 	struct list_head list; 
@@ -175,6 +181,9 @@ struct xt_match 
 	void (*destroy)(const struct xt_match *match, void *matchinfo, 
 			unsigned int matchinfosize); 
  
+	/* Called when userspace align differs from kernel space one */ 
+	int (*compat)(void *match, void **dstptr, int *size, int convert); 
+ 
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */ 
 	struct module *me; 
  
@@ -220,6 +229,9 @@ struct xt_target 
 	void (*destroy)(const struct xt_target *target, void *targinfo, 
 			unsigned int targinfosize); 
  
+	/* Called when userspace align differs from kernel space one */ 
+	int (*compat)(void *target, void **dstptr, int *size, int convert); 
+ 
 	/* Set this to THIS_MODULE if you are a module, otherwise NULL */ 
 	struct module *me; 
  
@@ -314,6 +326,61 @@ extern void xt_proto_fini(int af); 
 extern struct xt_table_info *xt_alloc_table_info(unsigned int size); 
 extern void xt_free_table_info(struct xt_table_info *info); 
  
+#ifdef CONFIG_COMPAT 
+#include <net/compat.h> 
+ 
+struct compat_xt_entry_match 
+{ 
+	union { 
+		struct { 
+			u_int16_t match_size; 
+			char name[XT_FUNCTION_MAXNAMELEN - 1]; 
+			u_int8_t revision; 
+		} user; 
+		u_int16_t match_size; 
+	} u; 
+	unsigned char data[0]; 
+}; 
+ 
+struct compat_xt_entry_target 
+{ 
+	union { 
+		struct { 
+			u_int16_t target_size; 
+			char name[XT_FUNCTION_MAXNAMELEN - 1]; 
+			u_int8_t revision; 
+		} user; 
+		u_int16_t target_size; 
+	} u; 
+	unsigned char data[0]; 
+}; 
+ 
+/* FIXME: this works only on 32 bit tasks 
+ * need to change whole approach in order to calculate align as function of 
+ * current task alignment */ 
+ 
+struct compat_xt_counters 
+{ 
+	u_int32_t cnt[4]; 
+}; 
+ 
+struct compat_xt_counters_info 
+{ 
+	char name[XT_TABLE_MAXNAMELEN]; 
+	compat_uint_t num_counters; 
+	struct compat_xt_counters counters[0]; 
+}; 
+ 
+#define COMPAT_XT_ALIGN(s) (((s) + (__alignof__(struct compat_xt_counters)-1)) \ 
+		& ~(__alignof__(struct compat_xt_counters)-1)) 
+ 
+extern void xt_compat_lock(int af); 
+extern void xt_compat_unlock(int af); 
+extern int xt_compat_match(void *match, void **dstptr, int *size, int convert); 
+extern int xt_compat_target(void *target, void **dstptr, int *size, 
+		int convert); 
+ 
+#endif /* CONFIG_COMPAT */ 
 #endif /* __KERNEL__ */ 
  
 #endif /* _X_TABLES_H */ 
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h 
index d5b8c0d..c0dac16 100644 
--- a/include/linux/netfilter_ipv4/ip_tables.h 
+++ b/include/linux/netfilter_ipv4/ip_tables.h 
@@ -316,5 +316,23 @@ extern unsigned int ipt_do_table(struct  
 				 void *userdata); 
  
 #define IPT_ALIGN(s) XT_ALIGN(s) 
+ 
+#ifdef CONFIG_COMPAT 
+#include <net/compat.h> 
+ 
+struct compat_ipt_entry 
+{ 
+	struct ipt_ip ip; 
+	compat_uint_t nfcache; 
+	u_int16_t target_offset; 
+	u_int16_t next_offset; 
+	compat_uint_t comefrom; 
+	struct compat_xt_counters counters; 
+	unsigned char elems[0]; 
+}; 
+ 
+#define COMPAT_IPT_ALIGN(s) 	COMPAT_XT_ALIGN(s) 
+ 
+#endif /* CONFIG_COMPAT */ 
 #endif /*__KERNEL__*/ 
 #endif /* _IPTABLES_H */ 
diff --git a/net/compat.c b/net/compat.c 
index 8fd37cd..d5d69fa 100644 
--- a/net/compat.c 
+++ b/net/compat.c 
@@ -476,8 +476,7 @@ asmlinkage long compat_sys_setsockopt(in 
 	int err; 
 	struct socket *sock; 
  
-	/* SO_SET_REPLACE seems to be the same in all levels */ 
-	if (optname == IPT_SO_SET_REPLACE) 
+	if (level == SOL_IPV6 && optname == IPT_SO_SET_REPLACE) 
 		return do_netfilter_replace(fd, level, optname, 
 					    optval, optlen); 
  
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c 
index a7b194c..34df287 100644 
--- a/net/ipv4/netfilter/ip_tables.c 
+++ b/net/ipv4/netfilter/ip_tables.c 
@@ -24,6 +24,7 @@ 
 #include <linux/module.h> 
 #include <linux/icmp.h> 
 #include <net/ip.h> 
+#include <net/compat.h> 
 #include <asm/uaccess.h> 
 #include <linux/mutex.h> 
 #include <linux/proc_fs.h> 
@@ -799,17 +800,11 @@ get_counters(const struct xt_table_info  
 	} 
 } 
  
-static int 
-copy_entries_to_user(unsigned int total_size, 
-		     struct ipt_table *table, 
-		     void __user *userptr) 
+static inline struct xt_counters * alloc_counters(struct ipt_table *table) 
 { 
-	unsigned int off, num, countersize; 
-	struct ipt_entry *e; 
+	unsigned int countersize; 
 	struct xt_counters *counters; 
 	struct xt_table_info *private = table->private; 
-	int ret = 0; 
-	void *loc_cpu_entry; 
  
 	/* We need atomic snapshot of counters: rest doesn't change 
 	   (other than comefrom, which userspace doesn't care 
@@ -818,13 +813,32 @@ copy_entries_to_user(unsigned int total_ 
 	counters = vmalloc_node(countersize, numa_node_id()); 
  
 	if (counters == NULL) 
-		return -ENOMEM; 
+		return ERR_PTR(-ENOMEM); 
  
 	/* First, sum counters... */ 
 	write_lock_bh(&table->lock); 
 	get_counters(private, counters); 
 	write_unlock_bh(&table->lock); 
  
+	return counters; 
+} 
+ 
+static int 
+copy_entries_to_user(unsigned int total_size, 
+		     struct ipt_table *table, 
+		     void __user *userptr) 
+{ 
+	unsigned int off, num; 
+	struct ipt_entry *e; 
+	struct xt_counters *counters; 
+	struct xt_table_info *private = table->private; 
+	int ret = 0; 
+	void *loc_cpu_entry; 
+ 
+	counters = alloc_counters(table); 
+	if (IS_ERR(counters)) 
+		return PTR_ERR(counters); 
+ 
 	/* choose the copy that is on our node/cpu, ... 
 	 * This choice is lazy (because current thread is 
 	 * allowed to migrate to another cpu) 
@@ -878,50 +892,905 @@ copy_entries_to_user(unsigned int total_ 
 			goto free_counters; 
 		} 
 	} 
- 
- free_counters: 
-	vfree(counters); 
+ 
+ free_counters: 
+	vfree(counters); 
+	return ret; 
+} 
+ 
+#ifdef CONFIG_COMPAT 
+struct compat_delta { 
+	struct compat_delta *next; 
+	u_int16_t offset; 
+	short delta; 
+}; 
+ 
+static struct compat_delta *compat_offsets = NULL; 
+ 
+static int compat_add_offset(u_int16_t offset, short delta) 
+{ 
+	struct compat_delta *tmp; 
+ 
+	tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL); 
+	if (!tmp) 
+		return -ENOMEM; 
+	tmp->offset = offset; 
+	tmp->delta = delta; 
+	if (compat_offsets) { 
+		tmp->next = compat_offsets->next; 
+		compat_offsets->next = tmp; 
+	} else { 
+		compat_offsets = tmp; 
+		tmp->next = NULL; 
+	} 
+	return 0; 
+} 
+ 
+static void compat_flush_offsets(void) 
+{ 
+	struct compat_delta *tmp, *next; 
+ 
+	if (compat_offsets) { 
+		for(tmp = compat_offsets; tmp; tmp = next) { 
+			next = tmp->next; 
+			kfree(tmp); 
+		} 
+		compat_offsets = NULL; 
+	} 
+} 
+ 
+static short compat_calc_jump(u_int16_t offset) 
+{ 
+	struct compat_delta *tmp; 
+	short delta; 
+ 
+	for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next) 
+		if (tmp->offset < offset) 
+			delta += tmp->delta; 
+	return delta; 
+} 
+ 
+struct compat_ipt_standard_target 
+{ 
+	struct compat_xt_entry_target target; 
+	compat_int_t verdict; 
+}; 
+ 
+#define IPT_ST_OFFSET	(sizeof(struct ipt_standard_target) - \ 
+				sizeof(struct compat_ipt_standard_target)) 
+ 
+struct compat_ipt_standard 
+{ 
+	struct compat_ipt_entry entry; 
+	struct compat_ipt_standard_target target; 
+}; 
+ 
+static int compat_ipt_standard_fn(void *target, 
+		void **dstptr, int *size, int convert) 
+{ 
+	struct compat_ipt_standard_target compat_st, *pcompat_st; 
+	struct ipt_standard_target st, *pst; 
+	int ret; 
+ 
+	ret = 0; 
+	switch (convert) { 
+		case COMPAT_TO_USER: 
+			pst = (struct ipt_stand
...
  
		
		
		
 |  
	| 
		
	 | 
 
 
 |  
  
 
Goto Forum:
 
 Current Time: Tue Nov 04 12:33:56 GMT 2025 
 Total time taken to generate the page: 0.18377 seconds 
 |