Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ae90ffa

Browse files
committed
Have pg_terminate/cancel_backend not ERROR on non-existent processes
This worked fine for superusers, but not for ordinary users trying to cancel their own processes. Tweak the order the checks are done in so that we correctly return SIGNAL_BACKEND_ERROR (which current callers know to ignore without erroring out) so that an ordinary user can loop through a resultset without fearing that a process might exit in the middle of said looping -- causing the remaining processes to go unsignalled. Incidentally, the last in-core caller of IsBackendPid() is now gone. However, the function is exported and must remain in place, because there are plenty of callers in external modules. Author: Josh Kupershmidt Reviewed by Noah Misch
1 parent 55c1687 commit ae90ffa

File tree

1 file changed

+16
-23
lines changed

1 file changed

+16
-23
lines changed

src/backend/utils/adt/misc.c

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ current_query(PG_FUNCTION_ARGS)
7373

7474
/*
7575
* Send a signal to another backend.
76+
*
7677
* The signal is delivered if the user is either a superuser or the same
7778
* role as the backend being signaled. For "dangerous" signals, an explicit
7879
* check for superuser needs to be done prior to calling this function.
7980
*
8081
* Returns 0 on success, 1 on general failure, and 2 on permission error.
81-
* In the event of a general failure (returncode 1), a warning message will
82+
* In the event of a general failure (return code 1), a warning message will
8283
* be emitted. For permission errors, doing that is the responsibility of
8384
* the caller.
8485
*/
@@ -88,38 +89,30 @@ current_query(PG_FUNCTION_ARGS)
8889
static int
8990
pg_signal_backend(int pid, int sig)
9091
{
91-
PGPROC *proc;
92-
93-
if (!superuser())
94-
{
95-
/*
96-
* Since the user is not superuser, check for matching roles. Trust
97-
* that BackendPidGetProc will return NULL if the pid isn't valid,
98-
* even though the check for whether it's a backend process is below.
99-
* The IsBackendPid check can't be relied on as definitive even if it
100-
* was first. The process might end between successive checks
101-
* regardless of their order. There's no way to acquire a lock on an
102-
* arbitrary process to prevent that. But since so far all the callers
103-
* of this mechanism involve some request for ending the process
104-
* anyway, that it might end on its own first is not a problem.
105-
*/
106-
proc = BackendPidGetProc(pid);
92+
PGPROC *proc = BackendPidGetProc(pid);
10793

108-
if (proc == NULL || proc->roleId != GetUserId())
109-
return SIGNAL_BACKEND_NOPERMISSION;
110-
}
111-
112-
if (!IsBackendPid(pid))
94+
/*
95+
* BackendPidGetProc returns NULL if the pid isn't valid; but by the time
96+
* we reach kill(), a process for which we get a valid proc here might have
97+
* terminated on its own. There's no way to acquire a lock on an arbitrary
98+
* process to prevent that. But since so far all the callers of this
99+
* mechanism involve some request for ending the process anyway, that it
100+
* might end on its own first is not a problem.
101+
*/
102+
if (proc == NULL)
113103
{
114104
/*
115105
* This is just a warning so a loop-through-resultset will not abort
116-
* if one backend terminated on it's own during the run
106+
* if one backend terminated on its own during the run.
117107
*/
118108
ereport(WARNING,
119109
(errmsg("PID %d is not a PostgreSQL server process", pid)));
120110
return SIGNAL_BACKEND_ERROR;
121111
}
122112

113+
if (!(superuser() || proc->roleId == GetUserId()))
114+
return SIGNAL_BACKEND_NOPERMISSION;
115+
123116
/*
124117
* Can the process we just validated above end, followed by the pid being
125118
* recycled for a new process, before reaching here? Then we'd be trying

0 commit comments

Comments
 (0)