xref: /openbmc/linux/fs/overlayfs/namei.c (revision 02b69b284cd7815239fabfe895bfef9a9eb5a3ce)
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>
13*02b69b28SMiklos Szeredi #include <linux/ratelimit.h>
14bbb1e54dSMiklos Szeredi #include "overlayfs.h"
15bbb1e54dSMiklos Szeredi #include "ovl_entry.h"
16bbb1e54dSMiklos Szeredi 
17e28edc46SMiklos Szeredi struct ovl_lookup_data {
18e28edc46SMiklos Szeredi 	struct qstr name;
19e28edc46SMiklos Szeredi 	bool is_dir;
20e28edc46SMiklos Szeredi 	bool opaque;
21e28edc46SMiklos Szeredi 	bool stop;
22e28edc46SMiklos Szeredi 	bool last;
23*02b69b28SMiklos Szeredi 	char *redirect;
24e28edc46SMiklos Szeredi };
25bbb1e54dSMiklos Szeredi 
26*02b69b28SMiklos Szeredi static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
27*02b69b28SMiklos Szeredi 			      size_t prelen, const char *post)
28*02b69b28SMiklos Szeredi {
29*02b69b28SMiklos Szeredi 	int res;
30*02b69b28SMiklos Szeredi 	char *s, *next, *buf = NULL;
31*02b69b28SMiklos Szeredi 
32*02b69b28SMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0);
33*02b69b28SMiklos Szeredi 	if (res < 0) {
34*02b69b28SMiklos Szeredi 		if (res == -ENODATA || res == -EOPNOTSUPP)
35*02b69b28SMiklos Szeredi 			return 0;
36*02b69b28SMiklos Szeredi 		goto fail;
37*02b69b28SMiklos Szeredi 	}
38*02b69b28SMiklos Szeredi 	buf = kzalloc(prelen + res + strlen(post) + 1, GFP_TEMPORARY);
39*02b69b28SMiklos Szeredi 	if (!buf)
40*02b69b28SMiklos Szeredi 		return -ENOMEM;
41*02b69b28SMiklos Szeredi 
42*02b69b28SMiklos Szeredi 	if (res == 0)
43*02b69b28SMiklos Szeredi 		goto invalid;
44*02b69b28SMiklos Szeredi 
45*02b69b28SMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res);
46*02b69b28SMiklos Szeredi 	if (res < 0)
47*02b69b28SMiklos Szeredi 		goto fail;
48*02b69b28SMiklos Szeredi 	if (res == 0)
49*02b69b28SMiklos Szeredi 		goto invalid;
50*02b69b28SMiklos Szeredi 	if (buf[0] == '/') {
51*02b69b28SMiklos Szeredi 		for (s = buf; *s++ == '/'; s = next) {
52*02b69b28SMiklos Szeredi 			next = strchrnul(s, '/');
53*02b69b28SMiklos Szeredi 			if (s == next)
54*02b69b28SMiklos Szeredi 				goto invalid;
55*02b69b28SMiklos Szeredi 		}
56*02b69b28SMiklos Szeredi 	} else {
57*02b69b28SMiklos Szeredi 		if (strchr(buf, '/') != NULL)
58*02b69b28SMiklos Szeredi 			goto invalid;
59*02b69b28SMiklos Szeredi 
60*02b69b28SMiklos Szeredi 		memmove(buf + prelen, buf, res);
61*02b69b28SMiklos Szeredi 		memcpy(buf, d->name.name, prelen);
62*02b69b28SMiklos Szeredi 	}
63*02b69b28SMiklos Szeredi 
64*02b69b28SMiklos Szeredi 	strcat(buf, post);
65*02b69b28SMiklos Szeredi 	kfree(d->redirect);
66*02b69b28SMiklos Szeredi 	d->redirect = buf;
67*02b69b28SMiklos Szeredi 	d->name.name = d->redirect;
68*02b69b28SMiklos Szeredi 	d->name.len = strlen(d->redirect);
69*02b69b28SMiklos Szeredi 
70*02b69b28SMiklos Szeredi 	return 0;
71*02b69b28SMiklos Szeredi 
72*02b69b28SMiklos Szeredi err_free:
73*02b69b28SMiklos Szeredi 	kfree(buf);
74*02b69b28SMiklos Szeredi 	return 0;
75*02b69b28SMiklos Szeredi fail:
76*02b69b28SMiklos Szeredi 	pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res);
77*02b69b28SMiklos Szeredi 	goto err_free;
78*02b69b28SMiklos Szeredi invalid:
79*02b69b28SMiklos Szeredi 	pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf);
80*02b69b28SMiklos Szeredi 	goto err_free;
81*02b69b28SMiklos Szeredi }
82*02b69b28SMiklos Szeredi 
83bbb1e54dSMiklos Szeredi static bool ovl_is_opaquedir(struct dentry *dentry)
84bbb1e54dSMiklos Szeredi {
85bbb1e54dSMiklos Szeredi 	int res;
86bbb1e54dSMiklos Szeredi 	char val;
87bbb1e54dSMiklos Szeredi 
88bbb1e54dSMiklos Szeredi 	if (!d_is_dir(dentry))
89bbb1e54dSMiklos Szeredi 		return false;
90bbb1e54dSMiklos Szeredi 
91bbb1e54dSMiklos Szeredi 	res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
92bbb1e54dSMiklos Szeredi 	if (res == 1 && val == 'y')
93bbb1e54dSMiklos Szeredi 		return true;
94bbb1e54dSMiklos Szeredi 
95bbb1e54dSMiklos Szeredi 	return false;
96bbb1e54dSMiklos Szeredi }
97bbb1e54dSMiklos Szeredi 
98e28edc46SMiklos Szeredi static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
99e28edc46SMiklos Szeredi 			     const char *name, unsigned int namelen,
100*02b69b28SMiklos Szeredi 			     size_t prelen, const char *post,
101e28edc46SMiklos Szeredi 			     struct dentry **ret)
102e28edc46SMiklos Szeredi {
103e28edc46SMiklos Szeredi 	struct dentry *this;
104e28edc46SMiklos Szeredi 	int err;
105e28edc46SMiklos Szeredi 
106e28edc46SMiklos Szeredi 	this = lookup_one_len_unlocked(name, base, namelen);
107e28edc46SMiklos Szeredi 	if (IS_ERR(this)) {
108e28edc46SMiklos Szeredi 		err = PTR_ERR(this);
109e28edc46SMiklos Szeredi 		this = NULL;
110e28edc46SMiklos Szeredi 		if (err == -ENOENT || err == -ENAMETOOLONG)
111e28edc46SMiklos Szeredi 			goto out;
112e28edc46SMiklos Szeredi 		goto out_err;
113e28edc46SMiklos Szeredi 	}
114e28edc46SMiklos Szeredi 	if (!this->d_inode)
115e28edc46SMiklos Szeredi 		goto put_and_out;
116e28edc46SMiklos Szeredi 
117e28edc46SMiklos Szeredi 	if (ovl_dentry_weird(this)) {
118e28edc46SMiklos Szeredi 		/* Don't support traversing automounts and other weirdness */
119e28edc46SMiklos Szeredi 		err = -EREMOTE;
120e28edc46SMiklos Szeredi 		goto out_err;
121e28edc46SMiklos Szeredi 	}
122e28edc46SMiklos Szeredi 	if (ovl_is_whiteout(this)) {
123e28edc46SMiklos Szeredi 		d->stop = d->opaque = true;
124e28edc46SMiklos Szeredi 		goto put_and_out;
125e28edc46SMiklos Szeredi 	}
126e28edc46SMiklos Szeredi 	if (!d_can_lookup(this)) {
127e28edc46SMiklos Szeredi 		d->stop = true;
128e28edc46SMiklos Szeredi 		if (d->is_dir)
129e28edc46SMiklos Szeredi 			goto put_and_out;
130e28edc46SMiklos Szeredi 		goto out;
131e28edc46SMiklos Szeredi 	}
132e28edc46SMiklos Szeredi 	d->is_dir = true;
133e28edc46SMiklos Szeredi 	if (!d->last && ovl_is_opaquedir(this)) {
134e28edc46SMiklos Szeredi 		d->stop = d->opaque = true;
135e28edc46SMiklos Szeredi 		goto out;
136e28edc46SMiklos Szeredi 	}
137*02b69b28SMiklos Szeredi 	err = ovl_check_redirect(this, d, prelen, post);
138*02b69b28SMiklos Szeredi 	if (err)
139*02b69b28SMiklos Szeredi 		goto out_err;
140e28edc46SMiklos Szeredi out:
141e28edc46SMiklos Szeredi 	*ret = this;
142e28edc46SMiklos Szeredi 	return 0;
143e28edc46SMiklos Szeredi 
144e28edc46SMiklos Szeredi put_and_out:
145e28edc46SMiklos Szeredi 	dput(this);
146e28edc46SMiklos Szeredi 	this = NULL;
147e28edc46SMiklos Szeredi 	goto out;
148e28edc46SMiklos Szeredi 
149e28edc46SMiklos Szeredi out_err:
150e28edc46SMiklos Szeredi 	dput(this);
151e28edc46SMiklos Szeredi 	return err;
152e28edc46SMiklos Szeredi }
153e28edc46SMiklos Szeredi 
154e28edc46SMiklos Szeredi static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
155e28edc46SMiklos Szeredi 			    struct dentry **ret)
156e28edc46SMiklos Szeredi {
157*02b69b28SMiklos Szeredi 	const char *s = d->name.name;
158*02b69b28SMiklos Szeredi 	struct dentry *dentry = NULL;
159*02b69b28SMiklos Szeredi 	int err;
160*02b69b28SMiklos Szeredi 
161*02b69b28SMiklos Szeredi 	if (*s != '/')
162*02b69b28SMiklos Szeredi 		return ovl_lookup_single(base, d, d->name.name, d->name.len,
163*02b69b28SMiklos Szeredi 					 0, "", ret);
164*02b69b28SMiklos Szeredi 
165*02b69b28SMiklos Szeredi 	while (*s++ == '/' && !IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
166*02b69b28SMiklos Szeredi 		const char *next = strchrnul(s, '/');
167*02b69b28SMiklos Szeredi 		size_t slen = strlen(s);
168*02b69b28SMiklos Szeredi 
169*02b69b28SMiklos Szeredi 		if (WARN_ON(slen > d->name.len) ||
170*02b69b28SMiklos Szeredi 		    WARN_ON(strcmp(d->name.name + d->name.len - slen, s)))
171*02b69b28SMiklos Szeredi 			return -EIO;
172*02b69b28SMiklos Szeredi 
173*02b69b28SMiklos Szeredi 		err = ovl_lookup_single(base, d, s, next - s,
174*02b69b28SMiklos Szeredi 					d->name.len - slen, next, &base);
175*02b69b28SMiklos Szeredi 		dput(dentry);
176*02b69b28SMiklos Szeredi 		if (err)
177*02b69b28SMiklos Szeredi 			return err;
178*02b69b28SMiklos Szeredi 		dentry = base;
179*02b69b28SMiklos Szeredi 		s = next;
180*02b69b28SMiklos Szeredi 	}
181*02b69b28SMiklos Szeredi 	*ret = dentry;
182*02b69b28SMiklos Szeredi 	return 0;
183e28edc46SMiklos Szeredi }
184e28edc46SMiklos Szeredi 
185bbb1e54dSMiklos Szeredi /*
186bbb1e54dSMiklos Szeredi  * Returns next layer in stack starting from top.
187bbb1e54dSMiklos Szeredi  * Returns -1 if this is the last layer.
188bbb1e54dSMiklos Szeredi  */
189bbb1e54dSMiklos Szeredi int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
190bbb1e54dSMiklos Szeredi {
191bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe = dentry->d_fsdata;
192bbb1e54dSMiklos Szeredi 
193bbb1e54dSMiklos Szeredi 	BUG_ON(idx < 0);
194bbb1e54dSMiklos Szeredi 	if (idx == 0) {
195bbb1e54dSMiklos Szeredi 		ovl_path_upper(dentry, path);
196bbb1e54dSMiklos Szeredi 		if (path->dentry)
197bbb1e54dSMiklos Szeredi 			return oe->numlower ? 1 : -1;
198bbb1e54dSMiklos Szeredi 		idx++;
199bbb1e54dSMiklos Szeredi 	}
200bbb1e54dSMiklos Szeredi 	BUG_ON(idx > oe->numlower);
201bbb1e54dSMiklos Szeredi 	*path = oe->lowerstack[idx - 1];
202bbb1e54dSMiklos Szeredi 
203bbb1e54dSMiklos Szeredi 	return (idx < oe->numlower) ? idx + 1 : -1;
204bbb1e54dSMiklos Szeredi }
205bbb1e54dSMiklos Szeredi 
206bbb1e54dSMiklos Szeredi struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
207bbb1e54dSMiklos Szeredi 			  unsigned int flags)
208bbb1e54dSMiklos Szeredi {
209bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe;
210bbb1e54dSMiklos Szeredi 	const struct cred *old_cred;
2116b2d5fe4SMiklos Szeredi 	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
212bbb1e54dSMiklos Szeredi 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
213bbb1e54dSMiklos Szeredi 	struct path *stack = NULL;
214bbb1e54dSMiklos Szeredi 	struct dentry *upperdir, *upperdentry = NULL;
215bbb1e54dSMiklos Szeredi 	unsigned int ctr = 0;
216bbb1e54dSMiklos Szeredi 	struct inode *inode = NULL;
217bbb1e54dSMiklos Szeredi 	bool upperopaque = false;
218*02b69b28SMiklos Szeredi 	char *upperredirect = NULL;
219bbb1e54dSMiklos Szeredi 	struct dentry *this;
220bbb1e54dSMiklos Szeredi 	unsigned int i;
221bbb1e54dSMiklos Szeredi 	int err;
222e28edc46SMiklos Szeredi 	struct ovl_lookup_data d = {
223e28edc46SMiklos Szeredi 		.name = dentry->d_name,
224e28edc46SMiklos Szeredi 		.is_dir = false,
225e28edc46SMiklos Szeredi 		.opaque = false,
226e28edc46SMiklos Szeredi 		.stop = false,
227e28edc46SMiklos Szeredi 		.last = !poe->numlower,
228*02b69b28SMiklos Szeredi 		.redirect = NULL,
229e28edc46SMiklos Szeredi 	};
230bbb1e54dSMiklos Szeredi 
2316b2d5fe4SMiklos Szeredi 	if (dentry->d_name.len > ofs->namelen)
2326b2d5fe4SMiklos Szeredi 		return ERR_PTR(-ENAMETOOLONG);
2336b2d5fe4SMiklos Szeredi 
234bbb1e54dSMiklos Szeredi 	old_cred = ovl_override_creds(dentry->d_sb);
235bbb1e54dSMiklos Szeredi 	upperdir = ovl_upperdentry_dereference(poe);
236bbb1e54dSMiklos Szeredi 	if (upperdir) {
237e28edc46SMiklos Szeredi 		err = ovl_lookup_layer(upperdir, &d, &upperdentry);
238e28edc46SMiklos Szeredi 		if (err)
239bbb1e54dSMiklos Szeredi 			goto out;
240bbb1e54dSMiklos Szeredi 
241e28edc46SMiklos Szeredi 		if (upperdentry && unlikely(ovl_dentry_remote(upperdentry))) {
242e28edc46SMiklos Szeredi 			dput(upperdentry);
243bbb1e54dSMiklos Szeredi 			err = -EREMOTE;
244bbb1e54dSMiklos Szeredi 			goto out;
245bbb1e54dSMiklos Szeredi 		}
246*02b69b28SMiklos Szeredi 
247*02b69b28SMiklos Szeredi 		if (d.redirect) {
248*02b69b28SMiklos Szeredi 			upperredirect = kstrdup(d.redirect, GFP_KERNEL);
249*02b69b28SMiklos Szeredi 			if (!upperredirect)
250*02b69b28SMiklos Szeredi 				goto out_put_upper;
251*02b69b28SMiklos Szeredi 			if (d.redirect[0] == '/')
252*02b69b28SMiklos Szeredi 				poe = dentry->d_sb->s_root->d_fsdata;
253*02b69b28SMiklos Szeredi 		}
254e28edc46SMiklos Szeredi 		upperopaque = d.opaque;
255bbb1e54dSMiklos Szeredi 	}
256bbb1e54dSMiklos Szeredi 
257e28edc46SMiklos Szeredi 	if (!d.stop && poe->numlower) {
258bbb1e54dSMiklos Szeredi 		err = -ENOMEM;
259*02b69b28SMiklos Szeredi 		stack = kcalloc(ofs->numlower, sizeof(struct path),
260e28edc46SMiklos Szeredi 				GFP_TEMPORARY);
261bbb1e54dSMiklos Szeredi 		if (!stack)
262bbb1e54dSMiklos Szeredi 			goto out_put_upper;
263bbb1e54dSMiklos Szeredi 	}
264bbb1e54dSMiklos Szeredi 
265e28edc46SMiklos Szeredi 	for (i = 0; !d.stop && i < poe->numlower; i++) {
266bbb1e54dSMiklos Szeredi 		struct path lowerpath = poe->lowerstack[i];
267bbb1e54dSMiklos Szeredi 
268e28edc46SMiklos Szeredi 		d.last = i == poe->numlower - 1;
269e28edc46SMiklos Szeredi 		err = ovl_lookup_layer(lowerpath.dentry, &d, &this);
270e28edc46SMiklos Szeredi 		if (err)
271bbb1e54dSMiklos Szeredi 			goto out_put;
2726b2d5fe4SMiklos Szeredi 
273bbb1e54dSMiklos Szeredi 		if (!this)
274bbb1e54dSMiklos Szeredi 			continue;
275bbb1e54dSMiklos Szeredi 
276bbb1e54dSMiklos Szeredi 		stack[ctr].dentry = this;
277bbb1e54dSMiklos Szeredi 		stack[ctr].mnt = lowerpath.mnt;
278bbb1e54dSMiklos Szeredi 		ctr++;
279*02b69b28SMiklos Szeredi 
280*02b69b28SMiklos Szeredi 		if (d.stop)
281*02b69b28SMiklos Szeredi 			break;
282*02b69b28SMiklos Szeredi 
283*02b69b28SMiklos Szeredi 		if (d.redirect &&
284*02b69b28SMiklos Szeredi 		    d.redirect[0] == '/' &&
285*02b69b28SMiklos Szeredi 		    poe != dentry->d_sb->s_root->d_fsdata) {
286*02b69b28SMiklos Szeredi 			poe = dentry->d_sb->s_root->d_fsdata;
287*02b69b28SMiklos Szeredi 
288*02b69b28SMiklos Szeredi 			/* Find the current layer on the root dentry */
289*02b69b28SMiklos Szeredi 			for (i = 0; i < poe->numlower; i++)
290*02b69b28SMiklos Szeredi 				if (poe->lowerstack[i].mnt == lowerpath.mnt)
291*02b69b28SMiklos Szeredi 					break;
292*02b69b28SMiklos Szeredi 			if (WARN_ON(i == poe->numlower))
293*02b69b28SMiklos Szeredi 				break;
294*02b69b28SMiklos Szeredi 		}
295bbb1e54dSMiklos Szeredi 	}
296bbb1e54dSMiklos Szeredi 
297bbb1e54dSMiklos Szeredi 	oe = ovl_alloc_entry(ctr);
298bbb1e54dSMiklos Szeredi 	err = -ENOMEM;
299bbb1e54dSMiklos Szeredi 	if (!oe)
300bbb1e54dSMiklos Szeredi 		goto out_put;
301bbb1e54dSMiklos Szeredi 
302bbb1e54dSMiklos Szeredi 	if (upperdentry || ctr) {
303bbb1e54dSMiklos Szeredi 		struct dentry *realdentry;
304bbb1e54dSMiklos Szeredi 		struct inode *realinode;
305bbb1e54dSMiklos Szeredi 
306bbb1e54dSMiklos Szeredi 		realdentry = upperdentry ? upperdentry : stack[0].dentry;
307bbb1e54dSMiklos Szeredi 		realinode = d_inode(realdentry);
308bbb1e54dSMiklos Szeredi 
309bbb1e54dSMiklos Szeredi 		err = -ENOMEM;
310bbb1e54dSMiklos Szeredi 		if (upperdentry && !d_is_dir(upperdentry)) {
311bbb1e54dSMiklos Szeredi 			inode = ovl_get_inode(dentry->d_sb, realinode);
312bbb1e54dSMiklos Szeredi 		} else {
313bbb1e54dSMiklos Szeredi 			inode = ovl_new_inode(dentry->d_sb, realinode->i_mode,
314bbb1e54dSMiklos Szeredi 					      realinode->i_rdev);
315bbb1e54dSMiklos Szeredi 			if (inode)
316bbb1e54dSMiklos Szeredi 				ovl_inode_init(inode, realinode, !!upperdentry);
317bbb1e54dSMiklos Szeredi 		}
318bbb1e54dSMiklos Szeredi 		if (!inode)
319bbb1e54dSMiklos Szeredi 			goto out_free_oe;
320bbb1e54dSMiklos Szeredi 		ovl_copyattr(realdentry->d_inode, inode);
321bbb1e54dSMiklos Szeredi 	}
322bbb1e54dSMiklos Szeredi 
323bbb1e54dSMiklos Szeredi 	revert_creds(old_cred);
324bbb1e54dSMiklos Szeredi 	oe->opaque = upperopaque;
325*02b69b28SMiklos Szeredi 	oe->redirect = upperredirect;
326bbb1e54dSMiklos Szeredi 	oe->__upperdentry = upperdentry;
327bbb1e54dSMiklos Szeredi 	memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
328bbb1e54dSMiklos Szeredi 	kfree(stack);
329*02b69b28SMiklos Szeredi 	kfree(d.redirect);
330bbb1e54dSMiklos Szeredi 	dentry->d_fsdata = oe;
331bbb1e54dSMiklos Szeredi 	d_add(dentry, inode);
332bbb1e54dSMiklos Szeredi 
333bbb1e54dSMiklos Szeredi 	return NULL;
334bbb1e54dSMiklos Szeredi 
335bbb1e54dSMiklos Szeredi out_free_oe:
336bbb1e54dSMiklos Szeredi 	kfree(oe);
337bbb1e54dSMiklos Szeredi out_put:
338bbb1e54dSMiklos Szeredi 	for (i = 0; i < ctr; i++)
339bbb1e54dSMiklos Szeredi 		dput(stack[i].dentry);
340bbb1e54dSMiklos Szeredi 	kfree(stack);
341bbb1e54dSMiklos Szeredi out_put_upper:
342bbb1e54dSMiklos Szeredi 	dput(upperdentry);
343*02b69b28SMiklos Szeredi 	kfree(upperredirect);
344bbb1e54dSMiklos Szeredi out:
345*02b69b28SMiklos Szeredi 	kfree(d.redirect);
346bbb1e54dSMiklos Szeredi 	revert_creds(old_cred);
347bbb1e54dSMiklos Szeredi 	return ERR_PTR(err);
348bbb1e54dSMiklos Szeredi }
349bbb1e54dSMiklos Szeredi 
350bbb1e54dSMiklos Szeredi bool ovl_lower_positive(struct dentry *dentry)
351bbb1e54dSMiklos Szeredi {
352bbb1e54dSMiklos Szeredi 	struct ovl_entry *oe = dentry->d_fsdata;
353bbb1e54dSMiklos Szeredi 	struct ovl_entry *poe = dentry->d_parent->d_fsdata;
354bbb1e54dSMiklos Szeredi 	const struct qstr *name = &dentry->d_name;
355bbb1e54dSMiklos Szeredi 	unsigned int i;
356bbb1e54dSMiklos Szeredi 	bool positive = false;
357bbb1e54dSMiklos Szeredi 	bool done = false;
358bbb1e54dSMiklos Szeredi 
359bbb1e54dSMiklos Szeredi 	/*
360bbb1e54dSMiklos Szeredi 	 * If dentry is negative, then lower is positive iff this is a
361bbb1e54dSMiklos Szeredi 	 * whiteout.
362bbb1e54dSMiklos Szeredi 	 */
363bbb1e54dSMiklos Szeredi 	if (!dentry->d_inode)
364bbb1e54dSMiklos Szeredi 		return oe->opaque;
365bbb1e54dSMiklos Szeredi 
366bbb1e54dSMiklos Szeredi 	/* Negative upper -> positive lower */
367bbb1e54dSMiklos Szeredi 	if (!oe->__upperdentry)
368bbb1e54dSMiklos Szeredi 		return true;
369bbb1e54dSMiklos Szeredi 
370bbb1e54dSMiklos Szeredi 	/* Positive upper -> have to look up lower to see whether it exists */
371bbb1e54dSMiklos Szeredi 	for (i = 0; !done && !positive && i < poe->numlower; i++) {
372bbb1e54dSMiklos Szeredi 		struct dentry *this;
373bbb1e54dSMiklos Szeredi 		struct dentry *lowerdir = poe->lowerstack[i].dentry;
374bbb1e54dSMiklos Szeredi 
375bbb1e54dSMiklos Szeredi 		this = lookup_one_len_unlocked(name->name, lowerdir,
376bbb1e54dSMiklos Szeredi 					       name->len);
377bbb1e54dSMiklos Szeredi 		if (IS_ERR(this)) {
378bbb1e54dSMiklos Szeredi 			switch (PTR_ERR(this)) {
379bbb1e54dSMiklos Szeredi 			case -ENOENT:
380bbb1e54dSMiklos Szeredi 			case -ENAMETOOLONG:
381bbb1e54dSMiklos Szeredi 				break;
382bbb1e54dSMiklos Szeredi 
383bbb1e54dSMiklos Szeredi 			default:
384bbb1e54dSMiklos Szeredi 				/*
385bbb1e54dSMiklos Szeredi 				 * Assume something is there, we just couldn't
386bbb1e54dSMiklos Szeredi 				 * access it.
387bbb1e54dSMiklos Szeredi 				 */
388bbb1e54dSMiklos Szeredi 				positive = true;
389bbb1e54dSMiklos Szeredi 				break;
390bbb1e54dSMiklos Szeredi 			}
391bbb1e54dSMiklos Szeredi 		} else {
392bbb1e54dSMiklos Szeredi 			if (this->d_inode) {
393bbb1e54dSMiklos Szeredi 				positive = !ovl_is_whiteout(this);
394bbb1e54dSMiklos Szeredi 				done = true;
395bbb1e54dSMiklos Szeredi 			}
396bbb1e54dSMiklos Szeredi 			dput(this);
397bbb1e54dSMiklos Szeredi 		}
398bbb1e54dSMiklos Szeredi 	}
399bbb1e54dSMiklos Szeredi 
400bbb1e54dSMiklos Szeredi 	return positive;
401bbb1e54dSMiklos Szeredi }
402