--- ./fs/namei.c.firstwave	2010-01-25 14:52:25.000000000 +0300
+++ ./fs/namei.c	2010-01-25 19:50:22.000000000 +0300
@@ -27,6 +27,7 @@
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/audit.h>
+#include <linux/file.h>
 #include <asm/namei.h>
 #include <asm/uaccess.h>
 
@@ -260,6 +261,11 @@ int permission(struct inode * inode, int
 	return security_inode_permission(inode, mask, nd);
 }
 
+static int file_permission(struct file *file, int mask)
+{
+	return permission(file->f_dentry->d_inode, mask, NULL, NULL);
+}
+
 /*
  * get_write_access() gets write permission for a file.
  * put_write_access() releases this write permission.
@@ -1093,9 +1099,11 @@ set_it:
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
-int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
+int fastcall path_fd_lookup(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
 {
 	int retval = 0;
+	int fput_needed;
+	struct file *file;
 
 	nd->last_type = LAST_ROOT; /* if there are only slashes... */
 	nd->flags = flags;
@@ -1113,10 +1121,34 @@ int fastcall path_lookup(const char *nam
 		}
 		nd->mnt = mntget(current->fs->rootmnt);
 		nd->dentry = dget(current->fs->root);
-	} else {
+	} else if (dfd == AT_FDCWD) {
 		nd->mnt = mntget(current->fs->pwdmnt);
 		nd->dentry = dget(current->fs->pwd);
+	} else {
+		struct dentry *dentry;
+
+		file = fget_light(dfd, &fput_needed);
+		retval = -EBADF;
+		if (!file)
+			goto out_fail;
+
+		dentry = file->f_dentry;
+
+		retval = -ENOTDIR;
+		if (!S_ISDIR(dentry->d_inode->i_mode))
+			goto fput_fail;
+
+		retval = file_permission(file, MAY_EXEC);
+		if (retval)
+			goto fput_fail;
+
+		nd->mnt = mntget(file->f_vfsmnt);
+		nd->dentry = dget(dentry);
+
+		fput_light(file, fput_needed);
+
 	}
+
 	read_unlock(&current->fs->lock);
 	current->total_link_count = 0;
 	retval = link_path_walk(name, nd);
@@ -1124,7 +1156,17 @@ out:
 	if (unlikely(current->audit_context
 		     && nd && nd->dentry && nd->dentry->d_inode))
 		audit_inode(name, nd->dentry->d_inode, flags);
+out_fail:
 	return retval;
+
+fput_fail:
+	fput_light(file, fput_needed);
+	goto out_fail;
+}
+
+int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
+{
+	return path_fd_lookup(AT_FDCWD, name, flags, nd);
 }
 
 /*
@@ -1220,18 +1262,24 @@ access:
  * that namei follows links, while lnamei does not.
  * SMP-safe
  */
-int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
+int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
+		struct nameidata *nd)
 {
 	char *tmp = getname(name);
 	int err = PTR_ERR(tmp);
 
 	if (!IS_ERR(tmp)) {
-		err = path_lookup(tmp, flags, nd);
+		err = path_fd_lookup(dfd, tmp, flags, nd);
 		putname(tmp);
 	}
 	return err;
 }
 
+int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
+{
+	return __user_walk_fd(AT_FDCWD, name, flags, nd);
+}
+
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
@@ -1513,7 +1561,7 @@ do_lookup_undo(struct nameidata *nd)
  * for symlinks (where the permissions are checked later).
  * SMP-safe
  */
-int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
+int open_fd_namei(int dfd, const char * pathname, int flag, int mode, struct nameidata *nd)
 {
 	int acc_mode, error = 0;
 	struct dentry *dentry;
@@ -1540,7 +1588,7 @@ int open_namei(const char * pathname, in
 	 * The simplest case - just a plain lookup.
 	 */
 	if (!(flag & O_CREAT)) {
-		error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd);
+		error = path_fd_lookup(dfd, pathname, lookup_flags(flag)|LOOKUP_OPEN, nd);
 		if (error)
 			return error;
 		goto ok;
@@ -1549,7 +1597,7 @@ int open_namei(const char * pathname, in
 	/*
 	 * Create - we need to know the parent.
 	 */
-	error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);
+	error = path_fd_lookup(dfd, pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);
 	if (error)
 		return error;
 
@@ -1689,6 +1737,11 @@ do_link:
 	goto do_last;
 }
 
+int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
+{
+	return open_fd_namei(AT_FDCWD, pathname, flag, mode, nd);
+}
+
 /**
  * lookup_create - lookup a dentry, creating it if it doesn't exist
  * @nd: nameidata info
@@ -2589,6 +2697,7 @@ struct inode_operations page_symlink_ino
 };
 
 EXPORT_SYMBOL(__user_walk);
+EXPORT_SYMBOL(__user_walk_fd);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
--- ./include/linux/fcntl.h.firstwave	2010-01-25 14:52:26.000000000 +0300
+++ ./include/linux/fcntl.h	2010-01-25 17:25:12.000000000 +0300
@@ -23,6 +23,14 @@
 #define DN_ATTRIB	0x00000020	/* File changed attibutes */
 #define DN_MULTISHOT	0x80000000	/* Don't remove notifier */
 
+#define AT_FDCWD                -100    /* Special value used to indicate
+					   openat should use the current
+					   working directory. */
+#define AT_SYMLINK_NOFOLLOW     0x100   /* Do not follow symbolic links.  */
+#define AT_REMOVEDIR            0x200   /* Remove directory instead of
+					   unlinking file.  */
+#define AT_SYMLINK_FOLLOW       0x400   /* Follow symbolic links.  */
+
 #ifdef __KERNEL__
 
 #ifndef force_o_largefile
--- ./include/linux/fs.h.firstwave	2010-01-25 14:52:26.000000000 +0300
+++ ./include/linux/fs.h	2010-01-25 20:03:02.000000000 +0300
@@ -1464,6 +1465,7 @@ static inline void allow_write_access(st
 extern int do_pipe(int *);
 
 extern int open_namei(const char *, int, int, struct nameidata *);
+extern int open_fd_namei(int dfd, const char *, int, int, struct nameidata *);
 extern int may_open(struct nameidata *, int, int);
 
 struct linux_binprm;
--- ./include/linux/namei.h.firstwave	2010-01-25 14:52:26.000000000 +0300
+++ ./include/linux/namei.h	2010-01-25 19:24:07.000000000 +0300
@@ -61,11 +61,13 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LA
 #define LOOKUP_STRICT		(0x2000)	/* no symlinks or other filesystems */
 
 extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *));
+extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *));
 #define user_path_walk(name,nd) \
 	__user_walk(name, LOOKUP_FOLLOW, nd)
 #define user_path_walk_link(name,nd) \
 	__user_walk(name, 0, nd)
 extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
+extern int FASTCALL(path_fd_lookup(int, const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_walk(const char *, struct nameidata *));
 extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
 extern void path_release(struct nameidata *);

