Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <viro@zeniv.linux.org.uk>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>

authored by

Amir Goldstein and committed by
Miklos Szeredi
cbe7fba8 7e63c87f

+115 -73
+16 -14
fs/overlayfs/copy_up.c
··· 251 251 WARN_ON(fh_type == FILEID_INVALID)) 252 252 goto out; 253 253 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); 257 259 if (!fh) { 258 260 fh = ERR_PTR(-ENOMEM); 259 261 goto out; 260 262 } 261 263 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; 266 268 /* 267 269 * When we will want to decode an overlay dentry from this handle 268 270 * and all layers are on the same fs, if we get a disconncted real ··· 272 270 * it to upperdentry or to lowerstack is by checking this flag. 273 271 */ 274 272 if (is_upper) 275 - fh->flags |= OVL_FH_FLAG_PATH_UPPER; 276 - fh->len = fh_len; 277 - fh->uuid = *uuid; 278 - memcpy(fh->fid, buf, buflen); 273 + fh->fb.flags |= OVL_FH_FLAG_PATH_UPPER; 274 + fh->fb.len = fh_len - OVL_FH_WIRE_OFFSET; 275 + fh->fb.uuid = *uuid; 276 + memcpy(fh->fb.fid, buf, buflen); 279 277 280 278 out: 281 279 kfree(buf); ··· 302 300 /* 303 301 * Do not fail when upper doesn't support xattrs. 304 302 */ 305 - err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh, 306 - fh ? fh->len : 0, 0); 303 + err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh->buf, 304 + fh ? fh->fb.len : 0, 0); 307 305 kfree(fh); 308 306 309 307 return err; ··· 319 317 if (IS_ERR(fh)) 320 318 return PTR_ERR(fh); 321 319 322 - err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh, fh->len, 0); 320 + err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh->buf, fh->fb.len, 0); 323 321 324 322 kfree(fh); 325 323 return err;
+49 -31
fs/overlayfs/export.c
··· 211 211 return 1; 212 212 } 213 213 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) 215 215 { 216 216 struct ovl_fh *fh = NULL; 217 217 int err, enc_lower; 218 + int len; 218 219 219 220 /* 220 221 * Check if we should encode a lower or upper file handle and maybe ··· 232 231 return PTR_ERR(fh); 233 232 234 233 err = -EOVERFLOW; 235 - if (fh->len > buflen) 234 + len = OVL_FH_LEN(fh); 235 + if (len > buflen) 236 236 goto fail; 237 237 238 - memcpy(buf, (char *)fh, fh->len); 239 - err = fh->len; 238 + memcpy(fid, fh, len); 239 + err = len; 240 240 241 241 out: 242 242 kfree(fh); ··· 245 243 246 244 fail: 247 245 pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n", 248 - dentry, err, buflen, fh ? (int)fh->len : 0, 249 - fh ? fh->type : 0); 246 + dentry, err, buflen, fh ? (int)fh->fb.len : 0, 247 + fh ? fh->fb.type : 0); 250 248 goto out; 251 - } 252 - 253 - static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len) 254 - { 255 - int res, len = *max_len << 2; 256 - 257 - res = ovl_d_to_fh(dentry, (char *)fid, len); 258 - if (res <= 0) 259 - return FILEID_INVALID; 260 - 261 - len = res; 262 - 263 - /* Round up to dwords */ 264 - *max_len = (len + 3) >> 2; 265 - return OVL_FILEID; 266 249 } 267 250 268 251 static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len, 269 252 struct inode *parent) 270 253 { 271 254 struct dentry *dentry; 272 - int type; 255 + int bytes = *max_len << 2; 273 256 274 257 /* TODO: encode connectable file handles */ 275 258 if (parent) ··· 264 277 if (WARN_ON(!dentry)) 265 278 return FILEID_INVALID; 266 279 267 - type = ovl_dentry_to_fh(dentry, fid, max_len); 268 - 280 + bytes = ovl_dentry_to_fid(dentry, fid, bytes); 269 281 dput(dentry); 270 - return type; 282 + if (bytes <= 0) 283 + return FILEID_INVALID; 284 + 285 + *max_len = bytes >> 2; 286 + 287 + return OVL_FILEID_V1; 271 288 } 272 289 273 290 /* ··· 768 777 goto out; 769 778 } 770 779 780 + static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type) 781 + { 782 + struct ovl_fh *fh; 783 + 784 + /* If on-wire inner fid is aligned - nothing to do */ 785 + if (fh_type == OVL_FILEID_V1) 786 + return (struct ovl_fh *)fid; 787 + 788 + if (fh_type != OVL_FILEID_V0) 789 + return ERR_PTR(-EINVAL); 790 + 791 + fh = kzalloc(buflen, GFP_KERNEL); 792 + if (!fh) 793 + return ERR_PTR(-ENOMEM); 794 + 795 + /* Copy unaligned inner fh into aligned buffer */ 796 + memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET); 797 + return fh; 798 + } 799 + 771 800 static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, 772 801 int fh_len, int fh_type) 773 802 { 774 803 struct dentry *dentry = NULL; 775 - struct ovl_fh *fh = (struct ovl_fh *) fid; 804 + struct ovl_fh *fh = NULL; 776 805 int len = fh_len << 2; 777 806 unsigned int flags = 0; 778 807 int err; 779 808 780 - err = -EINVAL; 781 - if (fh_type != OVL_FILEID) 809 + fh = ovl_fid_to_fh(fid, len, fh_type); 810 + err = PTR_ERR(fh); 811 + if (IS_ERR(fh)) 782 812 goto out_err; 783 813 784 814 err = ovl_check_fh_len(fh, len); 785 815 if (err) 786 816 goto out_err; 787 817 788 - flags = fh->flags; 818 + flags = fh->fb.flags; 789 819 dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ? 790 820 ovl_upper_fh_to_d(sb, fh) : 791 821 ovl_lower_fh_to_d(sb, fh); ··· 814 802 if (IS_ERR(dentry) && err != -ESTALE) 815 803 goto out_err; 816 804 805 + out: 806 + /* We may have needed to re-align OVL_FILEID_V0 */ 807 + if (!IS_ERR_OR_NULL(fh) && fh != (void *)fid) 808 + kfree(fh); 809 + 817 810 return dentry; 818 811 819 812 out_err: 820 813 pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n", 821 - len, fh_type, flags, err); 822 - return ERR_PTR(err); 814 + fh_len, fh_type, flags, err); 815 + dentry = ERR_PTR(err); 816 + goto out; 823 817 } 824 818 825 819 static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid,
+22 -22
fs/overlayfs/namei.c
··· 84 84 * Return -ENODATA for "origin unknown". 85 85 * Return <0 for an invalid file handle. 86 86 */ 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) 88 88 { 89 - if (fh_len < sizeof(struct ovl_fh) || fh_len < fh->len) 89 + if (fb_len < sizeof(struct ovl_fb) || fb_len < fb->len) 90 90 return -EINVAL; 91 91 92 - if (fh->magic != OVL_FH_MAGIC) 92 + if (fb->magic != OVL_FH_MAGIC) 93 93 return -EINVAL; 94 94 95 95 /* 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) 97 97 return -ENODATA; 98 98 99 99 /* 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) 102 102 return -ENODATA; 103 103 104 104 return 0; ··· 119 119 if (res == 0) 120 120 return NULL; 121 121 122 - fh = kzalloc(res, GFP_KERNEL); 122 + fh = kzalloc(res + OVL_FH_WIRE_OFFSET, GFP_KERNEL); 123 123 if (!fh) 124 124 return ERR_PTR(-ENOMEM); 125 125 126 - res = vfs_getxattr(dentry, name, fh, res); 126 + res = vfs_getxattr(dentry, name, fh->buf, res); 127 127 if (res < 0) 128 128 goto fail; 129 129 130 - err = ovl_check_fh_len(fh, res); 130 + err = ovl_check_fb_len(&fh->fb, res); 131 131 if (err < 0) { 132 132 if (err == -ENODATA) 133 133 goto out; ··· 158 158 * Make sure that the stored uuid matches the uuid of the lower 159 159 * layer where file handle will be decoded. 160 160 */ 161 - if (!uuid_equal(&fh->uuid, &mnt->mnt_sb->s_uuid)) 161 + if (!uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid)) 162 162 return NULL; 163 163 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, 167 167 connected ? ovl_acceptable : NULL, mnt); 168 168 if (IS_ERR(real)) { 169 169 /* ··· 173 173 * index entries correctly. 174 174 */ 175 175 if (real == ERR_PTR(-ESTALE) && 176 - !(fh->flags & OVL_FH_FLAG_PATH_UPPER)) 176 + !(fh->fb.flags & OVL_FH_FLAG_PATH_UPPER)) 177 177 real = NULL; 178 178 return real; 179 179 } ··· 410 410 if (IS_ERR(ofh)) 411 411 return PTR_ERR(ofh); 412 412 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)) 414 414 err = -ESTALE; 415 415 416 416 kfree(ofh); ··· 441 441 442 442 err = ovl_verify_fh(dentry, name, fh); 443 443 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); 445 445 if (err) 446 446 goto fail; 447 447 ··· 515 515 goto fail; 516 516 517 517 err = -EINVAL; 518 - if (index->d_name.len < sizeof(struct ovl_fh)*2) 518 + if (index->d_name.len < sizeof(struct ovl_fb)*2) 519 519 goto fail; 520 520 521 521 err = -ENOMEM; 522 522 len = index->d_name.len / 2; 523 - fh = kzalloc(len, GFP_KERNEL); 523 + fh = kzalloc(len + OVL_FH_WIRE_OFFSET, GFP_KERNEL); 524 524 if (!fh) 525 525 goto fail; 526 526 527 527 err = -EINVAL; 528 - if (hex2bin((u8 *)fh, index->d_name.name, len)) 528 + if (hex2bin(fh->buf, index->d_name.name, len)) 529 529 goto fail; 530 530 531 - err = ovl_check_fh_len(fh, len); 531 + err = ovl_check_fb_len(&fh->fb, len); 532 532 if (err) 533 533 goto fail; 534 534 ··· 607 607 { 608 608 char *n, *s; 609 609 610 - n = kcalloc(fh->len, 2, GFP_KERNEL); 610 + n = kcalloc(fh->fb.len, 2, GFP_KERNEL); 611 611 if (!n) 612 612 return -ENOMEM; 613 613 614 - s = bin2hex(n, fh, fh->len); 614 + s = bin2hex(n, fh->buf, fh->fb.len); 615 615 *name = (struct qstr) QSTR_INIT(n, s - n); 616 616 617 617 return 0;
+28 -6
fs/overlayfs/overlayfs.h
··· 71 71 #error Endianness not defined 72 72 #endif 73 73 74 - /* The type returned by overlay exportfs ops when encoding an ovl_fh handle */ 75 - #define OVL_FILEID 0xfb 74 + /* The type used to be returned by overlay exportfs for misaligned fid */ 75 + #define OVL_FILEID_V0 0xfb 76 + /* The type returned by overlay exportfs for 32bit aligned fid */ 77 + #define OVL_FILEID_V1 0xf8 76 78 77 - /* On-disk and in-memeory format for redirect by file handle */ 78 - struct ovl_fh { 79 + /* On-disk format for "origin" file handle */ 80 + struct ovl_fb { 79 81 u8 version; /* 0 */ 80 82 u8 magic; /* 0xfb */ 81 83 u8 len; /* size of this header + size of fid */ 82 84 u8 flags; /* OVL_FH_FLAG_* */ 83 85 u8 type; /* fid_type of fid */ 84 86 uuid_t uuid; /* uuid of filesystem */ 85 - u8 fid[0]; /* file identifier */ 87 + u32 fid[0]; /* file identifier should be 32bit aligned in-memory */ 86 88 } __packed; 89 + 90 + /* In-memory and on-wire format for overlay file handle */ 91 + struct ovl_fh { 92 + u8 padding[3]; /* make sure fb.fid is 32bit aligned */ 93 + union { 94 + struct ovl_fb fb; 95 + u8 buf[0]; 96 + }; 97 + } __packed; 98 + 99 + #define OVL_FH_WIRE_OFFSET offsetof(struct ovl_fh, fb) 100 + #define OVL_FH_LEN(fh) (OVL_FH_WIRE_OFFSET + (fh)->fb.len) 101 + #define OVL_FH_FID_OFFSET (OVL_FH_WIRE_OFFSET + \ 102 + offsetof(struct ovl_fb, fid)) 87 103 88 104 static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry) 89 105 { ··· 318 302 319 303 320 304 /* namei.c */ 321 - int ovl_check_fh_len(struct ovl_fh *fh, int fh_len); 305 + int ovl_check_fb_len(struct ovl_fb *fb, int fb_len); 306 + 307 + static inline int ovl_check_fh_len(struct ovl_fh *fh, int fh_len) 308 + { 309 + return ovl_check_fb_len(&fh->fb, fh_len - OVL_FH_WIRE_OFFSET); 310 + } 311 + 322 312 struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt, 323 313 bool connected); 324 314 int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,