-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lxcfs: handle NULL path in lxcfs_releasedir/lxcfs_release #577
Conversation
This is the method I've approached this problem with we discussed yesterday. The release/releasedir code now primarily uses this mechanism to release files back to memory. It spits an error in the event it doesn't know what to do. Flush is a noop so no work was required. Might be a nice-to-have to extend the same checks into other callbacks as its a little quicker than a strcmp(), but that isn't the concern of this fix. This still needs testing properly somewhere, I'll roll it out onto my own test systems tomorrow and check its not blowing up massively or leaking memory somehow. |
afc9a6d
to
27f2cfd
Compare
src/lxcfs.c
Outdated
@@ -1032,6 +1059,7 @@ static void *lxcfs_init(struct fuse_conn_info *conn) | |||
|
|||
#if HAVE_FUSE3 | |||
cfg->direct_io = 1; | |||
cfg->nullpath_ok = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it makes no sense to add this here, as we discussed before, cfg
is always initialized by zeroes. If you want to add this just to make the code more explicit, then we need to explicitly initialize all other options from cfg
structure, IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dropped this change, agree its unnecessary and implies a cause where none exists.
src/lxcfs.c
Outdated
up_users(); | ||
ret = do_sys_release(path, fi); | ||
down_users(); | ||
return ret; | ||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra spaces after ;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Thanks. Whilst I'm fairly proficient in C my git-etiquette is not unfortunately that great! I'll try to clean up my commits and remove the bits that are unnecessary. As you can tell I took an indirect approach at first (to preserve the I felt going to the effort of doing type-checks should at least potentially result in a slightly faster overall runtime experience. |
src/bindings.h
Outdated
@@ -31,6 +31,7 @@ | |||
#define LXCFS_NUMSTRLEN64 21 | |||
|
|||
enum lxcfs_virt_t { | |||
LXC_TYPE_START, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that it's safe to change the start value of this enum. Cause we support live lxc library reload after this change LXC_TYPE_CGDIR
becomes 1
instead of 0
. These values getting placed in the memory and kept between library reloads. So, let's not change this enum declaration at all. You can just place a comment inside enum definition which attracts developer attention to the macros LXCFS_TYPE_CGROUP
, LXCFS_TYPE_PROC
, LXCFS_TYPE_SYS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree here, totally didn't think of the case of reloading.
Generally we restart the service and rebind the mounts in the containers - there is a neat way to do this without restarting the containers, I'm still developing the software but am happy to share it later down the line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree here, totally didn't think of the case of reloading.
Generally we restart the service and rebind the mounts in the containers - there is a neat way to do this without restarting the containers, I'm still developing the software but am happy to share it later down the line.
great! I'm working on a way to recover the lxcfs from crashes another way. With preserving fuse connection between userspace and kernel. It's also not ready yet :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that it's safe to change the start value of this enum. Cause we support live lxc library reload after this change
LXC_TYPE_CGDIR
becomes1
instead of0
. These values getting placed in the memory and kept between library reloads. So, let's not change this enum declaration at all.
I think we should explictly number it though. That's what I do nowadays for all enums I add becuase it eliminates a whole bunch of subtle bugs if you force the numbering.
src/bindings.h
Outdated
#define LXCFS_TYPE_CGROUP(type) (type >= LXC_TYPE_CGDIR && type <= LXC_TYPE_CGFILE) | ||
#define LXCFS_TYPE_PROC(type) (type >= LXC_TYPE_PROC_MEMINFO && type <= LXC_TYPE_PROC_SLABINFO) | ||
#define LXCFS_TYPE_SYS(type) (type >= LXC_TYPE_SYS && type <= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE) | ||
#define LXCFS_TYPE_OK(type) (type >= LXC_TYPE_START && type <= LXC_TYPE_END) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define LXCFS_TYPE_OK(type) (type > LXC_TYPE_START && type < LXC_TYPE_END)
, correct?
But anyway, I think we don't need to have this separate values LXC_TYPE_START
and LXC_TYPE_END
.
#define LXCFS_TYPE_OK(type) (type >= LXC_TYPE_CGDIR && type <= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE)
looks sufficient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw and fixed this one earlier (the range checks being incorrect) might be best practice to keep the LXC_TYPE_END, it prevents needing to adjust LXCFS_TYPE_OK macro later on in the future and its pretty obvious to anyone going forwards not to add to the end of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree with you :)
src/lxcfs.c
Outdated
if (path && strcmp(path, "/") == 0) | ||
return 0; | ||
|
||
lxcfs_error("lxcfs_releasedir() unknown file type: path=%s, type=%d\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need extra \n
as lxcfs_error
prints a new line automatically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit.
src/lxcfs.c
Outdated
} | ||
|
||
lxcfs_error("lxcfs_release() unknown file type: path=%s, type=%d\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\n
is excess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And again.
0b749c9
to
04277d9
Compare
I've made the changes and cleaned up the commit history somewhat. I'll test the deployment out and see how it fares today. |
src/bindings.h
Outdated
#define LXCFS_TYPE_CGROUP(type) (type >= LXC_TYPE_CGDIR && type <= LXC_TYPE_CGFILE) | ||
#define LXCFS_TYPE_PROC(type) (type >= LXC_TYPE_PROC_MEMINFO && type <= LXC_TYPE_PROC_SLABINFO) | ||
#define LXCFS_TYPE_SYS(type) (type >= LXC_TYPE_SYS && type <= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE) | ||
#define LXCFS_TYPE_OK(type) (type > LXC_TYPE_CGDIR && type < LXC_TYPE_END) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define LXCFS_TYPE_OK(type) (type >= LXC_TYPE_CGDIR && type < LXC_TYPE_END)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spotted and fixed myself already. Thanks.
src/lxcfs.c
Outdated
up_users(); | ||
ret = do_sys_release(path, fi); | ||
down_users(); | ||
return ret; | ||
} | ||
|
||
lxcfs_error("lxcfs_release() unknown file type: path=%s, type=%d", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lxcfs_error
already prints the function name from where it's called ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
src/lxcfs.c
Outdated
if (path && strcmp(path, "/") == 0) | ||
return 0; | ||
|
||
lxcfs_error("lxcfs_releasedir() unknown file type: path=%s, type=%d", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function name is already printed inside the lxcfs_error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
04277d9
to
4e09af4
Compare
Thanks @deleriux for working on that. I think it's also important to mention in the commit message and PR description that you are trying to fix SEGV with this patch :) Because right now, at first glance, it looks just like an improvement. But in fact, this is a bugfix. Let's rename PR too to reflect the reason why you are doing all of that :) |
Let's call other reviewers :) cc @tych0 |
6bc0e36
to
478e579
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the first line in the commit message should be like lxcfs: handle NULL path in lxcfs_releasedir/lxcfs_release
.
And please rename PR accordingly.
|
478e579
to
d8a7f91
Compare
Fixed the latest minor niggle. There is no need to check for this in |
src/lxcfs.c
Outdated
up_users(); | ||
ret = do_sys_releasedir(path, fi); | ||
down_users(); | ||
return ret; | ||
} | ||
|
||
if (LXCFS_TYPE_PROC(type)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need this check at all then. Cause for /proc
directory we don't fill fi
with any info in lxcfs_opendir
:
static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
{
int ret;
if (strcmp(path, "/") == 0)
return 0; // don't touch "fi"
if (strncmp(path, "/cgroup", 7) == 0) {
up_users();
ret = do_cg_opendir(path, fi); // << fills "fi" with something
down_users();
return ret;
}
if (strcmp(path, "/proc") == 0)
return 0; // don't touch "fi"
if (strncmp(path, "/sys", 4) == 0) {
up_users();
ret = do_sys_opendir(path, fi); // << fills "fi" with something
down_users();
return ret;
}
return -ENOENT;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent point. I should try to extend my head-logic a bit further ;). Updated.
d8a7f91
to
1ca4c46
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks!
And yes, one small suggestion. We can replace |
1ca4c46
to
7791802
Compare
Fixed to include the pointer address. I assume you really only care if its a 0 or close to it though... |
in fact yes. But if we will have a coredump in a particular case this address may help to debug. |
src/lxcfs.c
Outdated
up_users(); | ||
ret = do_sys_release(path, fi); | ||
down_users(); | ||
return ret; | ||
} | ||
|
||
lxcfs_error("unknown file type: path=%s, type=%d, type=%" PRIu64, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type=
to fi->fh=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oof.. thanks.
7791802
to
4979d6b
Compare
src/bindings.h
Outdated
@@ -67,8 +67,15 @@ enum lxcfs_virt_t { | |||
|
|||
LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE, | |||
#define LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE_PATH "/sys/devices/system/cpu/online" | |||
LXC_TYPE_END, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Traditionally, we've suffixed things like that with MAX
so I'd prefer LXC_TYPE_MAX
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed style from END to MAX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the requested comment also.
src/bindings.h
Outdated
#define LXCFS_TYPE_CGROUP(type) (type >= LXC_TYPE_CGDIR && type <= LXC_TYPE_CGFILE) | ||
#define LXCFS_TYPE_PROC(type) (type >= LXC_TYPE_PROC_MEMINFO && type <= LXC_TYPE_PROC_SLABINFO) | ||
#define LXCFS_TYPE_SYS(type) (type >= LXC_TYPE_SYS && type <= LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE) | ||
#define LXCFS_TYPE_OK(type) (type >= LXC_TYPE_CGDIR && type < LXC_TYPE_END) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is error prone as it depends on ordering in the enum. The ordering isn't enforced however. So there needs to be at least a comment on top of the enum explaining this. Also, we should explicitly number the enum. This also makes it harder to accidently break ordering requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that too, after we extend this enum with new possible values it will be needed to fix these macros like that:
#define LXCFS_TYPE_PROC(type) ((type >= LXC_TYPE_PROC_MEMINFO && type <= LXC_TYPE_PROC_SLABINFO) || type == LXC_TYPE_PROC_SOMETHING)
. Not so fancy, but...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, right now it's also not correct to add new values in between the enum. Cause we can perform reloading of liblxcfs
in between open
and close
of the file descriptor. Then because enum values shift, some condition checks may become incorrect. For example https://github.com/lxc/lxcfs/blob/master/src/sysfs_fuse.c#L372
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also did give this some thought beforehand. I thought some ways to do this could be..
- re-order the enum numbering explicitly granting space for future files. IE
enum lxcfs_virt_t {
LXC_TYPE_CGROUP_BASE = 0x00000,
...
LXC_TYPE_CGROUP_MAX,
LXC_TYPE_PROC_BASE = 0x10000,
...
LXC_TYPE_PROC_MAX,
LXC_TYPE_SYS_BASE = 0x20000,
...
LXC_TYPE_SYS_MAX,
}
- extend
file_info
to include a 'class' parameter, ditch the defines, removefile_info_type
in favour offile_info_class
.
For 2. Obviously you'd basically have to go through every file type already configured and put them in the right class, but at that point ordering no longer matters as you're relying on a different set of metadata to work out what goes where..
Also you could hijack the unused file_info.buf
pointer and change it to a unsigned char abi_version[sizeof(char *)]
that you could check going forwards. This would let you conditionally and smartly extend the runtime ABI yet be able to deal with previous versions of the ABI changing.
This is of course assuming *buf is zeroed on initialization currently (version 0 implictly).
This also felt like a whole load of architectural work for what is essentially a bugfix!
For 1. Its much simpler to implement and prevents in the future having to make a headache again. That however breaks the ABI in a manner which would not survive a reload so didn't imagine that would get any traction..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just also thought you could actually do LXC_TYPE_BASE = 0x00000
, copy all the file types as-is, then have new namespaces for each type and defines for which you use going forwards. That gives you both the means to maintain reload
compatibility by checking if the type is in a 'base' namespace or the given correct namespace.
Its a little janky but probably simpler than doing some abi extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now just leaving a comment is fine. We just want to fix the immediate bug. Reworking it to something better should be a separate step. But feel free to follow this up with a series.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the requested comment above the enum indicating only appending to the bottom (above LXC_TYPE_MAX).
Can you talk about what case the path would be null? At first glance this seems like a weird call for libfuse to make. |
|
So I guess it's really the kernel, not libfuse, that's triggering these, given that they're just passthroughs from libfuse? I still don't understand why, but maybe it's a mystery for the ages... |
As far as I know, the kernel doesn't know anything about the path, or, speaking more correctly, the kernel gives the path from [1] https://github.com/torvalds/linux/blob/764822972d64e7f3e6792278ecc7a3b3c81087cd/fs/fuse/dir.c#L190 |
Yeah, that's what I was wondering about. Makes sense, thanks. Patch LGTM. |
4979d6b
to
f4153a9
Compare
Implement a file_info_type function. Create a series of defines for the file type Inspect the file type for each file handler and perform the relevant release code to free any memory. If the type cannot be determined, print an error and return -EINVAL. This should also be slightly faster than a strcmp() but its not likely that measurable. This code could be used elsewhere in the process to reduce the strcmp requirements, but for now just handle the release/releasedir case. This fixes SEGV in lxcfs_relase/releasedir when path=NULL but invoked a strcmp(). Signed-off-by: Matthew Ife <matthewi@mustardsystems.com>
f4153a9
to
cf02ccb
Compare
This fixes SEGV in
lxcfs_release/releasedir
when path=NULL.Avoid the use of paths doing the release and prefer to inspect the type
file_info
struct.Print an error in the case no valid type can be detected.