mirror of
https://github.com/ceph/ceph
synced 2025-01-03 01:22:53 +00:00
ceph-fuse: return EINVAL if get invalid fino instead of assert
All the snap ids of the finos returned to libfuse from libcephfs will be recorded in the map of 'stag_snap_map', and will never be erased before unmounting. So if libfuse passes invalid fino the ceph-fuse should return EINVAL errno instead of crash itself. Fixes: https://tracker.ceph.com/issues/54653 Signed-off-by: Xiubo Li <xiubli@redhat.com>
This commit is contained in:
parent
2349083a9d
commit
a6e83d8dec
@ -351,7 +351,9 @@ static void fuse_ll_forget(fuse_req_t req, fuse_ino_t ino,
|
||||
#endif
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
cfuse->client->ll_forget(cfuse->iget(ino), nlookup+1);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (in)
|
||||
cfuse->client->ll_forget(in, nlookup+1);
|
||||
fuse_reply_none(req);
|
||||
}
|
||||
|
||||
@ -360,11 +362,16 @@ static void fuse_ll_getattr(fuse_req_t req, fuse_ino_t ino,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
struct stat stbuf;
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
|
||||
(void) fi; // XXX
|
||||
|
||||
if (cfuse->client->ll_getattr(in, &stbuf, perms)
|
||||
@ -383,8 +390,13 @@ static void fuse_ll_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int mask = 0;
|
||||
@ -420,8 +432,13 @@ static void fuse_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_setxattr(in, name, value, size, flags, perms);
|
||||
@ -434,9 +451,14 @@ static void fuse_ll_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
char buf[size];
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_listxattr(in, buf, size, perms);
|
||||
@ -459,9 +481,14 @@ static void fuse_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
char buf[size];
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_getxattr(in, name, buf, size, perms);
|
||||
@ -480,8 +507,13 @@ static void fuse_ll_removexattr(fuse_req_t req, fuse_ino_t ino,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_removexattr(in, name, perms);
|
||||
@ -495,10 +527,14 @@ static void fuse_ll_opendir(fuse_req_t req, fuse_ino_t ino,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
void *dirp;
|
||||
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
void *dirp;
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_opendir(in, fi->flags, (dir_result_t **)&dirp,
|
||||
@ -517,11 +553,15 @@ static void fuse_ll_readlink(fuse_req_t req, fuse_ino_t ino)
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
char buf[PATH_MAX + 1]; // leave room for a null terminator
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
get_fuse_groups(perms, req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
int r = cfuse->client->ll_readlink(in, buf, sizeof(buf) - 1, perms);
|
||||
if (r >= 0) {
|
||||
buf[r] = '\0';
|
||||
@ -538,9 +578,14 @@ static void fuse_ll_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *i2, *i1 = cfuse->iget(parent);
|
||||
struct fuse_entry_param fe;
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *i2, *i1 = cfuse->iget(parent);
|
||||
if (!i1) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
memset(&fe, 0, sizeof(fe));
|
||||
@ -600,6 +645,11 @@ static void fuse_ll_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
#endif
|
||||
|
||||
i1 = cfuse->iget(parent);
|
||||
if (!i1) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
int r = cfuse->client->ll_mkdir(i1, name, mode, &fe.attr, &i2, perm);
|
||||
if (r == 0) {
|
||||
fe.ino = cfuse->make_fake_ino(fe.attr.st_ino, fe.attr.st_dev);
|
||||
@ -618,8 +668,13 @@ static void fuse_ll_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(parent);
|
||||
UserPerm perm(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(parent);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perm, req);
|
||||
|
||||
int r = cfuse->client->ll_unlink(in, name, perm);
|
||||
@ -632,8 +687,13 @@ static void fuse_ll_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(parent);
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(parent);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_rmdir(in, name, perms);
|
||||
@ -647,9 +707,14 @@ static void fuse_ll_symlink(fuse_req_t req, const char *existing,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *i2, *i1 = cfuse->iget(parent);
|
||||
struct fuse_entry_param fe;
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *i2, *i1 = cfuse->iget(parent);
|
||||
if (!i1) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
memset(&fe, 0, sizeof(fe));
|
||||
@ -677,9 +742,14 @@ static void fuse_ll_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
UserPerm perm(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(parent);
|
||||
Inode *nin = cfuse->iget(newparent);
|
||||
UserPerm perm(ctx->uid, ctx->gid);
|
||||
if (!in || !nin) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perm, req);
|
||||
|
||||
int r = cfuse->client->ll_rename(in, name, nin, newname, perm);
|
||||
@ -694,14 +764,18 @@ static void fuse_ll_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
struct fuse_entry_param fe;
|
||||
Inode *in = cfuse->iget(ino);
|
||||
Inode *nin = cfuse->iget(newparent);
|
||||
struct fuse_entry_param fe;
|
||||
if (!in || !nin) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&fe, 0, sizeof(fe));
|
||||
UserPerm perm(ctx->uid, ctx->gid);
|
||||
get_fuse_groups(perm, req);
|
||||
|
||||
|
||||
/*
|
||||
* Note that we could successfully link, but then fail the subsequent
|
||||
* getattr and return an error. Perhaps we should ignore getattr errors,
|
||||
@ -736,9 +810,14 @@ static void fuse_ll_open(fuse_req_t req, fuse_ino_t ino,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
Fh *fh = NULL;
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_open(in, fi->flags, &fh, perms);
|
||||
@ -930,10 +1009,14 @@ static void fuse_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
|
||||
|
||||
struct readdir_context rc;
|
||||
rc.req = req;
|
||||
rc.snap = cfuse->fino_snap(ino);
|
||||
if (rc.snap == CEPH_MAXSNAP) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
rc.buf = new char[size];
|
||||
rc.size = size;
|
||||
rc.pos = 0;
|
||||
rc.snap = cfuse->fino_snap(ino);
|
||||
|
||||
int r = cfuse->client->readdir_r_cb(dirp, fuse_ll_add_dirent, &rc);
|
||||
if (r == 0 || r == -CEPHFS_ENOSPC) /* ignore ENOSPC from our callback */
|
||||
@ -965,8 +1048,13 @@ static void fuse_ll_access(fuse_req_t req, fuse_ino_t ino, int mask)
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->inode_permission(in, perms, mask);
|
||||
@ -979,10 +1067,15 @@ static void fuse_ll_create(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
{
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
Inode *i1 = cfuse->iget(parent), *i2;
|
||||
struct fuse_entry_param fe;
|
||||
Fh *fh = NULL;
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *i1 = cfuse->iget(parent), *i2;
|
||||
if (!i1) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
memset(&fe, 0, sizeof(fe));
|
||||
@ -1015,9 +1108,14 @@ static void fuse_ll_statfs(fuse_req_t req, fuse_ino_t ino)
|
||||
{
|
||||
struct statvfs stbuf;
|
||||
CephFuse::Handle *cfuse = fuse_ll_req_prepare(req);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
const struct fuse_ctx *ctx = fuse_req_ctx(req);
|
||||
UserPerm perms(ctx->uid, ctx->gid);
|
||||
Inode *in = cfuse->iget(ino);
|
||||
if (!in) {
|
||||
fuse_reply_err(req, get_sys_errno(CEPHFS_EINVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
get_fuse_groups(perms, req);
|
||||
|
||||
int r = cfuse->client->ll_statfs(in, &stbuf, perms);
|
||||
@ -1534,7 +1632,8 @@ uint64_t CephFuse::Handle::fino_snap(uint64_t fino)
|
||||
} else {
|
||||
std::lock_guard l(stag_lock);
|
||||
uint64_t stag = FINO_STAG(fino);
|
||||
ceph_assert(stag_snap_map.count(stag));
|
||||
if (!stag_snap_map.count(stag))
|
||||
return CEPH_MAXSNAP;
|
||||
return stag_snap_map[stag];
|
||||
}
|
||||
}
|
||||
@ -1547,7 +1646,10 @@ Inode * CephFuse::Handle::iget(fuse_ino_t fino)
|
||||
if (client->use_faked_inos()) {
|
||||
return client->ll_get_inode((ino_t)fino);
|
||||
} else {
|
||||
vinodeno_t vino(FINO_INO(fino), fino_snap(fino));
|
||||
uint64_t snap = fino_snap(fino);
|
||||
if (snap == CEPH_MAXSNAP)
|
||||
return NULL;
|
||||
vinodeno_t vino(FINO_INO(fino), snap);
|
||||
return client->ll_get_inode(vino);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user