1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

Fix 'crypt' deadlock upon error.

* libguile/posix.c (scm_crypt): Take 'scm_i_misc_mutex' right before
calling 'crypt'.  Move 'SCM_SYSERROR' call after 'scm_dynwind_end'.
* test-suite/tests/posix.test ("crypt"): New test prefix.
This commit is contained in:
Ludovic Courtès 2017-12-22 11:12:57 +01:00
parent 2c7d6031f3
commit 6d391bf1a4
2 changed files with 40 additions and 6 deletions

View file

@ -1,6 +1,6 @@
/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, /* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
* 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, * 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
* 2014, 2016 Free Software Foundation, Inc. * 2014, 2016, 2017 Free Software Foundation, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
@ -1935,26 +1935,43 @@ SCM_DEFINE (scm_crypt, "crypt", 2, 0, 0,
"crypt(3) library call.") "crypt(3) library call.")
#define FUNC_NAME s_scm_crypt #define FUNC_NAME s_scm_crypt
{ {
int err;
SCM ret; SCM ret;
char *c_key, *c_salt, *c_ret; char *c_key, *c_salt, *c_ret;
scm_dynwind_begin (0); scm_dynwind_begin (0);
scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex);
c_key = scm_to_locale_string (key); c_key = scm_to_locale_string (key);
scm_dynwind_free (c_key); scm_dynwind_free (c_key);
c_salt = scm_to_locale_string (salt); c_salt = scm_to_locale_string (salt);
scm_dynwind_free (c_salt); scm_dynwind_free (c_salt);
/* Take the lock because 'crypt' uses a static buffer. */
scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex);
/* The Linux crypt(3) man page says crypt will return NULL and set errno /* The Linux crypt(3) man page says crypt will return NULL and set errno
on error. (Eg. ENOSYS if legal restrictions mean it cannot be on error. (Eg. ENOSYS if legal restrictions mean it cannot be
implemented). */ implemented). */
c_ret = crypt (c_key, c_salt); c_ret = crypt (c_key, c_salt);
if (c_ret == NULL)
SCM_SYSERROR;
ret = scm_from_locale_string (c_ret); if (c_ret == NULL)
/* Note: Do not throw until we've released 'scm_i_misc_mutex' since
this would cause a deadlock down the path. */
err = errno;
else
{
err = 0;
ret = scm_from_locale_string (c_ret);
}
scm_dynwind_end (); scm_dynwind_end ();
if (err != 0)
{
errno = err;
SCM_SYSERROR;
}
return ret; return ret;
} }
#undef FUNC_NAME #undef FUNC_NAME

View file

@ -1,7 +1,7 @@
;;;; posix.test --- Test suite for Guile POSIX functions. -*- scheme -*- ;;;; posix.test --- Test suite for Guile POSIX functions. -*- scheme -*-
;;;; ;;;;
;;;; Copyright 2003, 2004, 2006, 2007, 2010, 2012, ;;;; Copyright 2003, 2004, 2006, 2007, 2010, 2012,
;;;; 2015 Free Software Foundation, Inc. ;;;; 2015, 2017 Free Software Foundation, Inc.
;;;; ;;;;
;;;; This library is free software; you can redistribute it and/or ;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public ;;;; modify it under the terms of the GNU Lesser General Public
@ -222,3 +222,20 @@
(let ((me (getpid))) (let ((me (getpid)))
(and (not (zero? (system* "something-that-does-not-exist"))) (and (not (zero? (system* "something-that-does-not-exist")))
(= me (getpid)))))) (= me (getpid))))))
;;
;; crypt
;;
(with-test-prefix "crypt"
(pass-if "basic usage"
(string? (crypt "pass" "abcdefg")))
(pass-if-exception "glibc EINVAL" exception:system-error
;; This used to deadlock while trying to throw to 'system-error'.
;; This test uses the special interpretation of the salt that glibc
;; does; specifically, we pass a syntactically invalid salt here.
(if (string-contains %host-type "-gnu")
(crypt "pass" "$X$abc") ;EINVAL
(throw 'unresolved))))