xref: /openbmc/linux/fs/overlayfs/namei.c (revision bbb1e54d)
1bbb1e54dSMiklos Szeredi /*
2bbb1e54dSMiklos Szeredi  * Copyright (C) 2011 Novell Inc.
3bbb1e54dSMiklos Szeredi  * Copyright (C) 2016 Red Hat, Inc.
4bbb1e54dSMiklos Szeredi  *
5bbb1e54dSMiklos Szeredi  * This program is free software; you can redistribute it and/or modify it
6bbb1e54dSMiklos Szeredi  * under the terms of the GNU General Public License version 2 as published by
7bbb1e54dSMiklos Szeredi  * the Free Software Foundation.
8bbb1e54dSMiklos Szeredi  */
9bbb1e54dSMiklos Szeredi 
10bbb1e54dSMiklos Szeredi #include <linux/fs.h>
11bbb1e54dSMiklos Szeredi #include <linux/namei.h>
12bbb1e54dSMiklos Szeredi #include <linux/xattr.h>
13bbb1e54dSMiklos Szeredi #include "overlayfs.h"
14bbb1e54dSMiklos Szeredi #include "ovl_entry.h"
15bbb1e54dSMiklos Szeredi 
16bbb1e54dSMiklos Szeredi static struct dentry *ovl_lookup_real(struct dentry *dir,
17bbb1e54dSMiklos Szeredi 				      const struct qstr *name)
18bbb1e54dSMiklos Szeredi {
19bbb1e54dSMiklos Szeredi 	struct dentry *dentry;
20bbb1e54dSMiklos Szeredi 
21bbb1e54dSMiklos Szeredi 	dentry = lookup_one_len_unlocked(name->name, dir, name->len);
22bbb1e54dSMiklos Szeredi 	if (IS_ERR(dentry)) {
23bbb1e54dSMiklos Szeredi 		if (PTR_ERR(dentry) == -ENOENT)
24bbb1e54dSMiklos Szeredi 			dentry = NULL;
25bbb1e54dSMiklos Szeredi 	} else if (!dentry->d_inode) {
26bbb1e54dSMiklos Szeredi 		dput(dentry);
27bbb1e54dSMiklos Szeredi 		dentry = NULL;
28bbb1e54dSMiklos Szeredi 	} else if (ovl_dentry_weird(dentry)) {
29bbb1e54dSMiklos Szeredi 		dput(dentry);
30bbb1e54dSMiklos Szeredi 		/* Don't support traversing automounts and other weirdness */
31bbb1e54dSMiklos Szeredi 		dentry = ERR_PTR(-EREMOTE);
32bbb1e54dSMiklos Szeredi 	}
33bbb1e54dSMiklos Szeredi 	return dentry;
34bbb1e54dSMiklos Szeredi }
35bbb1e54dSMiklos Szeredi 
36bbb1e54dSMiklos Szeredi static bool ovl_is_opaquedir(struct dentry *dentry)
37bbb1e54dSMiklos Szeredi {
38bbb1e54dSMiklos Szeredi 	int res;
39bbb1e54dSMiklos Szeredi 	char val;
40bbb1e54dSMiklos Szeredi 
41bbb1e54dSMiklos Szeredi 	if (!d_is_dir(dentry))
42bbb1e54dSMiklos Szeredi 		return false;
43bbb1e54dSMiklos Szeredi 
44bbb1e54dSMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
45bbb1e54dSMiklos Szeredi 	if (res == 1 && val == 'y')
46bbb1e54dSMiklos Szeredi 		return true;
47bbb1e54dSMiklos Szeredi 
48bbb1e54dSMiklos Szeredi 	return false;
49bbb1e54dSMiklos Szeredi }
50bbb1e54dSMiklos Szeredi 
51bbb1e54dSMiklos Szeredi /*
52bbb1e54dSMiklos Szeredi  * Returns next layer in stack starting from top.
53bbb1e54dSMiklos Szeredi  * Returns -1 if this is the last layer.
54bbb1e54dSMiklos Szeredi  */
55bbb1e54dSMiklos Szeredi int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
56bbb1e54dSMiklos Szeredi {
57bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe = dentry->d_fsdata;
58bbb1e54dSMiklos Szeredi 
59bbb1e54dSMiklos Szeredi 	BUG_ON(idx < 0);
60bbb1e54dSMiklos Szeredi 	if (idx == 0) {
61bbb1e54dSMiklos Szeredi 		ovl_path_upper(dentry, path);
62bbb1e54dSMiklos Szeredi 		if (path->dentry)
63bbb1e54dSMiklos Szeredi 			return oe->numlower ? 1 : -1;
64bbb1e54dSMiklos Szeredi 		idx++;
65bbb1e54dSMiklos Szeredi 	}
66bbb1e54dSMiklos Szeredi 	BUG_ON(idx > oe->numlower);
67bbb1e54dSMiklos Szeredi 	*path = oe->lowerstack[idx - 1];
68bbb1e54dSMiklos Szeredi 
69bbb1e54dSMiklos Szeredi 	return (idx < oe->numlower) ? idx + 1 : -1;
70bbb1e54dSMiklos Szeredi }
71bbb1e54dSMiklos Szeredi 
72bbb1e54dSMiklos Szeredi struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
73bbb1e54dSMiklos Szeredi 			  unsigned int flags)
74bbb1e54dSMiklos Szeredi {
75bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe;
76bbb1e54dSMiklos Szeredi 	const struct cred *old_cred;
77bbb1e54dSMiklos Szeredi 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
78bbb1e54dSMiklos Szeredi 	struct path *stack = NULL;
79bbb1e54dSMiklos Szeredi 	struct dentry *upperdir, *upperdentry = NULL;
80bbb1e54dSMiklos Szeredi 	unsigned int ctr = 0;
81bbb1e54dSMiklos Szeredi 	struct inode *inode = NULL;
82bbb1e54dSMiklos Szeredi 	bool upperopaque = false;
83bbb1e54dSMiklos Szeredi 	bool stop = false;
84bbb1e54dSMiklos Szeredi 	bool isdir = false;
85bbb1e54dSMiklos Szeredi 	struct dentry *this;
86bbb1e54dSMiklos Szeredi 	unsigned int i;
87bbb1e54dSMiklos Szeredi 	int err;
88bbb1e54dSMiklos Szeredi 
89bbb1e54dSMiklos Szeredi 	old_cred = ovl_override_creds(dentry->d_sb);
90bbb1e54dSMiklos Szeredi 	upperdir = ovl_upperdentry_dereference(poe);
91bbb1e54dSMiklos Szeredi 	if (upperdir) {
92bbb1e54dSMiklos Szeredi 		this = ovl_lookup_real(upperdir, &dentry->d_name);
93bbb1e54dSMiklos Szeredi 		err = PTR_ERR(this);
94bbb1e54dSMiklos Szeredi 		if (IS_ERR(this))
95bbb1e54dSMiklos Szeredi 			goto out;
96bbb1e54dSMiklos Szeredi 
97bbb1e54dSMiklos Szeredi 		if (this) {
98bbb1e54dSMiklos Szeredi 			if (unlikely(ovl_dentry_remote(this))) {
99bbb1e54dSMiklos Szeredi 				dput(this);
100bbb1e54dSMiklos Szeredi 				err = -EREMOTE;
101bbb1e54dSMiklos Szeredi 				goto out;
102bbb1e54dSMiklos Szeredi 			}
103bbb1e54dSMiklos Szeredi 			if (ovl_is_whiteout(this)) {
104bbb1e54dSMiklos Szeredi 				dput(this);
105bbb1e54dSMiklos Szeredi 				this = NULL;
106bbb1e54dSMiklos Szeredi 				stop = upperopaque = true;
107bbb1e54dSMiklos Szeredi 			} else if (!d_is_dir(this)) {
108bbb1e54dSMiklos Szeredi 				stop = true;
109bbb1e54dSMiklos Szeredi 			} else {
110bbb1e54dSMiklos Szeredi 				isdir = true;
111bbb1e54dSMiklos Szeredi 				if (poe->numlower && ovl_is_opaquedir(this))
112bbb1e54dSMiklos Szeredi 					stop = upperopaque = true;
113bbb1e54dSMiklos Szeredi 			}
114bbb1e54dSMiklos Szeredi 		}
115bbb1e54dSMiklos Szeredi 		upperdentry = this;
116bbb1e54dSMiklos Szeredi 	}
117bbb1e54dSMiklos Szeredi 
118bbb1e54dSMiklos Szeredi 	if (!stop && poe->numlower) {
119bbb1e54dSMiklos Szeredi 		err = -ENOMEM;
120bbb1e54dSMiklos Szeredi 		stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL);
121bbb1e54dSMiklos Szeredi 		if (!stack)
122bbb1e54dSMiklos Szeredi 			goto out_put_upper;
123bbb1e54dSMiklos Szeredi 	}
124bbb1e54dSMiklos Szeredi 
125bbb1e54dSMiklos Szeredi 	for (i = 0; !stop && i < poe->numlower; i++) {
126bbb1e54dSMiklos Szeredi 		struct path lowerpath = poe->lowerstack[i];
127bbb1e54dSMiklos Szeredi 
128bbb1e54dSMiklos Szeredi 		this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
129bbb1e54dSMiklos Szeredi 		err = PTR_ERR(this);
130bbb1e54dSMiklos Szeredi 		if (IS_ERR(this)) {
131bbb1e54dSMiklos Szeredi 			/*
132bbb1e54dSMiklos Szeredi 			 * If it's positive, then treat ENAMETOOLONG as ENOENT.
133bbb1e54dSMiklos Szeredi 			 */
134bbb1e54dSMiklos Szeredi 			if (err == -ENAMETOOLONG && (upperdentry || ctr))
135bbb1e54dSMiklos Szeredi 				continue;
136bbb1e54dSMiklos Szeredi 			goto out_put;
137bbb1e54dSMiklos Szeredi 		}
138bbb1e54dSMiklos Szeredi 		if (!this)
139bbb1e54dSMiklos Szeredi 			continue;
140bbb1e54dSMiklos Szeredi 		if (ovl_is_whiteout(this)) {
141bbb1e54dSMiklos Szeredi 			dput(this);
142bbb1e54dSMiklos Szeredi 			break;
143bbb1e54dSMiklos Szeredi 		}
144bbb1e54dSMiklos Szeredi 		/*
145bbb1e54dSMiklos Szeredi 		 * If this is a non-directory then stop here.
146bbb1e54dSMiklos Szeredi 		 */
147bbb1e54dSMiklos Szeredi 		if (!d_is_dir(this)) {
148bbb1e54dSMiklos Szeredi 			if (isdir) {
149bbb1e54dSMiklos Szeredi 				dput(this);
150bbb1e54dSMiklos Szeredi 				break;
151bbb1e54dSMiklos Szeredi 			}
152bbb1e54dSMiklos Szeredi 			stop = true;
153bbb1e54dSMiklos Szeredi 		} else {
154bbb1e54dSMiklos Szeredi 			/*
155bbb1e54dSMiklos Szeredi 			 * Only makes sense to check opaque dir if this is not
156bbb1e54dSMiklos Szeredi 			 * the lowermost layer.
157bbb1e54dSMiklos Szeredi 			 */
158bbb1e54dSMiklos Szeredi 			if (i < poe->numlower - 1 && ovl_is_opaquedir(this))
159bbb1e54dSMiklos Szeredi 				stop = true;
160bbb1e54dSMiklos Szeredi 		}
161bbb1e54dSMiklos Szeredi 
162bbb1e54dSMiklos Szeredi 		stack[ctr].dentry = this;
163bbb1e54dSMiklos Szeredi 		stack[ctr].mnt = lowerpath.mnt;
164bbb1e54dSMiklos Szeredi 		ctr++;
165bbb1e54dSMiklos Szeredi 	}
166bbb1e54dSMiklos Szeredi 
167bbb1e54dSMiklos Szeredi 	oe = ovl_alloc_entry(ctr);
168bbb1e54dSMiklos Szeredi 	err = -ENOMEM;
169bbb1e54dSMiklos Szeredi 	if (!oe)
170bbb1e54dSMiklos Szeredi 		goto out_put;
171bbb1e54dSMiklos Szeredi 
172bbb1e54dSMiklos Szeredi 	if (upperdentry || ctr) {
173bbb1e54dSMiklos Szeredi 		struct dentry *realdentry;
174bbb1e54dSMiklos Szeredi 		struct inode *realinode;
175bbb1e54dSMiklos Szeredi 
176bbb1e54dSMiklos Szeredi 		realdentry = upperdentry ? upperdentry : stack[0].dentry;
177bbb1e54dSMiklos Szeredi 		realinode = d_inode(realdentry);
178bbb1e54dSMiklos Szeredi 
179bbb1e54dSMiklos Szeredi 		err = -ENOMEM;
180bbb1e54dSMiklos Szeredi 		if (upperdentry && !d_is_dir(upperdentry)) {
181bbb1e54dSMiklos Szeredi 			inode = ovl_get_inode(dentry->d_sb, realinode);
182bbb1e54dSMiklos Szeredi 		} else {
183bbb1e54dSMiklos Szeredi 			inode = ovl_new_inode(dentry->d_sb, realinode->i_mode,
184bbb1e54dSMiklos Szeredi 					      realinode->i_rdev);
185bbb1e54dSMiklos Szeredi 			if (inode)
186bbb1e54dSMiklos Szeredi 				ovl_inode_init(inode, realinode, !!upperdentry);
187bbb1e54dSMiklos Szeredi 		}
188bbb1e54dSMiklos Szeredi 		if (!inode)
189bbb1e54dSMiklos Szeredi 			goto out_free_oe;
190bbb1e54dSMiklos Szeredi 		ovl_copyattr(realdentry->d_inode, inode);
191bbb1e54dSMiklos Szeredi 	}
192bbb1e54dSMiklos Szeredi 
193bbb1e54dSMiklos Szeredi 	revert_creds(old_cred);
194bbb1e54dSMiklos Szeredi 	oe->opaque = upperopaque;
195bbb1e54dSMiklos Szeredi 	oe->__upperdentry = upperdentry;
196bbb1e54dSMiklos Szeredi 	memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
197bbb1e54dSMiklos Szeredi 	kfree(stack);
198bbb1e54dSMiklos Szeredi 	dentry->d_fsdata = oe;
199bbb1e54dSMiklos Szeredi 	d_add(dentry, inode);
200bbb1e54dSMiklos Szeredi 
201bbb1e54dSMiklos Szeredi 	return NULL;
202bbb1e54dSMiklos Szeredi 
203bbb1e54dSMiklos Szeredi out_free_oe:
204bbb1e54dSMiklos Szeredi 	kfree(oe);
205bbb1e54dSMiklos Szeredi out_put:
206bbb1e54dSMiklos Szeredi 	for (i = 0; i < ctr; i++)
207bbb1e54dSMiklos Szeredi 		dput(stack[i].dentry);
208bbb1e54dSMiklos Szeredi 	kfree(stack);
209bbb1e54dSMiklos Szeredi out_put_upper:
210bbb1e54dSMiklos Szeredi 	dput(upperdentry);
211bbb1e54dSMiklos Szeredi out:
212bbb1e54dSMiklos Szeredi 	revert_creds(old_cred);
213bbb1e54dSMiklos Szeredi 	return ERR_PTR(err);
214bbb1e54dSMiklos Szeredi }
215bbb1e54dSMiklos Szeredi 
216bbb1e54dSMiklos Szeredi bool ovl_lower_positive(struct dentry *dentry)
217bbb1e54dSMiklos Szeredi {
218bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe = dentry->d_fsdata;
219bbb1e54dSMiklos Szeredi 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
220bbb1e54dSMiklos Szeredi 	const struct qstr *name = &dentry->d_name;
221bbb1e54dSMiklos Szeredi 	unsigned int i;
222bbb1e54dSMiklos Szeredi 	bool positive = false;
223bbb1e54dSMiklos Szeredi 	bool done = false;
224bbb1e54dSMiklos Szeredi 
225bbb1e54dSMiklos Szeredi 	/*
226bbb1e54dSMiklos Szeredi 	 * If dentry is negative, then lower is positive iff this is a
227bbb1e54dSMiklos Szeredi 	 * whiteout.
228bbb1e54dSMiklos Szeredi 	 */
229bbb1e54dSMiklos Szeredi 	if (!dentry->d_inode)
230bbb1e54dSMiklos Szeredi 		return oe->opaque;
231bbb1e54dSMiklos Szeredi 
232bbb1e54dSMiklos Szeredi 	/* Negative upper -> positive lower */
233bbb1e54dSMiklos Szeredi 	if (!oe->__upperdentry)
234bbb1e54dSMiklos Szeredi 		return true;
235bbb1e54dSMiklos Szeredi 
236bbb1e54dSMiklos Szeredi 	/* Positive upper -> have to look up lower to see whether it exists */
237bbb1e54dSMiklos Szeredi 	for (i = 0; !done && !positive && i < poe->numlower; i++) {
238bbb1e54dSMiklos Szeredi 		struct dentry *this;
239bbb1e54dSMiklos Szeredi 		struct dentry *lowerdir = poe->lowerstack[i].dentry;
240bbb1e54dSMiklos Szeredi 
241bbb1e54dSMiklos Szeredi 		this = lookup_one_len_unlocked(name->name, lowerdir,
242bbb1e54dSMiklos Szeredi 					       name->len);
243bbb1e54dSMiklos Szeredi 		if (IS_ERR(this)) {
244bbb1e54dSMiklos Szeredi 			switch (PTR_ERR(this)) {
245bbb1e54dSMiklos Szeredi 			case -ENOENT:
246bbb1e54dSMiklos Szeredi 			case -ENAMETOOLONG:
247bbb1e54dSMiklos Szeredi 				break;
248bbb1e54dSMiklos Szeredi 
249bbb1e54dSMiklos Szeredi 			default:
250bbb1e54dSMiklos Szeredi 				/*
251bbb1e54dSMiklos Szeredi 				 * Assume something is there, we just couldn't
252bbb1e54dSMiklos Szeredi 				 * access it.
253bbb1e54dSMiklos Szeredi 				 */
254bbb1e54dSMiklos Szeredi 				positive = true;
255bbb1e54dSMiklos Szeredi 				break;
256bbb1e54dSMiklos Szeredi 			}
257bbb1e54dSMiklos Szeredi 		} else {
258bbb1e54dSMiklos Szeredi 			if (this->d_inode) {
259bbb1e54dSMiklos Szeredi 				positive = !ovl_is_whiteout(this);
260bbb1e54dSMiklos Szeredi 				done = true;
261bbb1e54dSMiklos Szeredi 			}
262bbb1e54dSMiklos Szeredi 			dput(this);
263bbb1e54dSMiklos Szeredi 		}
264bbb1e54dSMiklos Szeredi 	}
265bbb1e54dSMiklos Szeredi 
266bbb1e54dSMiklos Szeredi 	return positive;
267bbb1e54dSMiklos Szeredi }
268