Skip to content

Commit cbe7fba

Browse files
amir73ilMiklos Szeredi
authored andcommitted
ovl: make sure that real fid is 32bit aligned in memory
Seprate on-disk encoding from in-memory and on-wire resresentation of overlay file handle. In-memory and on-wire we only ever pass around pointers to struct ovl_fh, which encapsulates at offset 3 the on-disk format struct ovl_fb. struct ovl_fb encapsulates at offset 21 the real file handle. That makes sure that the real file handle is always 32bit aligned in-memory when passed down to the underlying filesystem. On-disk format remains the same and store/load are done into correctly aligned buffer. New nfs exported file handles are exported with aligned real fid. Old nfs file handles are copied to an aligned buffer before being decoded. Reported-by: Al Viro <[email protected]> Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 7e63c87 commit cbe7fba

File tree

4 files changed

+115
-73
lines changed

4 files changed

+115
-73
lines changed

fs/overlayfs/copy_up.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -251,29 +251,31 @@ struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper)
251251
WARN_ON(fh_type == FILEID_INVALID))
252252
goto out;
253253

254-
BUILD_BUG_ON(MAX_HANDLE_SZ + offsetof(struct ovl_fh, fid) > 255);
255-
fh_len = offsetof(struct ovl_fh, fid) + buflen;
256-
fh = kmalloc(fh_len, GFP_KERNEL);
254+
/* Make sure the real fid stays 32bit aligned */
255+
BUILD_BUG_ON(OVL_FH_FID_OFFSET % 4);
256+
BUILD_BUG_ON(MAX_HANDLE_SZ + OVL_FH_FID_OFFSET > 255);
257+
fh_len = OVL_FH_FID_OFFSET + buflen;
258+
fh = kzalloc(fh_len, GFP_KERNEL);
257259
if (!fh) {
258260
fh = ERR_PTR(-ENOMEM);
259261
goto out;
260262
}
261263

262-
fh->version = OVL_FH_VERSION;
263-
fh->magic = OVL_FH_MAGIC;
264-
fh->type = fh_type;
265-
fh->flags = OVL_FH_FLAG_CPU_ENDIAN;
264+
fh->fb.version = OVL_FH_VERSION;
265+
fh->fb.magic = OVL_FH_MAGIC;
266+
fh->fb.type = fh_type;
267+
fh->fb.flags = OVL_FH_FLAG_CPU_ENDIAN;
266268
/*
267269
* When we will want to decode an overlay dentry from this handle
268270
* and all layers are on the same fs, if we get a disconncted real
269271
* dentry when we decode fid, the only way to tell if we should assign
270272
* it to upperdentry or to lowerstack is by checking this flag.
271273
*/
272274
if (is_upper)
273-
fh->flags |= OVL_FH_FLAG_PATH_UPPER;
274-
fh->len = fh_len;
275-
fh->uuid = *uuid;
276-
memcpy(fh->fid, buf, buflen);
275+
fh->fb.flags |= OVL_FH_FLAG_PATH_UPPER;
276+
fh->fb.len = fh_len - OVL_FH_WIRE_OFFSET;
277+
fh->fb.uuid = *uuid;
278+
memcpy(fh->fb.fid, buf, buflen);
277279

278280
out:
279281
kfree(buf);
@@ -300,8 +302,8 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
300302
/*
301303
* Do not fail when upper doesn't support xattrs.
302304
*/
303-
err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh,
304-
fh ? fh->len : 0, 0);
305+
err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh->buf,
306+
fh ? fh->fb.len : 0, 0);
305307
kfree(fh);
306308

307309
return err;
@@ -317,7 +319,7 @@ static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index)
317319
if (IS_ERR(fh))
318320
return PTR_ERR(fh);
319321

320-
err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh, fh->len, 0);
322+
err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh->buf, fh->fb.len, 0);
321323

322324
kfree(fh);
323325
return err;

fs/overlayfs/export.c

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,11 @@ static int ovl_check_encode_origin(struct dentry *dentry)
211211
return 1;
212212
}
213213

214-
static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
214+
static int ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen)
215215
{
216216
struct ovl_fh *fh = NULL;
217217
int err, enc_lower;
218+
int len;
218219

219220
/*
220221
* Check if we should encode a lower or upper file handle and maybe
@@ -231,43 +232,29 @@ static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
231232
return PTR_ERR(fh);
232233

233234
err = -EOVERFLOW;
234-
if (fh->len > buflen)
235+
len = OVL_FH_LEN(fh);
236+
if (len > buflen)
235237
goto fail;
236238

237-
memcpy(buf, (char *)fh, fh->len);
238-
err = fh->len;
239+
memcpy(fid, fh, len);
240+
err = len;
239241

240242
out:
241243
kfree(fh);
242244
return err;
243245

244246
fail:
245247
pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
246-
dentry, err, buflen, fh ? (int)fh->len : 0,
247-
fh ? fh->type : 0);
248+
dentry, err, buflen, fh ? (int)fh->fb.len : 0,
249+
fh ? fh->fb.type : 0);
248250
goto out;
249251
}
250252

251-
static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len)
252-
{
253-
int res, len = *max_len << 2;
254-
255-
res = ovl_d_to_fh(dentry, (char *)fid, len);
256-
if (res <= 0)
257-
return FILEID_INVALID;
258-
259-
len = res;
260-
261-
/* Round up to dwords */
262-
*max_len = (len + 3) >> 2;
263-
return OVL_FILEID;
264-
}
265-
266253
static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
267254
struct inode *parent)
268255
{
269256
struct dentry *dentry;
270-
int type;
257+
int bytes = *max_len << 2;
271258

272259
/* TODO: encode connectable file handles */
273260
if (parent)
@@ -277,10 +264,14 @@ static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
277264
if (WARN_ON(!dentry))
278265
return FILEID_INVALID;
279266

280-
type = ovl_dentry_to_fh(dentry, fid, max_len);
281-
267+
bytes = ovl_dentry_to_fid(dentry, fid, bytes);
282268
dput(dentry);
283-
return type;
269+
if (bytes <= 0)
270+
return FILEID_INVALID;
271+
272+
*max_len = bytes >> 2;
273+
274+
return OVL_FILEID_V1;
284275
}
285276

286277
/*
@@ -777,37 +768,64 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
777768
goto out;
778769
}
779770

771+
static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
772+
{
773+
struct ovl_fh *fh;
774+
775+
/* If on-wire inner fid is aligned - nothing to do */
776+
if (fh_type == OVL_FILEID_V1)
777+
return (struct ovl_fh *)fid;
778+
779+
if (fh_type != OVL_FILEID_V0)
780+
return ERR_PTR(-EINVAL);
781+
782+
fh = kzalloc(buflen, GFP_KERNEL);
783+
if (!fh)
784+
return ERR_PTR(-ENOMEM);
785+
786+
/* Copy unaligned inner fh into aligned buffer */
787+
memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET);
788+
return fh;
789+
}
790+
780791
static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
781792
int fh_len, int fh_type)
782793
{
783794
struct dentry *dentry = NULL;
784-
struct ovl_fh *fh = (struct ovl_fh *) fid;
795+
struct ovl_fh *fh = NULL;
785796
int len = fh_len << 2;
786797
unsigned int flags = 0;
787798
int err;
788799

789-
err = -EINVAL;
790-
if (fh_type != OVL_FILEID)
800+
fh = ovl_fid_to_fh(fid, len, fh_type);
801+
err = PTR_ERR(fh);
802+
if (IS_ERR(fh))
791803
goto out_err;
792804

793805
err = ovl_check_fh_len(fh, len);
794806
if (err)
795807
goto out_err;
796808

797-
flags = fh->flags;
809+
flags = fh->fb.flags;
798810
dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ?
799811
ovl_upper_fh_to_d(sb, fh) :
800812
ovl_lower_fh_to_d(sb, fh);
801813
err = PTR_ERR(dentry);
802814
if (IS_ERR(dentry) && err != -ESTALE)
803815
goto out_err;
804816

817+
out:
818+
/* We may have needed to re-align OVL_FILEID_V0 */
819+
if (!IS_ERR_OR_NULL(fh) && fh != (void *)fid)
820+
kfree(fh);
821+
805822
return dentry;
806823

807824
out_err:
808825
pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
809-
len, fh_type, flags, err);
810-
return ERR_PTR(err);
826+
fh_len, fh_type, flags, err);
827+
dentry = ERR_PTR(err);
828+
goto out;
811829
}
812830

813831
static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid,

fs/overlayfs/namei.c

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,21 @@ static int ovl_acceptable(void *ctx, struct dentry *dentry)
8484
* Return -ENODATA for "origin unknown".
8585
* Return <0 for an invalid file handle.
8686
*/
87-
int ovl_check_fh_len(struct ovl_fh *fh, int fh_len)
87+
int ovl_check_fb_len(struct ovl_fb *fb, int fb_len)
8888
{
89-
if (fh_len < sizeof(struct ovl_fh) || fh_len < fh->len)
89+
if (fb_len < sizeof(struct ovl_fb) || fb_len < fb->len)
9090
return -EINVAL;
9191

92-
if (fh->magic != OVL_FH_MAGIC)
92+
if (fb->magic != OVL_FH_MAGIC)
9393
return -EINVAL;
9494

9595
/* Treat larger version and unknown flags as "origin unknown" */
96-
if (fh->version > OVL_FH_VERSION || fh->flags & ~OVL_FH_FLAG_ALL)
96+
if (fb->version > OVL_FH_VERSION || fb->flags & ~OVL_FH_FLAG_ALL)
9797
return -ENODATA;
9898

9999
/* Treat endianness mismatch as "origin unknown" */
100-
if (!(fh->flags & OVL_FH_FLAG_ANY_ENDIAN) &&
101-
(fh->flags & OVL_FH_FLAG_BIG_ENDIAN) != OVL_FH_FLAG_CPU_ENDIAN)
100+
if (!(fb->flags & OVL_FH_FLAG_ANY_ENDIAN) &&
101+
(fb->flags & OVL_FH_FLAG_BIG_ENDIAN) != OVL_FH_FLAG_CPU_ENDIAN)
102102
return -ENODATA;
103103

104104
return 0;
@@ -119,15 +119,15 @@ static struct ovl_fh *ovl_get_fh(struct dentry *dentry, const char *name)
119119
if (res == 0)
120120
return NULL;
121121

122-
fh = kzalloc(res, GFP_KERNEL);
122+
fh = kzalloc(res + OVL_FH_WIRE_OFFSET, GFP_KERNEL);
123123
if (!fh)
124124
return ERR_PTR(-ENOMEM);
125125

126-
res = vfs_getxattr(dentry, name, fh, res);
126+
res = vfs_getxattr(dentry, name, fh->buf, res);
127127
if (res < 0)
128128
goto fail;
129129

130-
err = ovl_check_fh_len(fh, res);
130+
err = ovl_check_fb_len(&fh->fb, res);
131131
if (err < 0) {
132132
if (err == -ENODATA)
133133
goto out;
@@ -158,12 +158,12 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
158158
* Make sure that the stored uuid matches the uuid of the lower
159159
* layer where file handle will be decoded.
160160
*/
161-
if (!uuid_equal(&fh->uuid, &mnt->mnt_sb->s_uuid))
161+
if (!uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid))
162162
return NULL;
163163

164-
bytes = (fh->len - offsetof(struct ovl_fh, fid));
165-
real = exportfs_decode_fh(mnt, (struct fid *)fh->fid,
166-
bytes >> 2, (int)fh->type,
164+
bytes = (fh->fb.len - offsetof(struct ovl_fb, fid));
165+
real = exportfs_decode_fh(mnt, (struct fid *)fh->fb.fid,
166+
bytes >> 2, (int)fh->fb.type,
167167
connected ? ovl_acceptable : NULL, mnt);
168168
if (IS_ERR(real)) {
169169
/*
@@ -173,7 +173,7 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
173173
* index entries correctly.
174174
*/
175175
if (real == ERR_PTR(-ESTALE) &&
176-
!(fh->flags & OVL_FH_FLAG_PATH_UPPER))
176+
!(fh->fb.flags & OVL_FH_FLAG_PATH_UPPER))
177177
real = NULL;
178178
return real;
179179
}
@@ -410,7 +410,7 @@ static int ovl_verify_fh(struct dentry *dentry, const char *name,
410410
if (IS_ERR(ofh))
411411
return PTR_ERR(ofh);
412412

413-
if (fh->len != ofh->len || memcmp(fh, ofh, fh->len))
413+
if (fh->fb.len != ofh->fb.len || memcmp(&fh->fb, &ofh->fb, fh->fb.len))
414414
err = -ESTALE;
415415

416416
kfree(ofh);
@@ -441,7 +441,7 @@ int ovl_verify_set_fh(struct dentry *dentry, const char *name,
441441

442442
err = ovl_verify_fh(dentry, name, fh);
443443
if (set && err == -ENODATA)
444-
err = ovl_do_setxattr(dentry, name, fh, fh->len, 0);
444+
err = ovl_do_setxattr(dentry, name, fh->buf, fh->fb.len, 0);
445445
if (err)
446446
goto fail;
447447

@@ -515,20 +515,20 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
515515
goto fail;
516516

517517
err = -EINVAL;
518-
if (index->d_name.len < sizeof(struct ovl_fh)*2)
518+
if (index->d_name.len < sizeof(struct ovl_fb)*2)
519519
goto fail;
520520

521521
err = -ENOMEM;
522522
len = index->d_name.len / 2;
523-
fh = kzalloc(len, GFP_KERNEL);
523+
fh = kzalloc(len + OVL_FH_WIRE_OFFSET, GFP_KERNEL);
524524
if (!fh)
525525
goto fail;
526526

527527
err = -EINVAL;
528-
if (hex2bin((u8 *)fh, index->d_name.name, len))
528+
if (hex2bin(fh->buf, index->d_name.name, len))
529529
goto fail;
530530

531-
err = ovl_check_fh_len(fh, len);
531+
err = ovl_check_fb_len(&fh->fb, len);
532532
if (err)
533533
goto fail;
534534

@@ -607,11 +607,11 @@ static int ovl_get_index_name_fh(struct ovl_fh *fh, struct qstr *name)
607607
{
608608
char *n, *s;
609609

610-
n = kcalloc(fh->len, 2, GFP_KERNEL);
610+
n = kcalloc(fh->fb.len, 2, GFP_KERNEL);
611611
if (!n)
612612
return -ENOMEM;
613613

614-
s = bin2hex(n, fh, fh->len);
614+
s = bin2hex(n, fh->buf, fh->fb.len);
615615
*name = (struct qstr) QSTR_INIT(n, s - n);
616616

617617
return 0;

0 commit comments

Comments
 (0)