summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFrank Schaefer <kelledin@gmail.com>2018-10-04 16:06:16 -0500
committerLennart Poettering <lennart@poettering.net>2018-10-05 21:40:41 +0200
commit14ee72b7d8de34a6b02767b865c3c49ceef2ed84 (patch)
treefa685caf8358d28b8106ee0fcfc076ce65cb24b0 /src
parentad191df836b79b74ac300229536a512d308cdbf1 (diff)
downloadsystemd-14ee72b7d8de34a6b02767b865c3c49ceef2ed84.tar.gz
* hack around deficiencies in prctl() PR_SET_MM_*
Diffstat (limited to 'src')
-rw-r--r--src/basic/process-util.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 1098cf453f..a02ceb79e5 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -336,15 +336,33 @@ int rename_process(const char name[]) {
/* Now, let's tell the kernel about this new memory */
if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
- log_debug_errno(errno, "PR_SET_MM_ARG_START failed, proceeding without: %m");
- (void) munmap(nn, nn_size);
- goto use_saved_argv;
- }
+ /* HACK: prctl() API is kind of dumb on this point. The existing end address may already be
+ * below the desired start address, in which case the kernel may have kicked this back due
+ * to a range-check failure (see linux/kernel/sys.c:validate_prctl_map() to see this in
+ * action). The proper solution would be to have a prctl() API that could set both start+end
+ * simultaneously, or at least let us query the existing address to anticipate this condition
+ * and respond accordingly. For now, we can only guess at the cause of this failure and try
+ * a workaround--which will briefly expand the arg space to something potentially huge before
+ * resizing it to what we want. */
+ log_debug_errno(errno, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m");
+
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) {
+ log_debug_errno(errno, "PR_SET_MM_ARG_END hack failed, proceeding without: %m");
+ (void) munmap(nn, nn_size);
+ goto use_saved_argv;
+ }
- /* And update the end pointer to the new end, too. If this fails, we don't really know what to do, it's
- * pretty unlikely that we can rollback, hence we'll just accept the failure, and continue. */
- if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
- log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
+ log_debug_errno(errno, "PR_SET_MM_ARG_START still failed, proceeding without: %m");
+ goto use_saved_argv;
+ }
+ } else {
+ /* And update the end pointer to the new end, too. If this fails, we don't really know what
+ * to do, it's pretty unlikely that we can rollback, hence we'll just accept the failure,
+ * and continue. */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
+ log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ }
if (mm)
(void) munmap(mm, mm_size);