Skip to content

Commit a144fee

Browse files
miss-islingtongpshead
authored andcommitted
bpo-28503: Use crypt_r() when available instead of crypt() (GH-11373) (GH-11376)
Use crypt_r() when available instead of crypt() in the crypt module. As a nice side effect: This also avoids a memory sanitizer flake as clang msan doesn't know about crypt's internal libc allocated buffer. (cherry picked from commit 387512c) Co-authored-by: Gregory P. Smith <[email protected]> [Google]
1 parent 01b9664 commit a144fee

File tree

6 files changed

+185
-1
lines changed

6 files changed

+185
-1
lines changed

Include/Python.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,17 @@
3636
#include <unistd.h>
3737
#endif
3838
#ifdef HAVE_CRYPT_H
39+
#if defined(HAVE_CRYPT_R) && !defined(_GNU_SOURCE)
40+
/* Required for glibc to expose the crypt_r() function prototype. */
41+
# define _GNU_SOURCE
42+
# define _Py_GNU_SOURCE_FOR_CRYPT
43+
#endif
3944
#include <crypt.h>
45+
#ifdef _Py_GNU_SOURCE_FOR_CRYPT
46+
/* Don't leak the _GNU_SOURCE define to other headers. */
47+
# undef _GNU_SOURCE
48+
# undef _Py_GNU_SOURCE_FOR_CRYPT
49+
#endif
4050
#endif
4151

4252
/* For size_t? */
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The `crypt` module now internally uses the `crypt_r()` library function
2+
instead of `crypt()` when available.

Modules/_cryptmodule.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,15 @@ static PyObject *
3434
crypt_crypt_impl(PyObject *module, const char *word, const char *salt)
3535
/*[clinic end generated code: output=0512284a03d2803c input=0e8edec9c364352b]*/
3636
{
37-
return Py_BuildValue("s", crypt(word, salt));
37+
char *crypt_result;
38+
#ifdef HAVE_CRYPT_R
39+
struct crypt_data data;
40+
memset(&data, 0, sizeof(data));
41+
crypt_result = crypt_r(word, salt, &data);
42+
#else
43+
crypt_result = crypt(word, salt);
44+
#endif
45+
return Py_BuildValue("s", crypt_result);
3846
}
3947

4048

configure

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12727,6 +12727,150 @@ fi
1272712727
done
1272812728

1272912729

12730+
# We search for both crypt and crypt_r as one or the other may be defined
12731+
# This gets us our -lcrypt in LIBS when required on the target platform.
12732+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt" >&5
12733+
$as_echo_n "checking for library containing crypt... " >&6; }
12734+
if ${ac_cv_search_crypt+:} false; then :
12735+
$as_echo_n "(cached) " >&6
12736+
else
12737+
ac_func_search_save_LIBS=$LIBS
12738+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
12739+
/* end confdefs.h. */
12740+
12741+
/* Override any GCC internal prototype to avoid an error.
12742+
Use char because int might match the return type of a GCC
12743+
builtin and then its argument prototype would still apply. */
12744+
#ifdef __cplusplus
12745+
extern "C"
12746+
#endif
12747+
char crypt ();
12748+
int
12749+
main ()
12750+
{
12751+
return crypt ();
12752+
;
12753+
return 0;
12754+
}
12755+
_ACEOF
12756+
for ac_lib in '' crypt; do
12757+
if test -z "$ac_lib"; then
12758+
ac_res="none required"
12759+
else
12760+
ac_res=-l$ac_lib
12761+
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
12762+
fi
12763+
if ac_fn_c_try_link "$LINENO"; then :
12764+
ac_cv_search_crypt=$ac_res
12765+
fi
12766+
rm -f core conftest.err conftest.$ac_objext \
12767+
conftest$ac_exeext
12768+
if ${ac_cv_search_crypt+:} false; then :
12769+
break
12770+
fi
12771+
done
12772+
if ${ac_cv_search_crypt+:} false; then :
12773+
12774+
else
12775+
ac_cv_search_crypt=no
12776+
fi
12777+
rm conftest.$ac_ext
12778+
LIBS=$ac_func_search_save_LIBS
12779+
fi
12780+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt" >&5
12781+
$as_echo "$ac_cv_search_crypt" >&6; }
12782+
ac_res=$ac_cv_search_crypt
12783+
if test "$ac_res" != no; then :
12784+
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
12785+
12786+
fi
12787+
12788+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt_r" >&5
12789+
$as_echo_n "checking for library containing crypt_r... " >&6; }
12790+
if ${ac_cv_search_crypt_r+:} false; then :
12791+
$as_echo_n "(cached) " >&6
12792+
else
12793+
ac_func_search_save_LIBS=$LIBS
12794+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
12795+
/* end confdefs.h. */
12796+
12797+
/* Override any GCC internal prototype to avoid an error.
12798+
Use char because int might match the return type of a GCC
12799+
builtin and then its argument prototype would still apply. */
12800+
#ifdef __cplusplus
12801+
extern "C"
12802+
#endif
12803+
char crypt_r ();
12804+
int
12805+
main ()
12806+
{
12807+
return crypt_r ();
12808+
;
12809+
return 0;
12810+
}
12811+
_ACEOF
12812+
for ac_lib in '' crypt; do
12813+
if test -z "$ac_lib"; then
12814+
ac_res="none required"
12815+
else
12816+
ac_res=-l$ac_lib
12817+
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
12818+
fi
12819+
if ac_fn_c_try_link "$LINENO"; then :
12820+
ac_cv_search_crypt_r=$ac_res
12821+
fi
12822+
rm -f core conftest.err conftest.$ac_objext \
12823+
conftest$ac_exeext
12824+
if ${ac_cv_search_crypt_r+:} false; then :
12825+
break
12826+
fi
12827+
done
12828+
if ${ac_cv_search_crypt_r+:} false; then :
12829+
12830+
else
12831+
ac_cv_search_crypt_r=no
12832+
fi
12833+
rm conftest.$ac_ext
12834+
LIBS=$ac_func_search_save_LIBS
12835+
fi
12836+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt_r" >&5
12837+
$as_echo "$ac_cv_search_crypt_r" >&6; }
12838+
ac_res=$ac_cv_search_crypt_r
12839+
if test "$ac_res" != no; then :
12840+
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
12841+
12842+
fi
12843+
12844+
12845+
ac_fn_c_check_func "$LINENO" "crypt_r" "ac_cv_func_crypt_r"
12846+
if test "x$ac_cv_func_crypt_r" = xyes; then :
12847+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
12848+
/* end confdefs.h. */
12849+
12850+
#define _GNU_SOURCE /* Required for crypt_r()'s prototype in glibc. */
12851+
#include <crypt.h>
12852+
12853+
int
12854+
main ()
12855+
{
12856+
12857+
struct crypt_data d;
12858+
char *r = crypt_r("", "", &d);
12859+
12860+
;
12861+
return 0;
12862+
}
12863+
_ACEOF
12864+
if ac_fn_c_try_compile "$LINENO"; then :
12865+
12866+
$as_echo "#define HAVE_CRYPT_R 1" >>confdefs.h
12867+
12868+
fi
12869+
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
12870+
12871+
fi
12872+
12873+
1273012874
for ac_func in clock_gettime
1273112875
do :
1273212876
ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"

configure.ac

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3875,6 +3875,23 @@ AC_CHECK_FUNCS(gettimeofday,
38753875
])
38763876
)
38773877

3878+
# We search for both crypt and crypt_r as one or the other may be defined
3879+
# This gets us our -lcrypt in LIBS when required on the target platform.
3880+
AC_SEARCH_LIBS(crypt, crypt)
3881+
AC_SEARCH_LIBS(crypt_r, crypt)
3882+
3883+
AC_CHECK_FUNC(crypt_r,
3884+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
3885+
#define _GNU_SOURCE /* Required for crypt_r()'s prototype in glibc. */
3886+
#include <crypt.h>
3887+
]], [[
3888+
struct crypt_data d;
3889+
char *r = crypt_r("", "", &d);
3890+
]])],
3891+
[AC_DEFINE(HAVE_CRYPT_R, 1, [Define if you have the crypt_r() function.])],
3892+
[])
3893+
)
3894+
38783895
AC_CHECK_FUNCS(clock_gettime, [], [
38793896
AC_CHECK_LIB(rt, clock_gettime, [
38803897
LIBS="$LIBS -lrt"

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@
143143
/* Define to 1 if you have the <crypt.h> header file. */
144144
#undef HAVE_CRYPT_H
145145

146+
/* Define if you have the crypt_r() function. */
147+
#undef HAVE_CRYPT_R
148+
146149
/* Define to 1 if you have the `ctermid' function. */
147150
#undef HAVE_CTERMID
148151

0 commit comments

Comments
 (0)