[zeromq-dev] pyzmq curve example code

Greg Ward greg at gerg.ca
Tue Feb 25 23:09:58 CET 2014


On 25 February 2014, To ZeroMQ development list said:
> But that seems to have decayed somewhat. I noticed an error from
> pyzmq's setup script about libsodium in the umpteenth build yesterday.
> I think maybe I'll start from scratch with a fresh prefix dir and see
> if that clarifies things.

OK I've updated libsodium, libzmq, and pyzmq from git master, rebuilt
and reinstalled everything to a fresh prefix (/usr/local/zmq4).
Building pyzmq ("python setup.py build --zmq=/usr/local/zmq4") printed

  Warning: Detected ZMQ version: 4.1.0. pyzmq's support for libzmq-dev is experimental.

but what the hell, I'm gonna barge on past that and take a chance. I
saw no warnings about curve or libsodium.

Now I have three problems in examples/security:

1) strawhouse succeeds but logs an error:

     $ python strawhouse.py 
     [ERROR] Failed to deny [u'127.0.0.1']
     Traceback (most recent call last):
       File "/usr/local/zmq4/lib/python2.7/site-packages/zmq/auth/thread.py", line 97, in _handle_pipe
         self.authenticator.deny(*addresses)
       File "/usr/local/zmq4/lib/python2.7/site-packages/zmq/auth/base.py", line 85, in deny
         raise ValueError("Only use a whitelist or a blacklist, not both")
     ValueError: Only use a whitelist or a blacklist, not both
     [INFO] Strawhouse test OK

   (I didn't see this yesterday; unclear what has changed -- except
   I'm now linking with latest upstream libzmq)

2) stonehouse.py refers to the wrong script:

     $ python stonehouse.py                       
     [CRITICAL] Certificates are missing - run generate_certificates script first

   (https://github.com/zeromq/pyzmq/pull/480)
   (I saw this yesterday, so today I thought I'd fix it)

3) generate_keys.py still crashes mysteriously:

     $ python generate_keys.py                                      
     Traceback (most recent call last):
       File "generate_keys.py", line 49, in <module>
         generate_certificates(os.path.dirname(__file__))
       File "generate_keys.py", line 30, in generate_certificates
         server_public_file, server_secret_file = zmq.auth.create_certificates(keys_dir, "server")
       File "/usr/local/zmq4/lib/python2.7/site-packages/zmq/auth/certs.py", line 67, in create_certificates
         public_key, secret_key = zmq.curve_keypair()
       File "utils.pyx", line 51, in zmq.backend.cython.utils.curve_keypair (zmq/backend/cython/utils.c:762)
       File "/usr/local/zmq4/lib/python2.7/site-packages/zmq/error.py", line 128, in _check_rc
         raise ZMQError(errno)
     zmq.error.ZMQError: No such file or directory

   (same problem as yesterday)

So I've dug in a little bit, and it looks like something is
incorrectly reusing errno. Evidence: I hacked
zmq/backend/cython/utils.py as follows:

--- a/zmq/backend/cython/utils.pyx
+++ b/zmq/backend/cython/utils.pyx
@@ -44,10 +44,16 @@ def curve_keypair():
     (public, secret) : two bytestrings
         The public and private keypair as 40 byte z85-encoded bytestrings.
     """
+    import os, signal
     cdef int rc
     cdef char[64] public_key
     cdef char[64] secret_key
+    print('calling zmq_curve_keypair(%r, %r)' % (public_key, secret_key))
+    pid = os.getpid()
+    print('sudo strace -f -tt -p %d' % pid)
+    os.kill(pid, signal.SIGSTOP)
     rc = zmq_curve_keypair (public_key, secret_key)
+    print('zmq_curve_keypair() = %r' % rc)
     _check_rc(rc)
     return public_key, secret_key
 

This gives me:

  * the opportunity to strace (in another terminal window) starting
    from just before the mysterious error
  * clear indicators (write() to stdout) before and after the error

So I run generate_keys.py with the hacked utils.pyx:

  $ python generate_keys.py
  calling zmq_curve_keypair('P\xc4X', '')
  sudo strace -f -tt -p 14453
  zsh: suspended (signal)  python generate_keys.py

In another window, I run the suggested strace command. Then I "fg"
generate_keys.py. Here's what strace reports:

  $ sudo strace -f -tt -p 14391
  Process 14391 attached
  16:58:05.345389 --- stopped by SIGSTOP ---
  16:58:08.518451 --- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=13915, si_uid=1554} ---
  16:58:08.518662 write(1, "zmq_curve_keypair() = -1\n", 25) = 25
  16:58:08.518989 stat("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno", 0x7fff9e5fa630) = -1 ENOENT (No such file or directory)
  16:58:08.519254 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.x86_64-linux-gnu.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  16:58:08.519508 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  16:58:08.519722 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errnomodule.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  16:58:08.519888 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.py", O_RDONLY) = -1 ENOENT (No such file or directory)
  16:58:08.520011 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.pyc", O_RDONLY) = -1 ENOENT (No such file or directory)
  16:58:08.520338 write(2, "Traceback (most recent call last"..., 35) = 35

Bingo. The only file I/O in the call to zmq_curve_keypair() is some
Python code trying to import errno (the module). So errno (the C
global variable) is left at ENOENT, which causes _check_rc() to
generate a misleading exception.

Just to confirm, I made it so the last file Python tries to open fails
differently:

  $ touch /data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.pyc
  $ chmod 000 /data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.pyc
  $ cat /data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.pyc
  cat: /data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.pyc: Permission denied

When I run the whole thing again, strace reports:

  Process 14405 attached
  17:00:00.913494 --- stopped by SIGSTOP ---
  17:00:02.679923 --- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=13915, si_uid=1554} ---
  17:00:02.680118 write(1, "zmq_curve_keypair() = -1\n", 25) = 25
  17:00:02.680430 stat("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno", 0x7fff0adee750) = -1 ENOENT (No such file or directory)
  17:00:02.680792 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.x86_64-linux-gnu.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  17:00:02.681013 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  17:00:02.681201 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errnomodule.so", O_RDONLY) = -1 ENOENT (No such file or directory)
  17:00:02.681312 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.py", O_RDONLY) = -1 ENOENT (No such file or directory)
  17:00:02.681412 open("/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/errno.pyc", O_RDONLY) = -1 EACCES (Permission denied)
  17:00:02.681719 write(2, "Traceback (most recent call last"..., 35) = 35

and the exception printed by python is now:

  Traceback (most recent call last):
    File "generate_keys.py", line 49, in <module>
      generate_certificates(os.path.dirname(__file__))
    File "generate_keys.py", line 30, in generate_certificates
      server_public_file, server_secret_file = zmq.auth.create_certificates(keys_dir, "server")
    File "/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/auth/certs.py", line 67, in create_certificates
      public_key, secret_key = zmq.curve_keypair()
    File "utils.pyx", line 57, in zmq.backend.cython.utils.curve_keypair (zmq/backend/cython/utils.c:905)
    File "/data/src/pyzmq/build/lib.linux-x86_64-2.7/zmq/error.py", line 128, in _check_rc
      raise ZMQError(errno)
  zmq.error.ZMQError: Permission denied

I'm slightly stumped. Next step?

        Greg



More information about the zeromq-dev mailing list