}
static bool
-ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path)
+ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path,
+ size_t len)
{
+ /* path must be a valid string */
+ if (memchr(path, '\0', len) == NULL) {
+ errno = EINVAL;
+ return false;
+ }
+
/* Avoid a previous directory attack to avoid /proc/../
* dhcpcd should never use a path with double dots. */
if (strstr(path, "..") != NULL)
- return false;
+ goto noperm;
if (cmd == PS_READFILE) {
#ifdef EMBEDDED_CONFIG
return true;
#endif
+noperm:
errno = EPERM;
return false;
}
size_t len)
{
char *file = data, *nc;
+ size_t flen;
nc = memchr(file, '\0', len);
if (nc == NULL) {
return -1;
}
- if (!ps_root_validpath(ctx, PS_WRITEFILE, file))
+ flen = (size_t)(nc - file) + 1;
+ if (!ps_root_validpath(ctx, PS_WRITEFILE, file, flen))
return -1;
nc++;
- return writefile(file, mode, nc, len - (size_t)(nc - file));
+ return writefile(file, mode, nc, len - flen);
}
#ifdef AUTH
err = ps_stopwait(ctx);
break;
case PS_UNLINK:
- if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
+ if (!ps_root_validpath(ctx, psm->ps_cmd, data, len)) {
err = -1;
break;
}
err = unlink(data);
break;
case PS_READFILE:
- if (!ps_root_validpath(ctx, psm->ps_cmd, data)) {
+ if (!ps_root_validpath(ctx, psm->ps_cmd, data, len)) {
err = -1;
break;
}
len);
break;
case PS_FILEMTIME:
+ if (!ps_root_validpath(ctx, psm->ps_cmd, data, len)) {
+ err = -1;
+ break;
+ }
err = filemtime(data, &mtime);
if (err != -1) {
rdata = &mtime;
#endif
#ifdef PLUGIN_DEV
case PS_DEV_INITTED:
+ /* Check ifname is terminated */
+ if (memchr(data, '\0', len) == NULL) {
+ err = -1;
+ errno = EINVAL;
+ break;
+ }
err = dev_initialised(ctx, data);
break;
case PS_DEV_LISTENING: