Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions src/dhcpcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,10 @@ static void
dhcpcd_initstate(struct interface *ifp, unsigned long long options)
{

dhcpcd_initstate1(ifp, ifp->ctx->argc, ifp->ctx->argv, options);
dhcpcd_initstate1(ifp,
ifp->argv ? ifp->argc : ifp->ctx->argc,
ifp->argv ? ifp->argv : ifp->ctx->argv,
options);
}

static void
Expand Down Expand Up @@ -1364,7 +1367,7 @@ if_reboot(struct interface *ifp, int argc, char **argv)
oldopts = ifp->options->options;
#endif
script_runreason(ifp, "RECONFIGURE");
dhcpcd_initstate1(ifp, argc, argv, 0);
dhcpcd_initstate1(ifp, argc, argv, 0); // control or main argv
#ifdef INET
if (ifp->options->options & DHCPCD_DHCP)
dhcp_reboot_newopts(ifp, oldopts);
Expand Down Expand Up @@ -1399,28 +1402,44 @@ reload_config(struct dhcpcd_ctx *ctx)
}

static void
reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
reconf_reboot(struct dhcpcd_ctx *ctx,
const int reboot_else_applyaddr,
const int argc, char **argv,
const int first_iface_arg)
{
int i;
struct interface *ifp;
bool args_empty = argc == first_iface_arg;

TAILQ_FOREACH(ifp, ctx->ifaces, next) {
for (i = oi; i < argc; i++) {
// Find ifp in iface args
for (i = first_iface_arg; i < argc; i++) {
if (strcmp(ifp->name, argv[i]) == 0)
break;
}
if (oi != argc && i == argc)
continue;

bool iface_found = i != argc;

if (!args_empty && !iface_found)
continue; // try to find other ifaces
// Note: if args_empty affect all interfaces

if (ifp->active == IF_ACTIVE_USER) {
if (action)
if (reboot_else_applyaddr)
if_reboot(ifp, argc, argv);
#ifdef INET
else
ipv4_applyaddr(ifp);
#endif
} else if (i != argc) {
} else if (iface_found) {
ifp->active = IF_ACTIVE_USER;
dhcpcd_initstate1(ifp, argc, argv, 0);
dhcpcd_initstate1(ifp, argc, argv, 0); // control cmd args

if (ifp->argv)
free_argv_copy(ifp->argv);
ifp->argv = copy_argv(argc, argv);
ifp->argc = ifp->argv ? argc : 0;

run_preinit(ifp);
dhcpcd_prestartinterface(ifp);
}
Expand Down Expand Up @@ -1529,7 +1548,7 @@ dhcpcd_signal_cb(int sig, void *arg)
reload_config(ctx);
/* Preserve any options passed on the commandline
* when we were started. */
reconf_reboot(ctx, 1, ctx->argc, ctx->argv,
reconf_reboot(ctx, 1 /*1=if_reboot*/, ctx->argc, ctx->argv,
ctx->argc - ctx->ifc);
return;
case SIGUSR1:
Expand Down Expand Up @@ -1773,7 +1792,7 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
}

reload_config(ctx);
/* XXX: Respect initial commandline options? */
/* Respect control cmd options! */
reconf_reboot(ctx, do_reboot, argc, argv, oifind);
return 0;
}
Expand Down Expand Up @@ -2680,7 +2699,7 @@ main(int argc, char **argv, char **envp)

TAILQ_FOREACH(ifp, ctx.ifaces, next) {
if (ifp->active)
dhcpcd_initstate1(ifp, argc, argv, 0);
dhcpcd_initstate1(ifp, argc, argv, 0); // main argv
}
if_learnaddrs(&ctx, ctx.ifaces, &ifaddrs);
if_freeifaddrs(&ctx, &ifaddrs);
Expand Down
3 changes: 3 additions & 0 deletions src/dhcpcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ struct interface {
uint8_t ssid[IF_SSIDLEN];
unsigned int ssid_len;

int argc;
char **argv;

char profile[PROFILE_LEN];
struct if_options *options;
void *if_data[IF_DATA_MAX];
Expand Down
63 changes: 63 additions & 0 deletions src/if-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>

#include "config.h"
#include "common.h"
Expand Down Expand Up @@ -2986,6 +2987,68 @@ add_options(struct dhcpcd_ctx *ctx, const char *ifname,
return r;
}

#define ARGV_COPY_MAGIC ((char *)0x5a54292d273f3d34)
/*^ intentional truncation on 32bit arches */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is scary.
Why do we need a sentinel here? The scope of the variable isn't going outside any process so we can just malloc and free which makes the below code easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sentinel is for memory safety. Think: double free or free or corrupted/wrong pointer being passed in. Always good manners for allocators IMO. Not sure what you mean by "going outside any process".

The sentinel could just as well be 32bit if you like, I just like to use the extra entropy modern machines can offer. The explicit cast should supress truncation warnings but I'm not 100% on that. Was hoping CI would show whether it raises a warning on on 32bit, but it seems there is no coverage.


char **copy_argv(int argc, char **argv)
{
int i;
size_t strslen = 0;

for (i = 0; i < argc; i++) {
strslen += strlen(argv[i]) + 1;
}
if (strslen == 0) // also handles argc < 0
return NULL;

unsigned nptrs = 1 + (unsigned)argc + 1;
size_t ptrslen = nptrs * sizeof(char *);
void *buf = malloc(ptrslen + strslen);
char **ptrs = buf;

if (!buf)
return NULL;

ptrs[0] = ARGV_COPY_MAGIC;
ptrs[nptrs - 1] = NULL;

if (argc == 0)
goto out;

char *strsp = (char *)&ptrs[nptrs];

for (i = 0; i < argc; i++) {
size_t len = strlcpy(strsp, argv[i], strslen);
if (len >= strslen) // truncated
goto err;

ptrs[1 + i] = strsp;

strsp += len + 1;
if (strslen < len + 1)
goto err;
strslen -= len + 1;
}

assert(strslen == 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it interesting that you assert this error but allow impossible errors to pass with a failure in the loop.
Please pick one and be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What "impossible errors" are you talking about?

assert(ptrs[nptrs - 1] == NULL);
out:
return &ptrs[1];

err:
free(buf);
return NULL;
}

void free_argv_copy(char **argv)
{
assert(argv[-1] == ARGV_COPY_MAGIC);
if (argv[-1] != ARGV_COPY_MAGIC) {
logerrx("%s: invalid argv", __func__);
} else
free(&argv[-1]);
}

void
free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
{
Expand Down
3 changes: 3 additions & 0 deletions src/if-options.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,7 @@ int add_options(struct dhcpcd_ctx *, const char *,
void free_dhcp_opt_embenc(struct dhcp_opt *);
void free_options(struct dhcpcd_ctx *, struct if_options *);

char **copy_argv(int argc, char **argv);
void free_argv_copy(char **argv);

#endif
2 changes: 2 additions & 0 deletions src/if.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ if_free(struct interface *ifp)
#endif
rt_freeif(ifp);
free_options(ifp->ctx, ifp->options);
if (ifp->argv)
free_argv_copy(ifp->argv);
free(ifp);
}

Expand Down