new function: file_open_root(dentry, mnt, name, flags) opens the file vfs_path_lookup would arrive to. Note that name can be empty; in that case the usual requirement that dentry should be a directory is lifted. open-coded equivalents switched to it, may_open() got down exactly one caller and became static.
Unified · Split
| @@ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req) · 123 unmodified lines | ||
| 124 | 124 | #if 0 |
| 125 | 125 | void mconsole_proc(struct mc_request *req) |
| 126 | 126 | { |
| 127 | − struct nameidata nd; | |
| 128 | 127 | struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt; |
| 129 | 128 | struct file *file; |
| 130 | − int n, err; | |
| 129 | + int n; | |
| 131 | 130 | char *ptr = req->request.data, *buf; |
| 132 | 131 | mm_segment_t old_fs = get_fs(); |
| 133 | 132 | |
| 134 | 133 | ptr += strlen("proc"); |
| 135 | 134 | ptr = skip_spaces(ptr); |
| 136 | 135 | |
| 137 | − err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd); | |
| 138 | − if (err) { | |
| 139 | − mconsole_reply(req, "Failed to look up file", 1, 0); | |
| 140 | − goto out; | |
| 141 | − } | |
| 142 | − | |
| 143 | − err = may_open(&nd.path, MAY_READ, O_RDONLY); | |
| 144 | − if (result) { | |
| 145 | − mconsole_reply(req, "Failed to open file", 1, 0); | |
| 146 | − path_put(&nd.path); | |
| 147 | − goto out; | |
| 148 | − } | |
| 149 | − | |
| 150 | − file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, | |
| 151 | − current_cred()); | |
| 152 | − err = PTR_ERR(file); | |
| 136 | + file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY); | |
| 153 | 137 | if (IS_ERR(file)) { |
| 154 | 138 | mconsole_reply(req, "Failed to open file", 1, 0); |
| 155 | − path_put(&nd.path); | |
| 156 | 139 | goto out; |
| 157 | 140 | } |
| 158 | 141 | |
| @@ -114,6 +114,8 @@ struct open_flags { · 113 unmodified lines | ||
| 114 | 114 | }; |
| 115 | 115 | extern struct file *do_filp_open(int dfd, const char *pathname, |
| 116 | 116 | const struct open_flags *op, int lookup_flags); |
| 117 | +extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, | |
| 118 | + const char *, const struct open_flags *, int lookup_flags); | |
| 117 | 119 | |
| 118 | 120 | /* |
| 119 | 121 | * inode.c |
| @@ -1487,11 +1487,13 @@ static int path_init(int dfd, const char *name, unsigned int flags, · 1486 unmodified lines | ||
| 1487 | 1487 | nd->depth = 0; |
| 1488 | 1488 | if (flags & LOOKUP_ROOT) { |
| 1489 | 1489 | struct inode *inode = nd->root.dentry->d_inode; |
| 1490 | − if (!inode->i_op->lookup) | |
| 1491 | − return -ENOTDIR; | |
| 1492 | − retval = inode_permission(inode, MAY_EXEC); | |
| 1493 | − if (retval) | |
| 1494 | − return retval; | |
| 1490 | + if (*name) { | |
| 1491 | + if (!inode->i_op->lookup) | |
| 1492 | + return -ENOTDIR; | |
| 1493 | + retval = inode_permission(inode, MAY_EXEC); | |
| 1494 | + if (retval) | |
| 1495 | + return retval; | |
| 1496 | + } | |
| 1495 | 1497 | nd->path = nd->root; |
| 1496 | 1498 | nd->inode = inode; |
| 1497 | 1499 | if (flags & LOOKUP_RCU) { |
| @@ -1937,7 +1939,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, · 439 unmodified lines | ||
| 1937 | 1939 | return error; |
| 1938 | 1940 | } |
| 1939 | 1941 | |
| 1940 | −int may_open(struct path *path, int acc_mode, int flag) | |
| 1942 | +static int may_open(struct path *path, int acc_mode, int flag) | |
| 1941 | 1943 | { |
| 1942 | 1944 | struct dentry *dentry = path->dentry; |
| 1943 | 1945 | struct inode *inode = dentry->d_inode; |
| @@ -2250,11 +2252,10 @@ exit: · 306 unmodified lines | ||
| 2250 | 2252 | } |
| 2251 | 2253 | |
| 2252 | 2254 | static struct file *path_openat(int dfd, const char *pathname, |
| 2253 | − const struct open_flags *op, int flags) | |
| 2255 | + struct nameidata *nd, const struct open_flags *op, int flags) | |
| 2254 | 2256 | { |
| 2255 | 2257 | struct file *base = NULL; |
| 2256 | 2258 | struct file *filp; |
| 2257 | − struct nameidata nd; | |
| 2258 | 2259 | struct path path; |
| 2259 | 2260 | int count = 0; |
| 2260 | 2261 | int error; |
| @@ -2264,27 +2265,27 @@ static struct file *path_openat(int dfd, const char *pathname, · 3 unmodified lines | ||
| 2264 | 2265 | return ERR_PTR(-ENFILE); |
| 2265 | 2266 | |
| 2266 | 2267 | filp->f_flags = op->open_flag; |
| 2267 | − nd.intent.open.file = filp; | |
| 2268 | − nd.intent.open.flags = open_to_namei_flags(op->open_flag); | |
| 2269 | − nd.intent.open.create_mode = op->mode; | |
| 2268 | + nd->intent.open.file = filp; | |
| 2269 | + nd->intent.open.flags = open_to_namei_flags(op->open_flag); | |
| 2270 | + nd->intent.open.create_mode = op->mode; | |
| 2270 | 2271 | |
| 2271 | − error = path_init(dfd, pathname, flags | LOOKUP_PARENT, &nd, &base); | |
| 2272 | + error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); | |
| 2272 | 2273 | if (unlikely(error)) |
| 2273 | 2274 | goto out_filp; |
| 2274 | 2275 | |
| 2275 | 2276 | current->total_link_count = 0; |
| 2276 | − error = link_path_walk(pathname, &nd); | |
| 2277 | + error = link_path_walk(pathname, nd); | |
| 2277 | 2278 | if (unlikely(error)) |
| 2278 | 2279 | goto out_filp; |
| 2279 | 2280 | |
| 2280 | − filp = do_last(&nd, &path, op, pathname); | |
| 2281 | + filp = do_last(nd, &path, op, pathname); | |
| 2281 | 2282 | while (unlikely(!filp)) { /* trailing symlink */ |
| 2282 | 2283 | struct path link = path; |
| 2283 | 2284 | struct inode *linki = link.dentry->d_inode; |
| 2284 | 2285 | void *cookie; |
| 2285 | − if (!(nd.flags & LOOKUP_FOLLOW) || count++ == 32) { | |
| 2286 | − path_put_conditional(&path, &nd); | |
| 2287 | − path_put(&nd.path); | |
| 2286 | + if (!(nd->flags & LOOKUP_FOLLOW) || count++ == 32) { | |
| 2287 | + path_put_conditional(&path, nd); | |
| 2288 | + path_put(&nd->path); | |
| 2288 | 2289 | filp = ERR_PTR(-ELOOP); |
| 2289 | 2290 | break; |
| 2290 | 2291 | } |
| @@ -2299,23 +2300,23 @@ static struct file *path_openat(int dfd, const char *pathname, · 8 unmodified lines | ||
| 2299 | 2300 | * have to putname() it when we are done. Procfs-like symlinks |
| 2300 | 2301 | * just set LAST_BIND. |
| 2301 | 2302 | */ |
| 2302 | − nd.flags |= LOOKUP_PARENT; | |
| 2303 | − nd.flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | |
| 2304 | − error = __do_follow_link(&link, &nd, &cookie); | |
| 2303 | + nd->flags |= LOOKUP_PARENT; | |
| 2304 | + nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | |
| 2305 | + error = __do_follow_link(&link, nd, &cookie); | |
| 2305 | 2306 | if (unlikely(error)) |
| 2306 | 2307 | filp = ERR_PTR(error); |
| 2307 | 2308 | else |
| 2308 | − filp = do_last(&nd, &path, op, pathname); | |
| 2309 | + filp = do_last(nd, &path, op, pathname); | |
| 2309 | 2310 | if (!IS_ERR(cookie) && linki->i_op->put_link) |
| 2310 | − linki->i_op->put_link(link.dentry, &nd, cookie); | |
| 2311 | + linki->i_op->put_link(link.dentry, nd, cookie); | |
| 2311 | 2312 | path_put(&link); |
| 2312 | 2313 | } |
| 2313 | 2314 | out: |
| 2314 | − if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT)) | |
| 2315 | − path_put(&nd.root); | |
| 2315 | + if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) | |
| 2316 | + path_put(&nd->root); | |
| 2316 | 2317 | if (base) |
| 2317 | 2318 | fput(base); |
| 2318 | − release_open_intent(&nd); | |
| 2319 | + release_open_intent(nd); | |
| 2319 | 2320 | return filp; |
| 2320 | 2321 | |
| 2321 | 2322 | out_filp: |
| @@ -2326,16 +2327,39 @@ out_filp: · 4 unmodified lines | ||
| 2326 | 2327 | struct file *do_filp_open(int dfd, const char *pathname, |
| 2327 | 2328 | const struct open_flags *op, int flags) |
| 2328 | 2329 | { |
| 2330 | + struct nameidata nd; | |
| 2329 | 2331 | struct file *filp; |
| 2330 | 2332 | |
| 2331 | − filp = path_openat(dfd, pathname, op, flags | LOOKUP_RCU); | |
| 2333 | + filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); | |
| 2332 | 2334 | if (unlikely(filp == ERR_PTR(-ECHILD))) |
| 2333 | − filp = path_openat(dfd, pathname, op, flags); | |
| 2335 | + filp = path_openat(dfd, pathname, &nd, op, flags); | |
| 2334 | 2336 | if (unlikely(filp == ERR_PTR(-ESTALE))) |
| 2335 | − filp = path_openat(dfd, pathname, op, flags | LOOKUP_REVAL); | |
| 2337 | + filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL); | |
| 2336 | 2338 | return filp; |
| 2337 | 2339 | } |
| 2338 | 2340 | |
| 2341 | +struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |
| 2342 | + const char *name, const struct open_flags *op, int flags) | |
| 2343 | +{ | |
| 2344 | + struct nameidata nd; | |
| 2345 | + struct file *file; | |
| 2346 | + | |
| 2347 | + nd.root.mnt = mnt; | |
| 2348 | + nd.root.dentry = dentry; | |
| 2349 | + | |
| 2350 | + flags |= LOOKUP_ROOT; | |
| 2351 | + | |
| 2352 | + if (dentry->d_inode->i_op->follow_link) | |
| 2353 | + return ERR_PTR(-ELOOP); | |
| 2354 | + | |
| 2355 | + file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); | |
| 2356 | + if (unlikely(file == ERR_PTR(-ECHILD))) | |
| 2357 | + file = path_openat(-1, name, &nd, op, flags); | |
| 2358 | + if (unlikely(file == ERR_PTR(-ESTALE))) | |
| 2359 | + file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL); | |
| 2360 | + return file; | |
| 2361 | +} | |
| 2362 | + | |
| 2339 | 2363 | /** |
| 2340 | 2364 | * lookup_create - lookup a dentry, creating it if it doesn't exist |
| 2341 | 2365 | * @nd: nameidata info |
| @@ -22,30 +22,17 @@ · 21 unmodified lines | ||
| 22 | 22 | |
| 23 | 23 | static struct file *do_open(char *name, int flags) |
| 24 | 24 | { |
| 25 | − struct nameidata nd; | |
| 26 | 25 | struct vfsmount *mnt; |
| 27 | − int error; | |
| 26 | + struct file *file; | |
| 28 | 27 | |
| 29 | 28 | mnt = do_kern_mount("nfsd", 0, "nfsd", NULL); |
| 30 | 29 | if (IS_ERR(mnt)) |
| 31 | 30 | return (struct file *)mnt; |
| 32 | 31 | |
| 33 | − error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd); | |
| 34 | − mntput(mnt); /* drop do_kern_mount reference */ | |
| 35 | − if (error) | |
| 36 | − return ERR_PTR(error); | |
| 37 | − | |
| 38 | − if (flags == O_RDWR) | |
| 39 | − error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags); | |
| 40 | − else | |
| 41 | − error = may_open(&nd.path, MAY_WRITE, flags); | |
| 32 | + file = file_open_root(mnt->mnt_root, mnt, name, flags); | |
| 42 | 33 | |
| 43 | − if (!error) | |
| 44 | − return dentry_open(nd.path.dentry, nd.path.mnt, flags, | |
| 45 | − current_cred()); | |
| 46 | − | |
| 47 | − path_put(&nd.path); | |
| 48 | − return ERR_PTR(error); | |
| 34 | + mntput(mnt); /* drop do_kern_mount reference */ | |
| 35 | + return file; | |
| 49 | 36 | } |
| 50 | 37 | |
| 51 | 38 | static struct { |
| @@ -959,6 +959,20 @@ struct file *filp_open(const char *filename, int flags, int mode) · 958 unmodified lines | ||
| 959 | 959 | } |
| 960 | 960 | EXPORT_SYMBOL(filp_open); |
| 961 | 961 | |
| 962 | +struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |
| 963 | + const char *filename, int flags) | |
| 964 | +{ | |
| 965 | + struct open_flags op; | |
| 966 | + int lookup = build_open_flags(flags, 0, &op); | |
| 967 | + if (flags & O_CREAT) | |
| 968 | + return ERR_PTR(-EINVAL); | |
| 969 | + if (!filename && (flags & O_DIRECTORY)) | |
| 970 | + if (!dentry->d_inode->i_op->lookup) | |
| 971 | + return ERR_PTR(-ENOTDIR); | |
| 972 | + return do_file_open_root(dentry, mnt, filename, &op, lookup); | |
| 973 | +} | |
| 974 | +EXPORT_SYMBOL(file_open_root); | |
| 975 | + | |
| 962 | 976 | long do_sys_open(int dfd, const char __user *filename, int flags, int mode) |
| 963 | 977 | { |
| 964 | 978 | struct open_flags op; |
| @@ -1990,6 +1990,8 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, · 1989 unmodified lines | ||
| 1990 | 1990 | extern long do_sys_open(int dfd, const char __user *filename, int flags, |
| 1991 | 1991 | int mode); |
| 1992 | 1992 | extern struct file *filp_open(const char *, int, int); |
| 1993 | +extern struct file *file_open_root(struct dentry *, struct vfsmount *, | |
| 1994 | + const char *, int); | |
| 1993 | 1995 | extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, |
| 1994 | 1996 | const struct cred *); |
| 1995 | 1997 | extern int filp_close(struct file *, fl_owner_t id); |
| @@ -2205,8 +2207,6 @@ extern struct file *create_read_pipe(struct file *f, int flags); · 209 unmodified lines | ||
| 2205 | 2207 | extern struct file *create_write_pipe(int flags); |
| 2206 | 2208 | extern void free_write_pipe(struct file *); |
| 2207 | 2209 | |
| 2208 | −extern int may_open(struct path *, int, int); | |
| 2209 | − | |
| 2210 | 2210 | extern int kernel_read(struct file *, loff_t, char *, unsigned long); |
| 2211 | 2211 | extern struct file * open_exec(const char *); |
| 2212 | 2212 | |
| @@ -1321,13 +1321,11 @@ static ssize_t binary_sysctl(const int *name, int nlen, · 1320 unmodified lines | ||
| 1321 | 1321 | void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) |
| 1322 | 1322 | { |
| 1323 | 1323 | const struct bin_table *table = NULL; |
| 1324 | − struct nameidata nd; | |
| 1325 | 1324 | struct vfsmount *mnt; |
| 1326 | 1325 | struct file *file; |
| 1327 | 1326 | ssize_t result; |
| 1328 | 1327 | char *pathname; |
| 1329 | 1328 | int flags; |
| 1330 | − int acc_mode; | |
| 1331 | 1329 | |
| 1332 | 1330 | pathname = sysctl_getname(name, nlen, &table); |
| 1333 | 1331 | result = PTR_ERR(pathname); |
| @@ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen, · 3 unmodified lines | ||
| 1337 | 1335 | /* How should the sysctl be accessed? */ |
| 1338 | 1336 | if (oldval && oldlen && newval && newlen) { |
| 1339 | 1337 | flags = O_RDWR; |
| 1340 | − acc_mode = MAY_READ | MAY_WRITE; | |
| 1341 | 1338 | } else if (newval && newlen) { |
| 1342 | 1339 | flags = O_WRONLY; |
| 1343 | − acc_mode = MAY_WRITE; | |
| 1344 | 1340 | } else if (oldval && oldlen) { |
| 1345 | 1341 | flags = O_RDONLY; |
| 1346 | − acc_mode = MAY_READ; | |
| 1347 | 1342 | } else { |
| 1348 | 1343 | result = 0; |
| 1349 | 1344 | goto out_putname; |
| 1350 | 1345 | } |
| 1351 | 1346 | |
| 1352 | 1347 | mnt = current->nsproxy->pid_ns->proc_mnt; |
| 1353 | − result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd); | |
| 1354 | − if (result) | |
| 1355 | − goto out_putname; | |
| 1356 | − | |
| 1357 | − result = may_open(&nd.path, acc_mode, flags); | |
| 1358 | − if (result) | |
| 1359 | − goto out_putpath; | |
| 1360 | − | |
| 1361 | − file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred()); | |
| 1348 | + file = file_open_root(mnt->mnt_root, mnt, pathname, flags); | |
| 1362 | 1349 | result = PTR_ERR(file); |
| 1363 | 1350 | if (IS_ERR(file)) |
| 1364 | 1351 | goto out_putname; |
| @@ -1370,10 +1357,6 @@ out_putname: · 5 unmodified lines | ||
| 1370 | 1357 | putname(pathname); |
| 1371 | 1358 | out: |
| 1372 | 1359 | return result; |
| 1373 | − | |
| 1374 | −out_putpath: | |
| 1375 | − path_put(&nd.path); | |
| 1376 | − goto out_putname; | |
| 1377 | 1360 | } |
| 1378 | 1361 | |
| 1379 | 1362 | |