mirror of https://github.com/python/cpython
bpo-38622: Add missing audit events for ctypes module (GH-17158)
This commit is contained in:
parent
476e76f7cf
commit
00923c6399
|
@ -1526,6 +1526,12 @@ object is available:
|
||||||
``ctypes.dlsym`` with arguments ``library`` (the library object) and ``name``
|
``ctypes.dlsym`` with arguments ``library`` (the library object) and ``name``
|
||||||
(the symbol's name as a string or integer).
|
(the symbol's name as a string or integer).
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.dlsym/handle handle,name ctypes.LibraryLoader
|
||||||
|
|
||||||
|
In cases when only the library handle is available rather than the object,
|
||||||
|
accessing a function raises an auditing event ``ctypes.dlsym/handle`` with
|
||||||
|
arguments ``handle`` (the raw library handle) and ``name``.
|
||||||
|
|
||||||
.. _ctypes-foreign-functions:
|
.. _ctypes-foreign-functions:
|
||||||
|
|
||||||
Foreign functions
|
Foreign functions
|
||||||
|
@ -1611,6 +1617,19 @@ They are instances of a private class:
|
||||||
passed arguments.
|
passed arguments.
|
||||||
|
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.seh_exception code foreign-functions
|
||||||
|
|
||||||
|
On Windows, when a foreign function call raises a system exception (for
|
||||||
|
example, due to an access violation), it will be captured and replaced with
|
||||||
|
a suitable Python exception. Further, an auditing event
|
||||||
|
``ctypes.seh_exception`` with argument ``code`` will be raised, allowing an
|
||||||
|
audit hook to replace the exception with its own.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.call_function func_pointer,arguments ctype-foreign-functions
|
||||||
|
|
||||||
|
Some ways to invoke foreign function calls may raise an auditing event
|
||||||
|
``ctypes.call_function`` with arguments ``function pointer`` and ``arguments``.
|
||||||
|
|
||||||
.. _ctypes-function-prototypes:
|
.. _ctypes-function-prototypes:
|
||||||
|
|
||||||
Function prototypes
|
Function prototypes
|
||||||
|
@ -1802,6 +1821,8 @@ Utility functions
|
||||||
Returns the address of the memory buffer as integer. *obj* must be an
|
Returns the address of the memory buffer as integer. *obj* must be an
|
||||||
instance of a ctypes type.
|
instance of a ctypes type.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.addressof obj ctypes.addressof
|
||||||
|
|
||||||
|
|
||||||
.. function:: alignment(obj_or_type)
|
.. function:: alignment(obj_or_type)
|
||||||
|
|
||||||
|
@ -1844,6 +1865,7 @@ Utility functions
|
||||||
termination character. An integer can be passed as second argument which allows
|
termination character. An integer can be passed as second argument which allows
|
||||||
specifying the size of the array if the length of the bytes should not be used.
|
specifying the size of the array if the length of the bytes should not be used.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.create_string_buffer init,size ctypes.create_string_buffer
|
||||||
|
|
||||||
|
|
||||||
.. function:: create_unicode_buffer(init_or_size, size=None)
|
.. function:: create_unicode_buffer(init_or_size, size=None)
|
||||||
|
@ -1860,6 +1882,7 @@ Utility functions
|
||||||
allows specifying the size of the array if the length of the string should not
|
allows specifying the size of the array if the length of the string should not
|
||||||
be used.
|
be used.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.create_unicode_buffer init,size ctypes.create_unicode_buffer
|
||||||
|
|
||||||
|
|
||||||
.. function:: DllCanUnloadNow()
|
.. function:: DllCanUnloadNow()
|
||||||
|
@ -1917,11 +1940,15 @@ Utility functions
|
||||||
Returns the current value of the ctypes-private copy of the system
|
Returns the current value of the ctypes-private copy of the system
|
||||||
:data:`errno` variable in the calling thread.
|
:data:`errno` variable in the calling thread.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.get_errno "" ctypes.get_errno
|
||||||
|
|
||||||
.. function:: get_last_error()
|
.. function:: get_last_error()
|
||||||
|
|
||||||
Windows only: returns the current value of the ctypes-private copy of the system
|
Windows only: returns the current value of the ctypes-private copy of the system
|
||||||
:data:`LastError` variable in the calling thread.
|
:data:`LastError` variable in the calling thread.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.get_last_error "" ctypes.get_last_error
|
||||||
|
|
||||||
.. function:: memmove(dst, src, count)
|
.. function:: memmove(dst, src, count)
|
||||||
|
|
||||||
Same as the standard C memmove library function: copies *count* bytes from
|
Same as the standard C memmove library function: copies *count* bytes from
|
||||||
|
@ -1965,6 +1992,7 @@ Utility functions
|
||||||
Set the current value of the ctypes-private copy of the system :data:`errno`
|
Set the current value of the ctypes-private copy of the system :data:`errno`
|
||||||
variable in the calling thread to *value* and return the previous value.
|
variable in the calling thread to *value* and return the previous value.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.set_errno errno ctypes.set_errno
|
||||||
|
|
||||||
|
|
||||||
.. function:: set_last_error(value)
|
.. function:: set_last_error(value)
|
||||||
|
@ -1973,6 +2001,7 @@ Utility functions
|
||||||
:data:`LastError` variable in the calling thread to *value* and return the
|
:data:`LastError` variable in the calling thread to *value* and return the
|
||||||
previous value.
|
previous value.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.set_last_error error ctypes.set_last_error
|
||||||
|
|
||||||
|
|
||||||
.. function:: sizeof(obj_or_type)
|
.. function:: sizeof(obj_or_type)
|
||||||
|
@ -1987,6 +2016,8 @@ Utility functions
|
||||||
object. If size is specified, it is used as size, otherwise the string is assumed
|
object. If size is specified, it is used as size, otherwise the string is assumed
|
||||||
to be zero-terminated.
|
to be zero-terminated.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.string_at address,size ctypes.string_at
|
||||||
|
|
||||||
|
|
||||||
.. function:: WinError(code=None, descr=None)
|
.. function:: WinError(code=None, descr=None)
|
||||||
|
|
||||||
|
@ -2007,6 +2038,8 @@ Utility functions
|
||||||
characters of the string, otherwise the string is assumed to be
|
characters of the string, otherwise the string is assumed to be
|
||||||
zero-terminated.
|
zero-terminated.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.wstring_at address,size ctypes.wstring_at
|
||||||
|
|
||||||
|
|
||||||
.. _ctypes-data-types:
|
.. _ctypes-data-types:
|
||||||
|
|
||||||
|
@ -2034,6 +2067,7 @@ Data types
|
||||||
source buffer in bytes; the default is zero. If the source buffer is not
|
source buffer in bytes; the default is zero. If the source buffer is not
|
||||||
large enough a :exc:`ValueError` is raised.
|
large enough a :exc:`ValueError` is raised.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.cdata/buffer pointer,size,offset ctypes._CData.from_buffer
|
||||||
|
|
||||||
.. method:: _CData.from_buffer_copy(source[, offset])
|
.. method:: _CData.from_buffer_copy(source[, offset])
|
||||||
|
|
||||||
|
@ -2043,6 +2077,8 @@ Data types
|
||||||
is zero. If the source buffer is not large enough a :exc:`ValueError` is
|
is zero. If the source buffer is not large enough a :exc:`ValueError` is
|
||||||
raised.
|
raised.
|
||||||
|
|
||||||
|
.. audit-event:: ctypes.cdata/buffer pointer,size,offset ctypes._CData.from_buffer_copy
|
||||||
|
|
||||||
.. method:: from_address(address)
|
.. method:: from_address(address)
|
||||||
|
|
||||||
This method returns a ctypes type instance using the memory specified by
|
This method returns a ctypes type instance using the memory specified by
|
||||||
|
|
|
@ -52,11 +52,13 @@ def create_string_buffer(init, size=None):
|
||||||
if isinstance(init, bytes):
|
if isinstance(init, bytes):
|
||||||
if size is None:
|
if size is None:
|
||||||
size = len(init)+1
|
size = len(init)+1
|
||||||
|
_sys.audit("ctypes.create_string_buffer", init, size)
|
||||||
buftype = c_char * size
|
buftype = c_char * size
|
||||||
buf = buftype()
|
buf = buftype()
|
||||||
buf.value = init
|
buf.value = init
|
||||||
return buf
|
return buf
|
||||||
elif isinstance(init, int):
|
elif isinstance(init, int):
|
||||||
|
_sys.audit("ctypes.create_string_buffer", None, init)
|
||||||
buftype = c_char * init
|
buftype = c_char * init
|
||||||
buf = buftype()
|
buf = buftype()
|
||||||
return buf
|
return buf
|
||||||
|
@ -283,11 +285,13 @@ def create_unicode_buffer(init, size=None):
|
||||||
# 32-bit wchar_t (1 wchar_t per Unicode character). +1 for
|
# 32-bit wchar_t (1 wchar_t per Unicode character). +1 for
|
||||||
# trailing NUL character.
|
# trailing NUL character.
|
||||||
size = len(init) + 1
|
size = len(init) + 1
|
||||||
|
_sys.audit("ctypes.create_unicode_buffer", init, size)
|
||||||
buftype = c_wchar * size
|
buftype = c_wchar * size
|
||||||
buf = buftype()
|
buf = buftype()
|
||||||
buf.value = init
|
buf.value = init
|
||||||
return buf
|
return buf
|
||||||
elif isinstance(init, int):
|
elif isinstance(init, int):
|
||||||
|
_sys.audit("ctypes.create_unicode_buffer", None, init)
|
||||||
buftype = c_wchar * init
|
buftype = c_wchar * init
|
||||||
buf = buftype()
|
buf = buftype()
|
||||||
return buf
|
return buf
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add additional audit events for the :mod:`ctypes` module.
|
|
@ -641,6 +641,12 @@ CDataType_from_buffer(PyObject *type, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PySys_Audit("ctypes.cdata/buffer", "nnn",
|
||||||
|
(Py_ssize_t)buffer->buf, buffer->len, offset) < 0) {
|
||||||
|
Py_DECREF(mv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
result = PyCData_AtAddress(type, (char *)buffer->buf + offset);
|
result = PyCData_AtAddress(type, (char *)buffer->buf + offset);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
Py_DECREF(mv);
|
Py_DECREF(mv);
|
||||||
|
@ -691,6 +697,12 @@ CDataType_from_buffer_copy(PyObject *type, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PySys_Audit("ctypes.cdata/buffer", "nnn",
|
||||||
|
(Py_ssize_t)buffer.buf, buffer.len, offset) < 0) {
|
||||||
|
PyBuffer_Release(&buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL);
|
result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
memcpy(((CDataObject *)result)->b_ptr,
|
memcpy(((CDataObject *)result)->b_ptr,
|
||||||
|
@ -714,6 +726,9 @@ CDataType_in_dll(PyObject *type, PyObject *args)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "Os:in_dll", &dll, &name))
|
if (!PyArg_ParseTuple(args, "Os:in_dll", &dll, &name))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (PySys_Audit("ctypes.dlsym", "O", args) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
obj = PyObject_GetAttrString(dll, "_handle");
|
obj = PyObject_GetAttrString(dll, "_handle");
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
@ -5535,6 +5550,9 @@ create_comerror(void)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
string_at(const char *ptr, int size)
|
string_at(const char *ptr, int size)
|
||||||
{
|
{
|
||||||
|
if (PySys_Audit("ctypes.string_at", "ni", (Py_ssize_t)ptr, size) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (size == -1)
|
if (size == -1)
|
||||||
return PyBytes_FromStringAndSize(ptr, strlen(ptr));
|
return PyBytes_FromStringAndSize(ptr, strlen(ptr));
|
||||||
return PyBytes_FromStringAndSize(ptr, size);
|
return PyBytes_FromStringAndSize(ptr, size);
|
||||||
|
@ -5626,6 +5644,9 @@ static PyObject *
|
||||||
wstring_at(const wchar_t *ptr, int size)
|
wstring_at(const wchar_t *ptr, int size)
|
||||||
{
|
{
|
||||||
Py_ssize_t ssize = size;
|
Py_ssize_t ssize = size;
|
||||||
|
if (PySys_Audit("ctypes.wstring_at", "nn", (Py_ssize_t)ptr, ssize) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (ssize == -1)
|
if (ssize == -1)
|
||||||
ssize = wcslen(ptr);
|
ssize = wcslen(ptr);
|
||||||
return PyUnicode_FromWideChar(ptr, ssize);
|
return PyUnicode_FromWideChar(ptr, ssize);
|
||||||
|
|
|
@ -199,8 +199,9 @@ set_error_internal(PyObject *self, PyObject *args, int index)
|
||||||
PyObject *errobj;
|
PyObject *errobj;
|
||||||
int *space;
|
int *space;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i", &new_errno))
|
if (!PyArg_ParseTuple(args, "i", &new_errno)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
errobj = _ctypes_get_errobj(&space);
|
errobj = _ctypes_get_errobj(&space);
|
||||||
if (errobj == NULL)
|
if (errobj == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -213,12 +214,18 @@ set_error_internal(PyObject *self, PyObject *args, int index)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_errno(PyObject *self, PyObject *args)
|
get_errno(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
if (PySys_Audit("ctypes.get_errno", NULL) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return get_error_internal(self, args, 0);
|
return get_error_internal(self, args, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_errno(PyObject *self, PyObject *args)
|
set_errno(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
if (PySys_Audit("ctypes.set_errno", "O", args) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return set_error_internal(self, args, 0);
|
return set_error_internal(self, args, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,12 +234,18 @@ set_errno(PyObject *self, PyObject *args)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
get_last_error(PyObject *self, PyObject *args)
|
get_last_error(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
if (PySys_Audit("ctypes.get_last_error", NULL) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return get_error_internal(self, args, 1);
|
return get_error_internal(self, args, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_last_error(PyObject *self, PyObject *args)
|
set_last_error(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
if (PySys_Audit("ctypes.set_last_error", "O", args) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return set_error_internal(self, args, 1);
|
return set_error_internal(self, args, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +275,11 @@ static WCHAR *FormatError(DWORD code)
|
||||||
#ifndef DONT_USE_SEH
|
#ifndef DONT_USE_SEH
|
||||||
static void SetException(DWORD code, EXCEPTION_RECORD *pr)
|
static void SetException(DWORD code, EXCEPTION_RECORD *pr)
|
||||||
{
|
{
|
||||||
|
if (PySys_Audit("ctypes.seh_exception", "I", code) < 0) {
|
||||||
|
/* An exception was set by the audit hook */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* The 'code' is a normal win32 error code so it could be handled by
|
/* The 'code' is a normal win32 error code so it could be handled by
|
||||||
PyErr_SetFromWindowsErr(). However, for some errors, we have additional
|
PyErr_SetFromWindowsErr(). However, for some errors, we have additional
|
||||||
information not included in the error code. We handle those here and
|
information not included in the error code. We handle those here and
|
||||||
|
@ -1427,6 +1445,9 @@ static PyObject *py_dl_sym(PyObject *self, PyObject *args)
|
||||||
if (!PyArg_ParseTuple(args, "O&s:dlsym",
|
if (!PyArg_ParseTuple(args, "O&s:dlsym",
|
||||||
&_parse_voidp, &handle, &name))
|
&_parse_voidp, &handle, &name))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (PySys_Audit("ctypes.dlsym/handle", "O", args) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ptr = ctypes_dlsym((void*)handle, name);
|
ptr = ctypes_dlsym((void*)handle, name);
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
PyErr_SetString(PyExc_OSError,
|
PyErr_SetString(PyExc_OSError,
|
||||||
|
@ -1454,6 +1475,10 @@ call_function(PyObject *self, PyObject *args)
|
||||||
&_parse_voidp, &func,
|
&_parse_voidp, &func,
|
||||||
&PyTuple_Type, &arguments))
|
&PyTuple_Type, &arguments))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (PySys_Audit("ctypes.call_function", "nO",
|
||||||
|
(Py_ssize_t)func, arguments) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
result = _ctypes_callproc((PPROC)func,
|
result = _ctypes_callproc((PPROC)func,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -1485,6 +1510,10 @@ call_cdeclfunction(PyObject *self, PyObject *args)
|
||||||
&_parse_voidp, &func,
|
&_parse_voidp, &func,
|
||||||
&PyTuple_Type, &arguments))
|
&PyTuple_Type, &arguments))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (PySys_Audit("ctypes.call_function", "nO",
|
||||||
|
(Py_ssize_t)func, arguments) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
result = _ctypes_callproc((PPROC)func,
|
result = _ctypes_callproc((PPROC)func,
|
||||||
arguments,
|
arguments,
|
||||||
|
@ -1597,11 +1626,15 @@ static const char addressof_doc[] =
|
||||||
static PyObject *
|
static PyObject *
|
||||||
addressof(PyObject *self, PyObject *obj)
|
addressof(PyObject *self, PyObject *obj)
|
||||||
{
|
{
|
||||||
if (CDataObject_Check(obj))
|
if (!CDataObject_Check(obj)) {
|
||||||
return PyLong_FromVoidPtr(((CDataObject *)obj)->b_ptr);
|
PyErr_SetString(PyExc_TypeError,
|
||||||
PyErr_SetString(PyExc_TypeError,
|
"invalid type");
|
||||||
"invalid type");
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
|
if (PySys_Audit("ctypes.addressof", "O", obj) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyLong_FromVoidPtr(((CDataObject *)obj)->b_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1615,8 +1648,12 @@ static PyObject *
|
||||||
My_PyObj_FromPtr(PyObject *self, PyObject *args)
|
My_PyObj_FromPtr(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *ob;
|
PyObject *ob;
|
||||||
if (!PyArg_ParseTuple(args, "O&:PyObj_FromPtr", converter, &ob))
|
if (!PyArg_ParseTuple(args, "O&:PyObj_FromPtr", converter, &ob)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
if (PySys_Audit("ctypes.PyObj_FromPtr", "O", ob) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Py_INCREF(ob);
|
Py_INCREF(ob);
|
||||||
return ob;
|
return ob;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue