-
Notifications
You must be signed in to change notification settings - Fork 188
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
Fixes: CFE-3982 do not kill unrelated process #4957
Conversation
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.
Also please read our contributing guidelines and try to keep the same coding style as the surrounding code.
libpromises/locks.c
Outdated
@@ -903,15 +927,23 @@ CfLock AcquireLock(EvalContext *ctx, const char *operand, const char *host, | |||
"Lock expired after %jd/%u minutes: %s", | |||
(intmax_t) elapsedtime, expireafter, cflock); | |||
|
|||
if (KillLockHolder(cflock)) | |||
if (is_cfengine_process(cflock.pid)) |
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'd prefer a function that returns the path/name to/of the executable when given a PID and using that function here. A the function should go to the file where we do process handling and process table parsing. Also, it should use the process info parsing code from there instead of reading /proc
directly because /proc
is not a portable thing available everywhere.
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 don't see any function for reading information for a process given its pid in ./libpromises/processes_select.c
If this is not what you call "the file where we do process handling" please point me to the correct one.
About the coding style, is there anything else than the function name that you want to point me to ? |
7bb5648
to
396cf6a
Compare
@peckpeck Some things I see at first glance:
|
libpromises/locks.c
Outdated
char* procfile = xcalloc(1024, sizeof(char)); | ||
char* cmd = xcalloc(1024, sizeof(char)); | ||
if (cmd && procfile){ | ||
sprintf(procfile, "/proc/%d/cmdline", pid); |
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 emits an error during compilation:
locks.c:565:9: error: 'sprintf' is deprecated
[-Werror,-Wdeprecated-declarations]
sprintf(procfile, "/proc/%d/cmdline", pid);
^
./../libntech/libutils/deprecated.h:42:5: note: 'sprintf' has been explicitly
marked deprecated here
FUNC_DEPRECATED("Try snprintf() or xsnprintf() or xasprintf()");
^
./../libntech/libutils/compiler.h:44:49: note: expanded from macro
'FUNC_DEPRECATED'
# define FUNC_DEPRECATED(msg) __attribute__((deprecated))
^
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.
A bit more work needed.
libpromises/locks.c
Outdated
// There is no /proc on windows | ||
#ifndef _WIN32 | ||
char* procfile = xcalloc(1024, sizeof(char)); | ||
char* cmd = xcalloc(1024, sizeof(char)); |
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.
Either free()
these variables or, better, use arrays like char procfile[PATH_MAX]
and similar.
libpromises/locks.c
Outdated
#ifndef _WIN32 | ||
char* procfile = xcalloc(1024, sizeof(char)); | ||
char* cmd = xcalloc(1024, sizeof(char)); | ||
if (cmd && procfile){ |
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.
No need to check these, xcalloc()
kills the process in case of ENOMEM
.
libpromises/locks.c
Outdated
@@ -587,6 +616,12 @@ static bool KillLockHolder(const char *lock) | |||
|
|||
CloseLock(dbp); | |||
|
|||
if (!IsCfengineProcess(lock_data.pid)) { | |||
Log(LOG_LEVEL_INFO, | |||
"Lock holder disappeared"); |
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 log message should be a bit more verbose and logged as VERBOSE
.
sorry for the delay |
@vpodzime any news on this ? |
Hi @peckpeck ! as far as i know, Windows is not the only platform without the ClearProcessTable(); /* Make sure old process table is not cached */
Item *procs = NULL;
if (LoadProcessTable())
{
ProcessSelect ps = PROCESS_SELECT_INIT;
ps.max_pid = ps.min_pid = lock_data.pid;
procs = SelectProcesses("cf-.*", &ps, true);
}
if (procs == NULL)
{
/* Process select returned nothing, it must be an unrelated process */
return false;
}
DeleteItemList(procs);
return true; Not sure if this would work, but feel free to give it a try. Otherwise you could maybe guard it with the |
libpromises/locks.c
Outdated
@@ -554,6 +554,33 @@ static void PromiseTypeString(char *dst, size_t dst_size, const Promise *pp) | |||
} | |||
} | |||
|
|||
// returns true if pid points to a cfengine process | |||
static bool IsCfengineProcess(const int pid) |
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.
const
has no meaning here, and the type should be pid_t
not int
.
libpromises/locks.c
Outdated
FILE *f = fopen(procfile, "r"); | ||
if (f != NULL){ | ||
size_t size; | ||
size = fread(cmd, sizeof(char), PATH_MAX, f); |
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.
Please check FullRead()
in libntech/libutils
libpromises/locks.c
Outdated
fclose(f); | ||
// cmd contains the process command path | ||
char *name = basename(cmd); | ||
return (strncmp("cf-", name, 3) == 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.
Please check StringStartsWith()
in libntech/libutils
libpromises/locks.c
Outdated
} | ||
fclose(f); | ||
// cmd contains the process command path | ||
char *name = basename(cmd); |
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.
If size
is 0
then cmd
is uninitialized here.
} | ||
#endif | ||
// assume true if we don't know | ||
return true; |
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.
Wouldn't it be safer to assume the opposite?
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.
we don't know means use the old behaviour on other platforms
if (!IsCfengineProcess(lock_data.pid)) { | ||
Log(LOG_LEVEL_VERBOSE, | ||
"Lock holder with pid %d was replaced by a non cfengine process, do not try to kill it!, ", lock_data.pid); | ||
return true; |
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.
So the function returns true
here in this case, but it doesn't really kill the lock holder. That can be a source of issues.
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 still applicable.
… unrelated process
PR updated, sorry for the delay |
{ | ||
char procfile[PATH_MAX]; | ||
char cmd[PATH_MAX]; // we don't need the full ARG_MAX | ||
snprintf(procfile, PATH_MAX, "/proc/%d/cmdline", pid); |
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.
pid_t
doesn't have to be int
and this can easily fail to compile in such a case because of the format (%d
) and type (pid_t
) mismatch. We usually use a trick with uintmax_t
for things like this.
// this will just return null on platform where /proc doesn't exist and return true as before | ||
if (f != NULL){ | ||
size_t size; | ||
size = FullRead(f, cmd, PATH_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.
size_t size = FullRead(f, cmd, PATH_MAX);
if (!IsCfengineProcess(lock_data.pid)) { | ||
Log(LOG_LEVEL_VERBOSE, | ||
"Lock holder with pid %d was replaced by a non cfengine process, do not try to kill it!, ", lock_data.pid); | ||
return true; |
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 still applicable.
@peckpeck I took your code as a base for my work on the related ticket. Thank you for your contribution! |
Pull request to fix https://tracker.mender.io/browse/CFE-3982