Skip to content

Commit fd1c2fb

Browse files
committed
Add support for a bunch of newer prctl's:
- PAC_RESET_KEYS - IO_FLUSHER - FP_MODE - MPX - THP_DISABLE - TASK_PERF_EVENTS - SPECULATION_CTRL
1 parent 3c211c0 commit fd1c2fb

File tree

4 files changed

+299
-15
lines changed

4 files changed

+299
-15
lines changed

_prctlmodule.c

+135-12
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ prctl_prctl(PyObject *self, PyObject *args)
5050
{
5151
long option = 0;
5252
long arg = 0;
53+
long arg2 = 0;
5354
char *argstr = NULL;
5455
char name[17] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
5556
int result;
@@ -59,7 +60,7 @@ prctl_prctl(PyObject *self, PyObject *args)
5960
* prctl possibilities. int+string is required for (and only accepted for)
6061
* PR_SET_NAME
6162
*/
62-
if(!PyArg_ParseTuple(args, "l|l", &option, &arg)) {
63+
if(!PyArg_ParseTuple(args, "l|ll", &option, &arg, &arg2)) {
6364
if(!PyArg_ParseTuple(args, "ls", &option, &argstr)) {
6465
return NULL;
6566
}
@@ -88,6 +89,9 @@ prctl_prctl(PyObject *self, PyObject *args)
8889
break;
8990
#endif
9091
case(PR_SET_DUMPABLE):
92+
#ifdef PR_SET_IO_FLUSHER
93+
case(PR_SET_IO_FLUSHER):
94+
#endif
9195
case(PR_SET_KEEPCAPS):
9296
/* Only 0 and 1 are allowed */
9397
arg = arg ? 1 : 0;
@@ -113,6 +117,14 @@ prctl_prctl(PyObject *self, PyObject *args)
113117
return NULL;
114118
}
115119
break;
120+
#ifdef PR_SET_FP_MODE
121+
case(PR_SET_FP_MODE):
122+
if(arg != PR_FP_MODE_FR && arg != PR_FP_MODE_FRE) {
123+
PyErr_SetString(PyExc_ValueError, "Unknown floating-point mode");
124+
return NULL;
125+
}
126+
break;
127+
#endif
116128
#ifdef PR_MCE_KILL
117129
case(PR_SET_MCE_KILL):
118130
if(arg != PR_MCE_KILL_DEFAULT && arg != PR_MCE_KILL_EARLY && arg != PR_MCE_KILL_LATE) {
@@ -127,6 +139,14 @@ prctl_prctl(PyObject *self, PyObject *args)
127139
}
128140
strncpy(name, argstr, 16);
129141
break;
142+
#ifdef PR_PAC_RESET_KEYS
143+
case(PR_PAC_RESET_KEYS):
144+
if(arg & ~(PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY)) {
145+
PyErr_SetString(PyExc_ValueError, "Unknown pointer authentication key");
146+
return NULL;
147+
}
148+
break;
149+
#endif
130150
case(PR_SET_PDEATHSIG):
131151
if(arg < 0 || arg > SIGRTMAX) {
132152
PyErr_SetString(PyExc_ValueError, "Unknown signal");
@@ -154,6 +174,30 @@ prctl_prctl(PyObject *self, PyObject *args)
154174
return NULL;
155175
}
156176
break;
177+
#endif
178+
#ifdef PR_GET_SPECULATION_CTRL
179+
case(PR_SET_SPECULATION_CTRL):
180+
if(arg != PR_SPEC_STORE_BYPASS && arg != PR_SPEC_INDIRECT_BRANCH) {
181+
PyErr_SetString(PyExc_ValueError, "Invalid speculation control setting");
182+
return NULL;
183+
}
184+
if(arg2 != PR_SPEC_ENABLE
185+
&& arg2 != PR_SPEC_DISABLE
186+
&& arg2 != PR_SPEC_FORCE_DISABLE
187+
#ifdef PR_SPEC_DISABLE_NOEXEC
188+
&& arg2 != PR_SPEC_DISABLE_NOEXEC
189+
#endif
190+
) {
191+
PyErr_SetString(PyExc_ValueError, "Invalid speculation control value");
192+
return NULL;
193+
}
194+
/* Intentionally not breaking */
195+
case(PR_GET_SPECULATION_CTRL):
196+
if(arg != PR_SPEC_STORE_BYPASS && arg != PR_SPEC_INDIRECT_BRANCH) {
197+
PyErr_SetString(PyExc_ValueError, "Invalid speculation control setting");
198+
return NULL;
199+
}
200+
break;
157201
#endif
158202
case(PR_SET_TIMING):
159203
if(arg != PR_TIMING_STATISTICAL && arg != PR_TIMING_TIMESTAMP) {
@@ -199,14 +243,29 @@ prctl_prctl(PyObject *self, PyObject *args)
199243
case(PR_SET_ENDIAN):
200244
case(PR_SET_FPEMU):
201245
case(PR_SET_FPEXC):
246+
#ifdef PR_SET_FP_MODE
247+
case(PR_GET_FP_MODE):
248+
case(PR_SET_FP_MODE):
249+
#endif
250+
#ifdef PR_SET_IO_FLUSHER
251+
case(PR_GET_IO_FLUSHER):
252+
case(PR_SET_IO_FLUSHER):
253+
#endif
202254
case(PR_SET_KEEPCAPS):
203255
case(PR_GET_KEEPCAPS):
204256
#ifdef PR_MCE_KILL
205257
case(PR_GET_MCE_KILL):
206258
#endif
259+
#ifdef PR_MPX_ENABLE_MANAGEMENT
260+
case(PR_MPX_ENABLE_MANAGEMENT):
261+
case(PR_MPX_DISABLE_MANAGEMENT):
262+
#endif
207263
#ifdef PR_GET_NO_NEW_PRIVS
208264
case(PR_GET_NO_NEW_PRIVS):
209265
case(PR_SET_NO_NEW_PRIVS):
266+
#endif
267+
#ifdef PR_PAC_RESET_KEYS
268+
case(PR_PAC_RESET_KEYS):
210269
#endif
211270
case(PR_SET_PDEATHSIG):
212271
#if defined(PR_GET_PTRACER) && (PR_GET_PTRACER != NOT_SET)
@@ -223,6 +282,18 @@ prctl_prctl(PyObject *self, PyObject *args)
223282
case(PR_SET_SECUREBITS):
224283
case(PR_GET_SECUREBITS):
225284
#endif
285+
#ifdef PR_GET_SPECULATION_CTRL
286+
case(PR_GET_SPECULATION_CTRL):
287+
case(PR_SET_SPECULATION_CTRL):
288+
#endif
289+
#ifdef PR_TASK_PERF_EVENTS_DISABLE
290+
case(PR_TASK_PERF_EVENTS_DISABLE):
291+
case(PR_TASK_PERF_EVENTS_ENABLE):
292+
#endif
293+
#ifdef PR_SET_THP_DISABLE
294+
case(PR_GET_THP_DISABLE):
295+
case(PR_SET_THP_DISABLE):
296+
#endif
226297
#ifdef PR_GET_TIMERSLACK
227298
case(PR_GET_TIMERSLACK):
228299
case(PR_SET_TIMERSLACK):
@@ -233,7 +304,7 @@ prctl_prctl(PyObject *self, PyObject *args)
233304
case(PR_SET_TSC):
234305
#endif
235306
case(PR_SET_UNALIGN):
236-
result = prctl(option, arg, 0, 0, 0);
307+
result = prctl(option, arg, arg2, 0, 0);
237308
if(result < 0) {
238309
PyErr_SetFromErrno(PyExc_OSError);
239310
return NULL;
@@ -243,12 +314,22 @@ prctl_prctl(PyObject *self, PyObject *args)
243314
case(PR_CAPBSET_READ):
244315
#endif
245316
case(PR_GET_DUMPABLE):
317+
#ifdef PR_SET_IO_FLUSHER
318+
case(PR_GET_IO_FLUSHER):
319+
#endif
246320
case(PR_GET_KEEPCAPS):
247321
#ifdef PR_GET_SECCOMP
248322
case(PR_GET_SECCOMP):
323+
#endif
324+
#ifdef PR_GET_THP_DISABLE
325+
case(PR_GET_THP_DISABLE):
249326
#endif
250327
case(PR_GET_TIMING):
251328
return PyBool_FromLong(result);
329+
330+
#ifdef PR_SET_FP_MODE
331+
case(PR_GET_FP_MODE):
332+
#endif
252333
#ifdef PR_MCE_KILL
253334
case(PR_GET_MCE_KILL):
254335
#endif
@@ -261,6 +342,9 @@ prctl_prctl(PyObject *self, PyObject *args)
261342
#ifdef PR_GET_SECUREBITS
262343
case(PR_GET_SECUREBITS):
263344
#endif
345+
#ifdef PR_GET_SPECULATION_CTRL
346+
case(PR_GET_SPECULATION_CTRL):
347+
#endif
264348
#ifdef PR_GET_TIMERSLACK
265349
case(PR_GET_TIMERSLACK):
266350
#endif
@@ -639,6 +723,9 @@ PyInit__prctl(void)
639723
#ifdef PR_CAPBSET_READ
640724
namedconstant(PR_CAPBSET_READ);
641725
namedconstant(PR_CAPBSET_DROP);
726+
#endif
727+
#ifdef PR_SET_CHILD_SUBREAPER
728+
namedattribute(CHILD_SUBREAPER);
642729
#endif
643730
namedattribute(DUMPABLE);
644731
namedattribute(ENDIAN);
@@ -659,34 +746,72 @@ PyInit__prctl(void)
659746
namedconstant(PR_FP_EXC_NONRECOV);
660747
namedconstant(PR_FP_EXC_ASYNC);
661748
namedconstant(PR_FP_EXC_PRECISE);
749+
#ifdef PR_SET_FP_MODE
750+
namedattribute(FP_MODE);
751+
namedconstant(PR_FP_MODE_FR);
752+
namedconstant(PR_FP_MODE_FRE);
753+
#endif
754+
#ifdef PR_SET_IO_FLUSHER
755+
namedattribute(IO_FLUSHER);
756+
#endif
662757
namedattribute(KEEPCAPS);
663758
#ifdef PR_MCE_KILL
664759
namedattribute(MCE_KILL);
665760
namedconstant(PR_MCE_KILL_DEFAULT);
666761
namedconstant(PR_MCE_KILL_EARLY);
667762
namedconstant(PR_MCE_KILL_LATE);
763+
#endif
764+
#ifdef PR_MPX_ENABLE_MANAGEMENT
765+
namedconstant(PR_MPX_ENABLE_MANAGEMENT);
766+
namedconstant(PR_MPX_DISABLE_MANAGEMENT);
668767
#endif
669768
namedattribute(NAME);
769+
#ifdef PR_SET_NO_NEW_PRIVS
770+
namedattribute(NO_NEW_PRIVS);
771+
#endif
772+
#ifdef PR_PAC_RESET_KEYS
773+
namedconstant(PR_PAC_RESET_KEYS);
774+
namedconstant(PR_PAC_APIAKEY);
775+
namedconstant(PR_PAC_APIBKEY);
776+
namedconstant(PR_PAC_APDAKEY);
777+
namedconstant(PR_PAC_APDBKEY);
778+
namedconstant(PR_PAC_APGAKEY);
779+
#endif
670780
namedattribute(PDEATHSIG);
671781
#ifdef PR_SET_PTRACER
672782
namedattribute(PTRACER);
673783
#endif
674784
#ifdef PR_SET_PTRACER_ANY
675785
namedconstant(PR_SET_PTRACER_ANY);
676786
#endif
677-
#ifdef PR_SET_CHILD_SUBREAPER
678-
namedattribute(CHILD_SUBREAPER);
679-
#endif
680-
#ifdef PR_SET_NO_NEW_PRIVS
681-
namedattribute(NO_NEW_PRIVS);
682-
#endif
683-
684787
#ifdef PR_GET_SECCOMP
685788
namedattribute(SECCOMP);
686789
#endif
687790
#ifdef PR_GET_SECUREBITS
688791
namedattribute(SECUREBITS);
689792
#endif
793+
#ifdef PR_SET_SPECULATION_CTRL
794+
namedattribute(SPECULATION_CTRL);
795+
namedconstant(PR_SPEC_STORE_BYPASS);
796+
namedconstant(PR_SPEC_INDIRECT_BRANCH);
797+
namedconstant(PR_SPEC_PRCTL);
798+
namedconstant(PR_SPEC_ENABLE);
799+
namedconstant(PR_SPEC_DISABLE);
800+
namedconstant(PR_SPEC_FORCE_DISABLE);
801+
#ifdef PR_SPEC_DISABLE_NOEXEC
802+
namedconstant(PR_SPEC_DISABLE_NOEXEC);
803+
#endif
804+
#endif
805+
#ifdef PR_TASK_PERF_EVENTS_DISABLE
806+
namedconstant(PR_TASK_PERF_EVENTS_DISABLE);
807+
namedconstant(PR_TASK_PERF_EVENTS_ENABLE);
808+
#endif
809+
#ifdef PR_SET_THP_DISABLE
810+
namedattribute(THP_DISABLE);
811+
#endif
812+
#ifdef PR_GET_TID_ADDRESS
813+
namedconstant(PR_GET_TID_ADDRESS);
814+
#endif
690815
#ifdef PR_GET_TIMERSLACK
691816
namedattribute(TIMERSLACK);
692817
#endif
@@ -701,9 +826,7 @@ PyInit__prctl(void)
701826
namedattribute(UNALIGN);
702827
namedconstant(PR_UNALIGN_NOPRINT);
703828
namedconstant(PR_UNALIGN_SIGBUS);
704-
#ifdef PR_GET_TID_ADDRESS
705-
namedconstant(PR_GET_TID_ADDRESS);
706-
#endif
829+
707830
/* Add the CAP_* constants too */
708831
namedconstant(CAP_EFFECTIVE);
709832
namedconstant(CAP_PERMITTED);

docs/index.rst

+85
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,21 @@ The prctl module is now ready to use.
137137
Return the floating-point exception mode as a bitmap of enabled modes. See
138138
:func:`set_fpexc`.
139139

140+
.. function:: set_io_flusher(is_flusher)
141+
142+
Put the process in :const:`IO_FLUSHER` state, which, which allows it special
143+
treatment to make progress when allocating memory. This is used by process
144+
involved in the block layer or filesystem i/o path, such as fuse daemons or
145+
scsi device emulation daemons.
146+
147+
This is only available in linux 5.6 and newer
148+
149+
.. function:: get_io_flusher()
150+
151+
Return the :const:`IO_FLUSHER` state of the process.
152+
153+
This is only available in linux 5.6 and newer
154+
140155
.. function:: set_keepcaps(flag)
141156

142157
Set the state of the thread's "keep capabilities" flag, which determines
@@ -147,6 +162,7 @@ The prctl module is now ready to use.
147162
are cleared). This value will be reset to :const:`False` on subsequent calls
148163
to :func:`execve`.
149164

165+
150166
.. function:: get_keepcaps()
151167

152168
Return the current state of the calling thread's "keep capabilities" flag.
@@ -171,6 +187,16 @@ The prctl module is now ready to use.
171187

172188
This is only available in linux 2.6.32 and newer
173189

190+
.. function:: pr_mpx_enable_management()
191+
192+
.. function:: pr_mpx_disable_management()
193+
194+
Enable or disable intel memory protection extensions. See :manpage:`prctl(2)`
195+
for details and limitations.
196+
197+
This is only available in linux 3.19 and newer, but no longer available in
198+
linux 5.4 and newer.
199+
174200
.. function:: set_name(name)
175201

176202
Set the process name for the calling process, the name can be up to 16 bytes
@@ -199,6 +225,23 @@ The prctl module is now ready to use.
199225

200226
This is only available in linux 3.5 and newer
201227

228+
.. function:: pac_reset_keys(keys)
229+
230+
Securely reset the thread's pointer authentication keys to fresh random
231+
values generated by the kernel. The keys must be a logical or of any of the
232+
keys you want to reset, or 0 to reset all keys. The available keys are
233+
:const:`PR_PAC_APIAKEY`, :const:`PR_PAC_APIBKEY`, :const:`PR_PAC_APDAKEY`,
234+
:const:`PR_PAC_APDBKEY` and :const:`PR_PAC_APGAKEY`.
235+
236+
For more information, see the kernel source file
237+
Documentation/arm64/pointer-authentication.rst
238+
239+
This is only available in linux 5.0 and newer
240+
241+
.. note::
242+
This function only works on arm64 systems. An :exc:`OSError` is raised
243+
when called on other systems.
244+
202245
.. function:: set_proctitle(title)
203246

204247
Set the process name for the calling process by overwriting the C-level
@@ -272,6 +315,48 @@ The prctl module is now ready to use.
272315
operation is only available if the kernel is configured with
273316
:const:`CONFIG_SECCOMP` enabled.
274317

318+
.. function:: set_speculation_ctrl(feature, value)
319+
320+
Sets the state of a speculation misfeature (:const:`SPEC_STORE_BYPASS` or
321+
:const:`SPEC_INDIRECT_BRANCH`). The value is one of :const:`PR_SPEC_ENABLE`
322+
to enable the feature, :const:`PR_SPEC_DISABLE` to disable it,
323+
:const:`PR_SPEC_FORCE_DISABLE` to disable it permanently for the thread and
324+
:const:`PR_SPEC_DISABLE_NOEXEC` to disable it until the next :func:`execve`.
325+
326+
This is only available in linux 4.17 and newer
327+
328+
.. function:: get_speculation_ctrl(feature)
329+
330+
Returns the state of a speculation misfeature (:const:`SPEC_STORE_BYPASS` or
331+
:const:`SPEC_INDIRECT_BRANCH`). The value is one of the values that can be
332+
set by :func:`pr_set_speculation_ctrl`, possibly logically OR'ed with
333+
const:`PR_SPEC_PRCTL` to indicate that the value can be controlled er thread
334+
by that function. If all bits are 0, the CPU is not affected by the
335+
misfeature.
336+
337+
This is only available in linux 4.17 and newer
338+
339+
.. function:: task_perf_events_disable()
340+
.. function:: task_perf_events_enable()
341+
342+
Disable or enable all performance counters attached to the calling process,
343+
regardless of whether the counters were created by this process or another
344+
process. Performance counters created by the calling process for other
345+
processes are unaffected.
346+
347+
.. function:: set_thp_disable(is_disabled)
348+
349+
Disable transparent huge ages for the current process. This flag is inhereted
350+
by child process and preserved across execve.
351+
352+
This is only available in linux 3.15 and newer
353+
354+
.. function:: get_thp_disable()
355+
356+
Return whether transparent huge pages are disabled for the current process.
357+
358+
This is only available in linux 3.15 and newer
359+
275360
.. function:: get_tid_address()
276361

277362
Allows the process to obtain its own `clear_tid_address`, used when

0 commit comments

Comments
 (0)