[parisc-linux-cvs] linux grundler

Grant Grundler grundler@parisc-linux.org
Tue, 15 Jul 2003 01:58:19 -0600


On Tue, Jul 15, 2003 at 01:36:54AM -0600, Grant Grundler wrote:
> Log message:
> 2.4.21-pa6 add IPT_SO_SET_REPLACE to sys32_setsockopt
> 
> I caught this when reviewing the 2.4.20 vs 2.4.21 sparc64 syscall wrapper.
> 2.6 already has this in net/compat.c:compat_sys_setsockopt().

diff appended.

I didn't test this - have no clue really what it's supposed to do.

grant


Index: Makefile
===================================================================
RCS file: /var/cvs/linux/Makefile,v
retrieving revision 1.403
diff -u -p -r1.403 Makefile
--- Makefile	15 Jul 2003 04:35:17 -0000	1.403
+++ Makefile	15 Jul 2003 07:27:03 -0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 21
-EXTRAVERSION = -pa5
+EXTRAVERSION = -pa6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: arch/parisc/kernel/sys_parisc32.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/sys_parisc32.c,v
retrieving revision 1.28
diff -u -p -r1.28 sys_parisc32.c
--- arch/parisc/kernel/sys_parisc32.c	15 Jul 2003 04:35:18 -0000	1.28
+++ arch/parisc/kernel/sys_parisc32.c	15 Jul 2003 07:27:04 -0000
@@ -2298,6 +2298,82 @@ out:
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
+static inline void *compat_ptr(u32 uptr)
+{
+	return (void *)(unsigned long)uptr;
+}
+
+static int do_netfilter_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct ipt_replace32 {
+		char name[IPT_TABLE_MAXNAMELEN];
+		__u32 valid_hooks;
+		__u32 num_entries;
+		__u32 size;
+		__u32 hook_entry[NF_IP_NUMHOOKS];
+		__u32 underflow[NF_IP_NUMHOOKS];
+		__u32 num_counters;
+		__u32 counters;
+		struct ipt_entry entries[0];
+	} *repl32 = (struct ipt_replace32 *)optval;
+	struct ipt_replace *krepl;
+	struct ipt_counters *counters32;
+	__u32 origsize;
+	unsigned int kreplsize, kcountersize;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (optlen < sizeof(repl32))
+		return -EINVAL;
+
+	if (copy_from_user(&origsize,
+			&repl32->size,
+			sizeof(origsize)))
+		return -EFAULT;
+
+	kreplsize = sizeof(*krepl) + origsize;
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+
+	/* Hack: Causes ipchains to give correct error msg --RR */
+	if (optlen != kreplsize)
+		return -ENOPROTOOPT;
+
+	krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
+	if (krepl == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(krepl, optval, kreplsize)) {
+		kfree(krepl);
+		return -EFAULT;
+	}
+
+	counters32 = (struct ipt_counters *) compat_ptr(((struct ipt_replace32 *)krepl)->counters);
+
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+	krepl->counters = (struct ipt_counters *)kmalloc(
+					kcountersize, GFP_KERNEL);
+	if (krepl->counters == NULL) {
+		kfree(krepl);
+		return -ENOMEM;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)krepl, kreplsize);
+	set_fs(old_fs);
+
+	if (ret == 0 &&
+		copy_to_user(counters32, krepl->counters, kcountersize))
+			ret = -EFAULT;
+
+	kfree(krepl->counters);
+	kfree(krepl);
+
+	return ret;
+}
+
 static int do_set_attach_filter(int fd, int level, int optname,
 				char *optval, int optlen)
 {
@@ -2473,6 +2549,9 @@ err02:
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
+	if (optname == IPT_SO_SET_REPLACE)
+		return do_netfilter_replace(fd, level, optname, optval, optlen);
+
 	if (optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname, optval, optlen);
 
@@ -3031,6 +3110,7 @@ asmlinkage long sys32_adjtimex(struct ti
 	CP(shift); CP(stabil); CP(jitcnt); CP(calcnt); CP(errcnt);
 	CP(stbcnt);
 	ret = do_adjtimex(&txc);
+#undef CP
 #define CP(x) t32.x = txc.x
 	CP(modes); CP(offset); CP(freq); CP(maxerror); CP(esterror);
 	CP(status); CP(constant); CP(precision); CP(tolerance);