Keyboard shortcuts

Scrolling

dorCtrl+d
Scroll down
uorCtrl+u
Scroll up
Ctrl+e
One line down
Ctrl+y
One line up
gtheng
Top of article
G
Bottom of article

Articles

j
Older article
k
Newer article
O
Open original
H
Open hackernews
R
Open reddit

Lists

jor↓
Next item
kor↑
Previous item
gtheng
First item
G
Last item
oorEnter
Open selected item

Go to

gthenforgtheni
Feed
gthen1–9
Open feed entry
gthenb
Browse
gthenp
Preferences

Search and help

⌘+kCtrl+kor/
Global search
?
Show this help
Esc
Close this help

POSIX wordexp(3) is dangerous

yossarian.net via lobste.rs original

wordexp(3) is a POSIX API for performing shell-style expansions from C.

It's often cited/recommended as a way to do tilde expansion (e.g. ~/foo to /home/me/foo):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wordexp.h>

int expand_tilde(const char *input, char **output) {
    wordexp_t p;
    int ret = wordexp(input, &p, 0);
    if (ret == 0) {
        *output = strdup(p.we_wordv[0]);
        wordfree(&p);
    }
    return ret;
}

int main(void) {
    char *expanded = NULL;
    expand_tilde("~/foo", &expanded);
    printf("expanded: %s\n", expanded);
    return 0;
}

However, wordexp(3) is also dangerous! That last 0 argument is for the flags parameter. By default, all expansion features are enabled, including command expansion:

expand_tilde("$(whoami)/foo", &expanded);

or:

expand_tilde("$(cat /etc/passwd)/foo", &expanded);

Disabling this requires passing WRDE_NOCMD as a flag. Unfortunately, this palliative at best in some libc implementations:

  • musl implements wordexp(3) by delegating to the system shell. It adds some perfunctory scanning for command substitutions before delegating, but fails to match some patterns that the underlying shell (like GNU Bash) can treat as valid command substitutions.

  • macOS's libc implements wordexp(3) in a similar manner, delegating to /usr/lib/system/wordexp-helper1

    . According to Julian Squires this had the same bypass as musl as recently as 2023, although I didn't bother testing whether it's still effective now that the default macOS shell is zsh instead of bash.

Bottom line: don't use wordexp(3) on untrusted inputs, even with WRDE_NOCMD.

  1. Previously, macOS's wordexp(3) would shell out to Perl. wordexp-helper appears to be the "modern" solution. ↩