php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login

Patch fmp_scoreboard_proc_oob_v1.patch for FPM related Bug #81026

Patch version 2021-05-31 13:32 UTC

Return to Bug #81026 | Download this patch
Patch Revisions:

Developer: bukka@php.net

From 61f3c6e4461975f3b24b96a998c7ce789534d0f5 Mon Sep 17 00:00:00 2001
From: Jakub Zelenka <bukka@php.net>
Date: Mon, 31 May 2021 14:26:09 +0100
Subject: [PATCH] Fix bug #81026 (PHP-FPM oob R/W in root process leading to
 privilege escalation)

---
 sapi/fpm/fpm/fpm_request.c    |  6 +++---
 sapi/fpm/fpm/fpm_scoreboard.c | 35 +++++++++++++++++++++++++++++++++++
 sapi/fpm/fpm/fpm_scoreboard.h |  2 ++
 3 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/sapi/fpm/fpm/fpm_request.c b/sapi/fpm/fpm/fpm_request.c
index 83401f1553..540949b026 100644
--- a/sapi/fpm/fpm/fpm_request.c
+++ b/sapi/fpm/fpm/fpm_request.c
@@ -227,7 +227,7 @@ void fpm_request_check_timed_out(struct fpm_child_s *child, struct timeval *now,
 {
 	struct fpm_scoreboard_proc_s proc, *proc_p;
 
-	proc_p = fpm_scoreboard_proc_acquire(child->wp->scoreboard, child->scoreboard_i, 1);
+	proc_p = fpm_scoreboard_proc_acquire_from_child(child, 1);
 	if (!proc_p) {
 		zlog(ZLOG_WARNING, "failed to acquire scoreboard");
 		return;
@@ -287,7 +287,7 @@ int fpm_request_is_idle(struct fpm_child_s *child) /* {{{ */
 	struct fpm_scoreboard_proc_s *proc;
 
 	/* no need in atomicity here */
-	proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i);
+	proc = fpm_scoreboard_proc_get_from_child(child);
 	if (!proc) {
 		return 0;
 	}
@@ -302,7 +302,7 @@ int fpm_request_last_activity(struct fpm_child_s *child, struct timeval *tv) /*
 
 	if (!tv) return -1;
 
-	proc = fpm_scoreboard_proc_get(child->wp->scoreboard, child->scoreboard_i);
+	proc = fpm_scoreboard_proc_get_from_child(child);
 	if (!proc) {
 		return -1;
 	}
diff --git a/sapi/fpm/fpm/fpm_scoreboard.c b/sapi/fpm/fpm/fpm_scoreboard.c
index 328f999f0c..b26e503f9c 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.c
+++ b/sapi/fpm/fpm/fpm_scoreboard.c
@@ -6,6 +6,7 @@
 #include <time.h>
 
 #include "fpm_config.h"
+#include "fpm_children.h"
 #include "fpm_scoreboard.h"
 #include "fpm_shm.h"
 #include "fpm_sockets.h"
@@ -184,6 +185,23 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *s
 }
 /* }}} */
 
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child) /* {{{*/
+{
+	struct fpm_worker_pool_s *wp = child->wp;
+	struct fpm_scoreboard_proc_s *proc = fpm_scoreboard_proc_get(wp->scoreboard, child->scoreboard_i);
+	ptrdiff_t proc_start = (uintptr_t) wp->scoreboard + sizeof(struct fpm_scoreboard_s);
+	ptrdiff_t proc_end = sizeof(struct fpm_scoreboard_s) + (wp->config->pm_max_children - 1) * sizeof(struct fpm_scoreboard_proc_s *);
+	uintptr_t proc_position = (uintptr_t) proc;
+
+	if (proc_position < proc_start || proc_position > proc_end) {
+		zlog(ZLOG_WARNING, "failed to get proc from the child scoreboard because the proc pointer is invalid");
+		return NULL;
+	}
+
+	return proc;
+}
+/* }}} */
+
 struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */
 {
 	struct fpm_scoreboard_s *s;
@@ -225,6 +243,23 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_
 }
 /* }}} */
 
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire_from_child(struct fpm_child_s *child, int nohang) /* {{{ */
+{
+	struct fpm_scoreboard_proc_s *proc;
+
+	proc = fpm_scoreboard_proc_get_from_child(child);
+	if (!proc) {
+		return NULL;
+	}
+
+	if (!fpm_spinlock(&proc->lock, nohang)) {
+		return NULL;
+	}
+
+	return proc;
+}
+/* }}} */
+
 void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc) /* {{{ */
 {
 	if (!proc) {
diff --git a/sapi/fpm/fpm/fpm_scoreboard.h b/sapi/fpm/fpm/fpm_scoreboard.h
index 1fecde1d0f..ff7ed1806d 100644
--- a/sapi/fpm/fpm/fpm_scoreboard.h
+++ b/sapi/fpm/fpm/fpm_scoreboard.h
@@ -72,10 +72,12 @@ int fpm_scoreboard_init_child(struct fpm_worker_pool_s *wp);
 void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int slow_rq, int action, struct fpm_scoreboard_s *scoreboard);
 struct fpm_scoreboard_s *fpm_scoreboard_get();
 struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index);
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_child_s *child);
 
 struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang);
 void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard);
 struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s *scoreboard, int child_index, int nohang);
+struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire_from_child(struct fpm_child_s *child, int nohang);
 void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc);
 
 void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard);
-- 
2.25.1

 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Fri Dec 02 05:05:54 2022 UTC