cfreebsd

Need help in understanding the Capsicum capability mode and its effect on getpass()


I am experimenting with the Capsicum framework on FreeBSD. I am trying to learn how to use its sandboxing capabilities. While experimenting, I discovered that if I enter capability mode with cap_enter() prior to calling getpass(), the passphrase is echoed to the terminal as you're typing. I clearly don't want that, but the rest of the program still runs as expected with no errors. If we call cap_enter() after getpass(), it behaves normally and the rest of the program executes as expected.

The first two questions that occurred to me are:

This article from 2012 by David Chisnall maybe give a hint on the second page in the section "File Descriptors as Capabilities".

As I say, I'm working on FreeBSD; 14.0-RELEASE-p4. Here is a simple program that demonstrates the issue with getpass(). My initial expectation was that getpass() would behave normally. I'd like to understand why it doesn't inside capability mode, and how to fix it so I can use getpass() inside capability mode with no echo.

//cap_test.c

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/capsicum.h>

#include "test.h"


int main(int argc, char* argv[]) {

    // Entering capability mode  here causes getpass()
    // to echo the passphrase.
    //cap_enter();
  
    char* pwd = getpass("Passphrase: ");
    
    // By making the call here, the passphrase is
    // not echoed.
    cap_enter();

    // The SHA256() function takes a char* as input and returns
    // an unsigned char pointer.
    uchar* key =  SHA256(pwd);
    memset(pwd, 0, sizeof(pwd)*sizeof(pwd[0])); // added in edit
    
    // Echo 32 hash bytes
    for (int i=0; i<32; i++) {
        printf("%x ", key[i]);
    }
    printf("\n");

    // Zero-out key memory location to check that it works.                                          
    memset(key, 0, 32*sizeof(key[0]));

    return 0;
}

The simple header file gives us a typedef and function prototype:

typedef unsigned char uchar;
extern unsigned char* SHA256(char*);

Solution

  • On Linux, the getpass(3) function is clearly marked: "This function is obsolete. Do not use it." Now might be a good time to heed that advice. See also the NOTES section and the commentary about using readpassphrase() from libbsd.

    After reading the article you reference in the question, it looks to me as if you will need to write your own analogue of readpassphrase() using the Capsicum facilities to allow you to open /dev/tty. You'll have to decide what to do if the program has no controlling terminal. However, the article is from 2012; a lot may have changed/expanded in the world of Capsicum in the last decade, so read the manuals to see what options there are.

    It would be worth looking for more recent material on Capsicum. Wikipedia on Capsicum is an obvious place to look, as is the manual page for capsicum(4) and the FreeBSD Wiki on Capsicum — no doubt, you're already aware of these. A Google search also shows links to Cambridge University Computer Laboratory, which initiated the work on Capsicum.