diff options
| -rw-r--r-- | fs/namei.c | 18 | ||||
| -rw-r--r-- | fs/stat.c | 5 | ||||
| -rw-r--r-- | include/linux/namei.h | 1 |
3 files changed, 17 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c index 7657be4352bf..ac6d214da827 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -137,7 +137,7 @@ static int do_getname(const char __user *filename, char *page) | |||
| 137 | return retval; | 137 | return retval; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | static char *getname_flags(const char __user * filename, int flags) | 140 | static char *getname_flags(const char __user *filename, int flags, int *empty) |
| 141 | { | 141 | { |
| 142 | char *tmp, *result; | 142 | char *tmp, *result; |
| 143 | 143 | ||
| @@ -148,6 +148,8 @@ static char *getname_flags(const char __user * filename, int flags) | |||
| 148 | 148 | ||
| 149 | result = tmp; | 149 | result = tmp; |
| 150 | if (retval < 0) { | 150 | if (retval < 0) { |
| 151 | if (retval == -ENOENT && empty) | ||
| 152 | *empty = 1; | ||
| 151 | if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { | 153 | if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { |
| 152 | __putname(tmp); | 154 | __putname(tmp); |
| 153 | result = ERR_PTR(retval); | 155 | result = ERR_PTR(retval); |
| @@ -160,7 +162,7 @@ static char *getname_flags(const char __user * filename, int flags) | |||
| 160 | 162 | ||
| 161 | char *getname(const char __user * filename) | 163 | char *getname(const char __user * filename) |
| 162 | { | 164 | { |
| 163 | return getname_flags(filename, 0); | 165 | return getname_flags(filename, 0, 0); |
| 164 | } | 166 | } |
| 165 | 167 | ||
| 166 | #ifdef CONFIG_AUDITSYSCALL | 168 | #ifdef CONFIG_AUDITSYSCALL |
| @@ -1798,11 +1800,11 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | |||
| 1798 | return __lookup_hash(&this, base, NULL); | 1800 | return __lookup_hash(&this, base, NULL); |
| 1799 | } | 1801 | } |
| 1800 | 1802 | ||
| 1801 | int user_path_at(int dfd, const char __user *name, unsigned flags, | 1803 | int user_path_at_empty(int dfd, const char __user *name, unsigned flags, |
| 1802 | struct path *path) | 1804 | struct path *path, int *empty) |
| 1803 | { | 1805 | { |
| 1804 | struct nameidata nd; | 1806 | struct nameidata nd; |
| 1805 | char *tmp = getname_flags(name, flags); | 1807 | char *tmp = getname_flags(name, flags, empty); |
| 1806 | int err = PTR_ERR(tmp); | 1808 | int err = PTR_ERR(tmp); |
| 1807 | if (!IS_ERR(tmp)) { | 1809 | if (!IS_ERR(tmp)) { |
| 1808 | 1810 | ||
| @@ -1816,6 +1818,12 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, | |||
| 1816 | return err; | 1818 | return err; |
| 1817 | } | 1819 | } |
| 1818 | 1820 | ||
| 1821 | int user_path_at(int dfd, const char __user *name, unsigned flags, | ||
| 1822 | struct path *path) | ||
| 1823 | { | ||
| 1824 | return user_path_at_empty(dfd, name, flags, path, 0); | ||
| 1825 | } | ||
| 1826 | |||
| 1819 | static int user_path_parent(int dfd, const char __user *path, | 1827 | static int user_path_parent(int dfd, const char __user *path, |
| 1820 | struct nameidata *nd, char **name) | 1828 | struct nameidata *nd, char **name) |
| 1821 | { | 1829 | { |
| @@ -294,15 +294,16 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, | |||
| 294 | { | 294 | { |
| 295 | struct path path; | 295 | struct path path; |
| 296 | int error; | 296 | int error; |
| 297 | int empty = 0; | ||
| 297 | 298 | ||
| 298 | if (bufsiz <= 0) | 299 | if (bufsiz <= 0) |
| 299 | return -EINVAL; | 300 | return -EINVAL; |
| 300 | 301 | ||
| 301 | error = user_path_at(dfd, pathname, LOOKUP_EMPTY, &path); | 302 | error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty); |
| 302 | if (!error) { | 303 | if (!error) { |
| 303 | struct inode *inode = path.dentry->d_inode; | 304 | struct inode *inode = path.dentry->d_inode; |
| 304 | 305 | ||
| 305 | error = -EINVAL; | 306 | error = empty ? -ENOENT : -EINVAL; |
| 306 | if (inode->i_op->readlink) { | 307 | if (inode->i_op->readlink) { |
| 307 | error = security_inode_readlink(path.dentry); | 308 | error = security_inode_readlink(path.dentry); |
| 308 | if (!error) { | 309 | if (!error) { |
diff --git a/include/linux/namei.h b/include/linux/namei.h index 409328d1cbbb..ffc02135c483 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
| @@ -67,6 +67,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; | |||
| 67 | #define LOOKUP_EMPTY 0x4000 | 67 | #define LOOKUP_EMPTY 0x4000 |
| 68 | 68 | ||
| 69 | extern int user_path_at(int, const char __user *, unsigned, struct path *); | 69 | extern int user_path_at(int, const char __user *, unsigned, struct path *); |
| 70 | extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); | ||
| 70 | 71 | ||
| 71 | #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path) | 72 | #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path) |
| 72 | #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path) | 73 | #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path) |
