patch-2.1.5 linux/fs/namei.c

Next file: linux/include/asm-alpha/segment.h
Previous file: linux/fs/ext2/symlink.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.4/linux/fs/namei.c linux/fs/namei.c
@@ -21,66 +21,47 @@
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
 /*
- * How long a filename can we get from user space?
- *  -EFAULT if invalid area
- *  0 if ok (ENAMETOOLONG before EFAULT)
- *  >0 EFAULT after xx bytes
- */
-static inline int get_max_filename(unsigned long address)
-{
-	struct vm_area_struct * vma;
-
-	if (get_fs() == KERNEL_DS)
-		return 0;
-	vma = find_vma(current->mm, address);
-	if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	address = vma->vm_end - address;
-	if (address > PAGE_SIZE)
-		return 0;
-	if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
-	   (vma->vm_next->vm_flags & VM_READ))
-		return 0;
-	return address;
-}
-
-/*
  * In order to reduce some races, while at the same time doing additional
  * checking and hopefully speeding things up, we copy filenames to the
  * kernel data space before using them..
  *
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  */
+static inline int do_getname(const char *filename, char *page)
+{
+	int retval;
+	unsigned long len = PAGE_SIZE;
+
+	if ((unsigned long) filename >= TASK_SIZE) {
+		if (get_fs() != KERNEL_DS)
+			return -EFAULT;
+	} else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE)
+		len = TASK_SIZE - (unsigned long) filename;
+
+	retval = strncpy_from_user((char *)page, filename, len);
+	if (retval > 0) {
+		if (retval < len)
+			return 0;
+		return -ENAMETOOLONG;
+	} else if (!retval)
+		retval = -ENOENT;
+	return retval;
+}
+
 int getname(const char * filename, char **result)
 {
-	int i, error;
 	unsigned long page;
-	char * tmp, c;
+	int retval;
 
-	i = get_max_filename((unsigned long) filename);
-	if (i < 0)
-		return i;
-	error = -EFAULT;
-	if (!i) {
-		error = -ENAMETOOLONG;
-		i = PAGE_SIZE;
-	}
-	get_user(c, filename++);
-	if (!c)
-		return -ENOENT;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	*result = tmp = (char *) page;
-	while (--i) {
-		*(tmp++) = c;
-		get_user(c, filename++);
-		if (!c) {
-			*tmp = '\0';
-			return 0;
-		}
+	page  = __get_free_page(GFP_KERNEL);
+	retval = -ENOMEM;
+	if (page) {
+		*result = (char *)page;
+		retval = do_getname(filename, (char *) page);
+		if (retval < 0)
+			free_page(page);
 	}
-	free_page(page);
-	return error;
+	return retval;
 }
 
 void putname(char * name)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov