sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

quark-noroot-20260211-5ad0df9.diff (10649B)


      1 From 8d41e52f7a22b13008e111dbd5edbfc190f253ad Mon Sep 17 00:00:00 2001
      2 From: Rogo <goryachev.romochka@gmail.com>
      3 Date: Wed, 11 Feb 2026 02:31:33 +0300
      4 Subject: [PATCH 1/4] applying quark-noroot-20191003-3c7049e.diff
      5 
      6 ---
      7  main.c  | 92 ++-------------------------------------------------------
      8  quark.1 | 21 +------------
      9  sock.c  | 15 ++--------
     10  sock.h  |  2 +-
     11  4 files changed, 7 insertions(+), 123 deletions(-)
     12 
     13 diff --git a/main.c b/main.c
     14 index 1e88536..d4969fb 100644
     15 --- a/main.c
     16 +++ b/main.c
     17 @@ -1,8 +1,7 @@
     18  /* See LICENSE file for copyright and license details. */
     19  #include <errno.h>
     20 -#include <grp.h>
     21  #include <limits.h>
     22 -#include <pwd.h>
     23 +#include <netinet/in.h>
     24  #include <regex.h>
     25  #include <signal.h>
     26  #include <stddef.h>
     27 @@ -54,7 +53,7 @@ handlesignals(void(*hdl)(int))
     28  static void
     29  usage(void)
     30  {
     31 -	const char *opts = "[-u user] [-g group] [-n num] [-d dir] [-l] "
     32 +	const char *opts = "[-n num] [-d dir] [-l] "
     33  	                   "[-i file] [-v vhost] ... [-m map] ...";
     34  
     35  	die("usage: %s -p port [-h host] %s\n"
     36 @@ -65,9 +64,6 @@ usage(void)
     37  int
     38  main(int argc, char *argv[])
     39  {
     40 -	struct group *grp = NULL;
     41 -	struct passwd *pwd = NULL;
     42 -	struct rlimit rlim;
     43  	struct server srv = {
     44  		.docindex = "index.html",
     45  	};
     46 @@ -80,16 +76,11 @@ main(int argc, char *argv[])
     47  	size_t nthreads = 4;
     48  	size_t nslots = 64;
     49  	char *servedir = ".";
     50 -	char *user = "nobody";
     51 -	char *group = "nogroup";
     52  
     53  	ARGBEGIN {
     54  	case 'd':
     55  		servedir = EARGF(usage());
     56  		break;
     57 -	case 'g':
     58 -		group = EARGF(usage());
     59 -		break;
     60  	case 'h':
     61  		srv.host = EARGF(usage());
     62  		break;
     63 @@ -134,9 +125,6 @@ main(int argc, char *argv[])
     64  	case 'U':
     65  		udsname = EARGF(usage());
     66  		break;
     67 -	case 'u':
     68 -		user = EARGF(usage());
     69 -		break;
     70  	case 'v':
     71  		if (spacetok(EARGF(usage()), tok, 4) || !tok[0] || !tok[1] ||
     72  		    !tok[2]) {
     73 @@ -178,42 +166,10 @@ main(int argc, char *argv[])
     74  		}
     75  	}
     76  
     77 -	/* validate user and group */
     78 -	errno = 0;
     79 -	if (!user || !(pwd = getpwnam(user))) {
     80 -		die("getpwnam '%s': %s", user ? user : "null",
     81 -		    errno ? strerror(errno) : "Entry not found");
     82 -	}
     83 -	errno = 0;
     84 -	if (!group || !(grp = getgrnam(group))) {
     85 -		die("getgrnam '%s': %s", group ? group : "null",
     86 -		    errno ? strerror(errno) : "Entry not found");
     87 -	}
     88 -
     89  	/* open a new process group */
     90  	setpgid(0, 0);
     91  
     92  	handlesignals(sigcleanup);
     93 -
     94 -	/*
     95 -	 * set the maximum number of open file descriptors as needed
     96 -	 *  - 3 initial fd's
     97 -	 *  - nthreads fd's for the listening socket
     98 -	 *  - (nthreads * nslots) fd's for the connection-fd
     99 -	 *  - (5 * nthreads) fd's for general purpose thread-use
    100 -	 */
    101 -	rlim.rlim_cur = rlim.rlim_max = 3 + nthreads + nthreads * nslots +
    102 -	                                5 * nthreads;
    103 -	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
    104 -		if (errno == EPERM) {
    105 -			die("You need to run as root or have "
    106 -			    "CAP_SYS_RESOURCE set, or are asking for more "
    107 -			    "file descriptors than the system can offer");
    108 -		} else {
    109 -			die("setrlimit:");
    110 -		}
    111 -	}
    112 -
    113  	/*
    114  	 * create the (non-blocking) listening socket
    115  	 *
    116 @@ -228,7 +184,7 @@ main(int argc, char *argv[])
    117  	 * kernel by changing epoll-sheduling from a FIFO- to a
    118  	 * LIFO-model, especially as it doesn't affect performance
    119  	 */
    120 -	insock = udsname ? sock_get_uds(udsname, pwd->pw_uid, grp->gr_gid) :
    121 +	insock = udsname ? sock_get_uds(udsname) :
    122  	                   sock_get_ips(srv.host, srv.port);
    123  	if (sock_set_nonblocking(insock)) {
    124  		return 1;
    125 @@ -287,51 +243,9 @@ main(int argc, char *argv[])
    126  		eunveil(servedir, "r");
    127  		eunveil(NULL, NULL);
    128  
    129 -		/* chroot */
    130  		if (chdir(servedir) < 0) {
    131  			die("chdir '%s':", servedir);
    132  		}
    133 -		if (chroot(".") < 0) {
    134 -			if (errno == EPERM) {
    135 -				die("You need to run as root or have "
    136 -				    "CAP_SYS_CHROOT set");
    137 -			} else {
    138 -				die("chroot:");
    139 -			}
    140 -		}
    141 -
    142 -		/* drop root */
    143 -		if (pwd->pw_uid == 0 || grp->gr_gid == 0) {
    144 -			die("Won't run under root %s for hopefully obvious reasons",
    145 -			    (pwd->pw_uid == 0) ? (grp->gr_gid == 0) ?
    146 -			    "user and group" : "user" : "group");
    147 -		}
    148 -
    149 -		if (setgroups(1, &(grp->gr_gid)) < 0) {
    150 -			if (errno == EPERM) {
    151 -				die("You need to run as root or have "
    152 -				    "CAP_SETGID set");
    153 -			} else {
    154 -				die("setgroups:");
    155 -			}
    156 -		}
    157 -		if (setgid(grp->gr_gid) < 0) {
    158 -			if (errno == EPERM) {
    159 -				die("You need to run as root or have "
    160 -				    "CAP_SETGID set");
    161 -			} else {
    162 -				die("setgid:");
    163 -			}
    164 -
    165 -		}
    166 -		if (setuid(pwd->pw_uid) < 0) {
    167 -			if (errno == EPERM) {
    168 -				die("You need to run as root or have "
    169 -				    "CAP_SETUID set");
    170 -			} else {
    171 -				die("setuid:");
    172 -			}
    173 -		}
    174  
    175  		if (udsname) {
    176  			epledge("stdio rpath proc unix", NULL);
    177 diff --git a/quark.1 b/quark.1
    178 index d752cc7..93126b5 100644
    179 --- a/quark.1
    180 +++ b/quark.1
    181 @@ -46,13 +46,8 @@ hidden files and directories.
    182  .It Fl d Ar dir
    183  Serve
    184  .Ar dir
    185 -after chrooting into it.
    186 +after changing into it.
    187  The default is ".".
    188 -.It Fl g Ar group
    189 -Set group ID when dropping privileges, and in socket mode the group of the
    190 -socket file, to the ID of
    191 -.Ar group .
    192 -The default is "nogroup".
    193  .It Fl h Ar host
    194  Use
    195  .Ar host
    196 @@ -94,20 +89,6 @@ redirects on non-standard ports.
    197  Create the UNIX-domain socket
    198  .Ar file ,
    199  listen on it for incoming connections and remove it on exit.
    200 -.It Fl s Ar num
    201 -Set the number of connection slots per worker thread to
    202 -.Ar num .
    203 -The default is 64.
    204 -.It Fl t Ar num
    205 -Set the number of worker threads to
    206 -.Ar num .
    207 -The default is 4.
    208 -.It Fl u Ar user
    209 -Set user ID when dropping privileges,
    210 -and in socket mode the user of the socket file,
    211 -to the ID of
    212 -.Ar user .
    213 -The default is "nobody".
    214  .It Fl v Ar vhost
    215  Add the virtual host specified by
    216  .Ar vhost ,
    217 diff --git a/sock.c b/sock.c
    218 index ebbbf65..bff1b38 100644
    219 --- a/sock.c
    220 +++ b/sock.c
    221 @@ -70,14 +70,13 @@ sock_get_ips(const char *host, const char* port)
    222  }
    223  
    224  int
    225 -sock_get_uds(const char *udsname, uid_t uid, gid_t gid)
    226 +sock_get_uds(const char *udsname)
    227  {
    228  	struct sockaddr_un addr = {
    229  		.sun_family = AF_UNIX,
    230  	};
    231  	size_t udsnamelen;
    232 -	int insock, sockmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
    233 -	                       S_IROTH | S_IWOTH;
    234 +	int insock;
    235  
    236  	if ((insock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    237  		die("socket:");
    238 @@ -97,16 +96,6 @@ sock_get_uds(const char *udsname, uid_t uid, gid_t gid)
    239  		die("listen:");
    240  	}
    241  
    242 -	if (chmod(udsname, sockmode) < 0) {
    243 -		sock_rem_uds(udsname);
    244 -		die("chmod '%s':", udsname);
    245 -	}
    246 -
    247 -	if (chown(udsname, uid, gid) < 0) {
    248 -		sock_rem_uds(udsname);
    249 -		die("chown '%s':", udsname);
    250 -	}
    251 -
    252  	return insock;
    253  }
    254  
    255 diff --git a/sock.h b/sock.h
    256 index 22ae303..765016d 100644
    257 --- a/sock.h
    258 +++ b/sock.h
    259 @@ -7,8 +7,8 @@
    260  #include <sys/types.h>
    261  
    262  int sock_get_ips(const char *, const char *);
    263 -int sock_get_uds(const char *, uid_t, gid_t);
    264  void sock_rem_uds(const char *);
    265 +int sock_get_uds(const char *);
    266  int sock_set_timeout(int, int);
    267  int sock_set_nonblocking(int);
    268  int sock_get_inaddr_str(const struct sockaddr_storage *, char *, size_t);
    269 -- 
    270 2.52.0
    271 
    272 
    273 From 56bde27402884fd051cbe9e5def222b1d4fb5fdb Mon Sep 17 00:00:00 2001
    274 From: Rogo <goryachev.romochka@gmail.com>
    275 Date: Wed, 11 Feb 2026 02:44:40 +0300
    276 Subject: [PATCH 2/4] Remove setrlimit() code
    277 
    278 User other tools to setup process limits, capabilities, credentials.
    279 ---
    280  main.c | 28 ----------------------------
    281  1 file changed, 28 deletions(-)
    282 
    283 diff --git a/main.c b/main.c
    284 index d4969fb..8bb7023 100644
    285 --- a/main.c
    286 +++ b/main.c
    287 @@ -211,34 +211,6 @@ main(int argc, char *argv[])
    288  			die("signal: Failed to set SIG_IGN on SIGPIPE");
    289  		}
    290  
    291 -		/*
    292 -		 * try increasing the thread-limit by the number
    293 -		 * of threads we need (which is the only reliable
    294 -		 * workaround I know given the thread-limit is per user
    295 -		 * rather than per process), but ignore EPERM errors,
    296 -		 * because this most probably means the user has already
    297 -		 * set the value to the kernel's limit, and there's not
    298 -		 * much we can do in any other case.
    299 -		 * There's also no danger of overflow as the value
    300 -		 * returned by getrlimit() is way below the limits of the
    301 -		 * rlim_t datatype.
    302 -		 */
    303 -		if (getrlimit(RLIMIT_NPROC, &rlim) < 0) {
    304 -			die("getrlimit:");
    305 -		}
    306 -		if (rlim.rlim_max == RLIM_INFINITY) {
    307 -			if (rlim.rlim_cur != RLIM_INFINITY) {
    308 -				/* try increasing current limit by nthreads */
    309 -				rlim.rlim_cur += nthreads;
    310 -			}
    311 -		} else {
    312 -			/* try increasing current and hard limit by nthreads */
    313 -			rlim.rlim_cur = rlim.rlim_max += nthreads;
    314 -		}
    315 -		if (setrlimit(RLIMIT_NPROC, &rlim) < 0 && errno != EPERM) {
    316 -			die("setrlimit()");
    317 -		}
    318 -
    319  		/* limit ourselves to reading the servedir and block further unveils */
    320  		eunveil(servedir, "r");
    321  		eunveil(NULL, NULL);
    322 -- 
    323 2.52.0
    324 
    325 
    326 From a31e262d003b0ffdc4bdeff8d6690cd11d5e2f45 Mon Sep 17 00:00:00 2001
    327 From: Rogo <goryachev.romochka@gmail.com>
    328 Date: Wed, 11 Feb 2026 07:13:49 +0300
    329 Subject: [PATCH 3/4] Make internal_path relative to "." or vhost dir
    330 
    331 Absolute pathnames for filesystem paths only work with chroot.
    332 
    333 Without even dealing with other problems that abuse of chroot for
    334 "sandboxing" introduces, it makes impossible to run quark as unpriviliged
    335 user.  URL path is already sanitized for ".." dirs, and quark doesn't
    336 create new files and links.
    337 ---
    338  http.c | 8 ++------
    339  1 file changed, 2 insertions(+), 6 deletions(-)
    340 
    341 diff --git a/http.c b/http.c
    342 index 36f8b1c..9d17cfb 100644
    343 --- a/http.c
    344 +++ b/http.c
    345 @@ -776,16 +776,12 @@ http_prepare_response(const struct request *req, struct response *res,
    346  	 * path and the virtual host while ignoring query and fragment
    347  	 * (valid according to RFC 3986)
    348  	 */
    349 -	if (esnprintf(res->internal_path, sizeof(res->internal_path), "/%s/%s",
    350 -	              (srv->vhost && res->vhost) ? res->vhost->dir : "",
    351 +	if (esnprintf(res->internal_path, sizeof(res->internal_path), "%s/%s",
    352 +	              (srv->vhost && res->vhost) ? res->vhost->dir : ".",
    353  		      res->path)) {
    354  		s = S_REQUEST_TOO_LARGE;
    355  		goto err;
    356  	}
    357 -	if ((tmps = path_normalize(res->internal_path, NULL))) {
    358 -		s = tmps;
    359 -		goto err;
    360 -	}
    361  	if (stat(res->internal_path, &st) < 0) {
    362  		s = (errno == EACCES) ? S_FORBIDDEN : S_NOT_FOUND;
    363  		goto err;
    364 -- 
    365 2.52.0
    366 
    367 
    368 From c67c92dcbdc00f5a16179da8d46525c70a28d219 Mon Sep 17 00:00:00 2001
    369 From: Rogo <goryachev.romochka@gmail.com>
    370 Date: Wed, 11 Feb 2026 07:25:23 +0300
    371 Subject: [PATCH 4/4] Remove "setpgid(0, 0)"; stop breaking ^C behavior in
    372  shell
    373 
    374 ---
    375  main.c | 3 ---
    376  1 file changed, 3 deletions(-)
    377 
    378 diff --git a/main.c b/main.c
    379 index 8bb7023..776fb13 100644
    380 --- a/main.c
    381 +++ b/main.c
    382 @@ -166,9 +166,6 @@ main(int argc, char *argv[])
    383  		}
    384  	}
    385  
    386 -	/* open a new process group */
    387 -	setpgid(0, 0);
    388 -
    389  	handlesignals(sigcleanup);
    390  	/*
    391  	 * create the (non-blocking) listening socket
    392 -- 
    393 2.52.0
    394