[hackers] [quark] Add normabspath() to replace realpath(), making quark work with musl || Laslo Hunhold

From: <git_AT_suckless.org>
Date: Wed, 21 Jun 2017 10:35:37 +0200 (CEST)

commit 283bf91a0e411cd2a1b8b9212752aa7841ca77c7
Author: Laslo Hunhold <dev_AT_frign.de>
AuthorDate: Wed Jun 21 10:27:17 2017 +0200
Commit: Laslo Hunhold <dev_AT_frign.de>
CommitDate: Wed Jun 21 10:35:40 2017 +0200

    Add normabspath() to replace realpath(), making quark work with musl
    
    Compiled against musl, quark will not work as musl needs the presence
    of procfs to process paths in realpath().
    We could wait for it to be implemented[0] or also notice that we don't
    want to overengineer the target-resolving. I don't think it's very
    suckless if we deploy such a huge infrastructure to resolve paths.
    
    To counteract this and given there are no good solutions available, I
    set out to write the function normabspath(), which normalizes an
    absolute path.
    It is idempotent and works on the buffer passed to it. We don't need a
    target, as the resulting resolved path is guaranteed to be of equal
    length or shorter. This requires a memcpy in our case before calling it,
    but I see it as a nice demonstration of the possibilities and it might
    prove to be useful for other projects.
    
    Not requiring a target buffer (that needs to have its length specified),
    the one-string-call also simplifies the calling semantics drasticly.
    
    With this function in place, quark works with musl. Statically linked,
    stripped and with -Os, it only weighs 102K.
    
    [0]: http://www.openwall.com/lists/musl/2016/11/03/5

diff --git a/quark.c b/quark.c
index dbfbd08..5fcf004 100644
--- a/quark.c
+++ b/quark.c
_AT_@ -456,6 +456,47 @@ sendfile(int fd, char *name, struct request *r, struct stat *st, char *mime,
         return s;
 }
 
+static int
+normabspath(char *path)
+{
+ size_t len;
+ int done = 0;
+ char *p, *q, *lastp;
+
+ /* force and skip first slash */
+ if (path[0] != '/') {
+ return 1;
+ }
+ p = path + 1;
+
+ /* get length of path */
+ len = strlen(p);
+
+ for (lastp = p; !done; ) {
+ /* bound path component within (p,q) */
+ if (!(q = strchr(p, '/'))) {
+ q = strchr(p, '\0');
+ done = 1;
+ }
+
+ if (p == q || (q - p == 1 && p[0] == '.')) {
+ /* "/" or "./" */
+ memcpy(p, q + 1, len - ((q + 1) - path) + 2);
+ len -= (q + 1) - p;
+ } else if (q - p == 2 && p[0] == '.' && p[1] == '.') {
+ /* "../" */
+ memcpy(lastp, q + 1, len - ((q + 1) - path) + 2);
+ len -= (q + 1) - lastp;
+ p = lastp;
+ } else {
+ lastp = p;
+ p = q + 1;
+ }
+ }
+
+ return 0;
+}
+
 static enum status
 sendresponse(int fd, struct request *r)
 {
_AT_@ -472,8 +513,9 @@ sendresponse(int fd, struct request *r)
         }
 
         /* normalize target */
- if (!realpath(r->target, realtarget)) {
- return sendstatus(fd, (errno == EACCES) ? S_FORBIDDEN : S_NOT_FOUND);
+ memcpy(realtarget, r->target, sizeof(realtarget));
+ if (normabspath(realtarget)) {
+ return sendstatus(fd, S_BAD_REQUEST);
         }
 
         /* reject hidden target */
Received on Wed Jun 21 2017 - 10:35:37 CEST

This archive was generated by hypermail 2.3.0 : Wed Jun 21 2017 - 10:36:20 CEST