# snetaid — Informe de bugs (auditoría estática)

**Versión revisada:** 1.5.10 (`src/`)  
**Fecha:** 2026-06-03  
**Alcance:** `policy.c`, `server.c`, `config.c`, `util.c`, `netlink_monitor.c`, `iwlist.c`

Este documento recoge hallazgos de una revisión estática del daemon **snetaid**, el componente más crítico del ecosistema NETAID (ubus, netlink, WiFi, hotplug Ethernet).

---

## Resumen ejecutivo

| Severidad | Cantidad | Estado (1.5.10) |
|-----------|----------|-----------------|
| Crítica   | 10       | Corregidos      |
| Alta      | 8        | Corregidos      |
| Media     | 10       | Corregidos      |
| Baja      | 7        | Corregidos      |

Todos los defectos listados (BUG-001 … BUG-036) tienen parche aplicado en la rama de trabajo 1.5.10.

---

## Críticos

### BUG-001 — Use-after-free al desinstalar WiFi activa

**Archivo:** `src/policy.c` (~1280–1286)  
**Descripción:** `cancel_previous_task()` llama a `send_reply_and_cleanup()`, que hace `free(active_watchdog)`. Inmediatamente después se usa `active_watchdog->ifname` en `kill_all_processes()`.  
**Impacto:** Segfault al borrar un perfil en uso.  
**Corrección:** Copiar `ifname` a buffer local antes de cancelar.

---

### BUG-002 — `cancel_previous_task` mata el PID equivocado

**Archivo:** `src/policy.c` (`cancel_previous_task`, `ifup_cb`)  
**Descripción:** `task->proc.pid` se asigna primero a `wpa_supplicant` y luego `ifup_cb` lo sobrescribe con el PID de `ifup`. La cancelación envía SIGTERM/SIGKILL al proceso incorrecto; `wpa_supplicant` puede quedar huérfano.  
**Impacto:** Procesos zombies, bloqueos de fichero, conexiones que no se cancelan.  
**Corrección:** Mantener PIDs separados o usar `kill_all_processes(ifname, NULL)` y limpiar ambos handlers uloop.

---

### BUG-003 — Doble/triple `ubus_complete_deferred_request` y UAF en callbacks

**Archivo:** `src/policy.c` (`ifup_cb`, `check_ip_retry_cb`, `wpa_process_cb`, `send_reply_and_cleanup`, `cancel_previous_task`)  
**Descripción:**

- `ifup_cb` completa la petición ubus diferida.
- `check_ip_retry_cb` puede volver a completarla al obtener IP.
- `wpa_process_cb` llama a `send_reply_and_cleanup` cuando termina wpa, aunque el cliente ya recibió respuesta.
- Los callbacks `uloop_process` / `uloop_timeout` pueden ejecutarse tras `free(task)`.

**Impacto:** Comportamiento indefinido en ubus, cierres del daemon, clientes GTK bloqueados o con respuestas duplicadas.  
**Corrección:** Flag `req_completed`; un solo punto de cierre ubus; cancelar timeout/proceso y anular callbacks antes de `free(task)`.

---

### BUG-004 — Null dereference si falta `passwd` en ubus

**Archivo:** `src/policy.c` (~1055–1056, 1166)  
**Descripción:** `blobmsg_get_string(tb[WIRELESS_CONNECTION_PASSWD])` sin comprobar `tb[...]`; luego `if (*passwd == '\0')`.  
**Impacto:** Crash en conexión a red abierta si el cliente omite el campo.  
**Corrección:** Tratar ausencia de atributo como contraseña vacía solo si `!tb[PASSWD] || !passwd || passwd[0] == '\0'`.

---

### BUG-005 — Red abierta: escritura fuera de rutas permitidas

**Archivo:** `src/policy.c` (~1086–1201)  
**Descripción:** Redes con `passwd` vacío escriben el `.conf` sin exigir `pass_filter_ok`. Un `filename` fuera de `WIFI_DIR` / `PREFIX` puede crearse igual.  
**Impacto:** Escritura de configuración en rutas no previstas.  
**Corrección:** Validar prefijo de `path` antes de cualquier escritura.

---

### BUG-006 — Crash netlink: `IFLA_MTU` opcional

**Archivo:** `src/netlink_monitor.c` (~726–727)  
**Descripción:** `*(int *)RTA_DATA(tb[IFLA_MTU])` sin comprobar que `tb[IFLA_MTU]` exista.  
**Impacto:** Segfault en callback uloop ante mensajes `RTM_NEWLINK` sin MTU.  
**Corrección:** Guard `if (tb[IFLA_MTU])`.

---

### BUG-007 — `iwlist()` termina el daemon con `exit()`

**Archivo:** `src/iwlist.c` (~305–307)  
**Descripción:** Fallo al abrir socket wireless → `exit(EXIT_FAILURE)`. Llamado desde `wireless_connection()` en `util.c`.  
**Impacto:** Caída total de snetaid por un fallo de escaneo.  
**Corrección:** Devolver código de error al caller.

---

### BUG-008 — Overflow / datos no inicializados en escaneo

**Archivo:** `src/iwlist.c` (~137–138, 167–172)  
**Descripción:**

- `memcpy(key, ..., event->u.data.length)` sin acotar a `IW_ENCODING_TOKEN_MAX`.
- Con `IW_QUAL_QUAL_INVALID` no se rellena `buffer` pero se publica en ubus.

**Impacto:** Corrupción de pila / JSON con basura.  
**Corrección:** `MIN(length, IW_ENCODING_TOKEN_MAX)`; no añadir Quality si es inválido.

---

### BUG-009 — Fichero de configuración INI nunca cargado

**Archivo:** `src/server.c`, `src/config.c`  
**Descripción:** `main()` solo usa `config_load_from_args()`. `config_load()` existe pero no se invoca; `-a` / `--config_path` no lee el INI.  
**Impacto:** Interfaces, pidfile y logs del fichero de configuración ignorados salvo flags CLI.  
**Corrección:** Tras parsear args, llamar `config_load(config_path ?: DEFAULT_CONFIG_FILE, m_config)` con CLI sobrescribiendo valores.

---

### BUG-010 — Interfaces tratadas como rutas de fichero

**Archivo:** `src/config.c` (`config_fullpaths`, `need_fullpath[]`)  
**Descripción:** `wired_interface` / `wireless_interface` se absolutizan con `getcwd` (tras `daemonize()` → `/tmp`), p. ej. `eth0` → `/tmp/eth0`.  
**Impacto:** Hotplug y periodic_cb operan sobre rutas inválidas.  
**Corrección:** Excluir nombres de interfaz de `need_fullpath[]`.

---

### BUG-011 — Ruta de lockfile por defecto incorrecta

**Archivo:** `src/server.c` (~84)  
**Descripción:** `default_lockfile = " /run/snetaid/snetaid.lock"` (espacio inicial).  
**Impacto:** Lock por defecto en ruta errónea.  
**Corrección:** `"/run/snetaid/snetaid.lock"`.

---

## Altos

### BUG-012 — Hotplug Ethernet: `shall_connect` impide reconexión

**Archivo:** `src/netlink_monitor.c` (~701–707)  
**Descripción:** Tras desconectar cable, `shall_connect = 0`. Al reconectar, si `shall_connect` es 0 solo se pone a 1 sin llamar a `wired_connection_hotplug_trigger()`.  
**Impacto:** Cable enchufado sin autoconexión hasta otro evento netlink.  
**Corrección:** Invocar trigger al detectar enlace activo.

---

### BUG-013 — Zombie en `append_wpa_config` si falla `malloc`

**Archivo:** `src/util.c` (~131–139)  
**Descripción:** Rama sin `waitpid` tras fallo de `malloc`.  
**Corrección:** `waitpid` en todas las rutas de error.

---

### BUG-014 — `nl_msg` desbordamiento por `strcat` sin límite

**Archivo:** `src/netlink_monitor.c` (múltiples `strcat` sobre `nl_msg[MAX_SIZE]`)  
**Impacto:** Corrupción de buffer en eventos de ruta/enlace largos.  
**Corrección:** Acumular con `snprintf` y offset, o buffer dinámico.

---

### BUG-015 — `if_index2name` comprueba el puntero equivocado

**Archivo:** `src/netlink_monitor.c` (~217–223)  
**Descripción:** Se comprueba `name == NULL` (buffer de salida) en lugar del resultado de `if_indextoname`.  
**Corrección:** Devolver cadena segura si `if_name == NULL`.

---

### BUG-016 — `posix_spawnattr_destroy` duplicado

**Archivo:** `src/policy.c` (~1225, 1245)  
**Descripción:** Destrucción doble del mismo `attr` en ruta de éxito.  
**Corrección:** Un solo bloque de limpieza.

---

### BUG-017 — Un solo `active_watchdog` global

**Archivo:** `src/policy.c`  
**Descripción:** Nueva conexión en otra interfaz no cancela tarea previa en distinta `ifname`.  
**Corrección:** Cancelar cualquier tarea activa antes de una nueva conexión, o mapa por interfaz.

---

### BUG-018 — Truncado de `path` en `task->path[256]`

**Archivo:** `src/policy.c` (~1203–1204, comparación en uninstall)  
**Descripción:** `path[1024]` copiado con `strncpy` a 256 bytes; desinstalar puede no detectar perfil activo.  
**Corrección:** Validar longitud o almacenar ruta completa/canónica.

---

### BUG-019 — Hotplug bloquea uloop

**Archivo:** `src/netlink_monitor.c` (`wired_connection_hotplug_trigger` en callback)  
**Descripción:** Operaciones lentas (ifup, DHCP) en el callback netlink.  
**Corrección:** Diferir con `uloop_timeout` / cola de trabajo.

---

## Medios

| ID | Archivo | Problema |
|----|---------|----------|
| BUG-020 | `server.c` | `signal_handler` → `uloop_end()` no async-signal-safe |
| BUG-021 | `netlink_monitor.c` | `kernel_init()` falla en silencio |
| BUG-022 | `netlink_monitor.c` | `MSG_TRUNC` parseado igualmente |
| BUG-023 | `util.c` / `server.c` | `--check` sin validar `pidfile_path` NULL |
| BUG-024 | `server.c` | Fugas en salidas `--kill` / `--check` |
| BUG-025 | `policy.c` | `chmod(path, 0644)` en configs con contraseña |
| BUG-026 | `config.c` | `config_load_from_args(config, ...)` ignora parámetro `config` |
| BUG-027 | `config.c` | `get_fullpath` sin tamaño de destino (`strcpy`/`strcat`) |
| BUG-028 | `netlink_monitor.c` | Interfaces nuevas (`index == 0`) sin hotplug |
| BUG-029 | `config.c` | OOM en `strdup_or_null` devuelve éxito al parser INI |

## Bajos

| ID | Archivo | Problema |
|----|---------|----------|
| BUG-030 | `netlink_monitor.c` | `u->fd > 0` debería ser `>= 0` |
| BUG-031 | `netlink_monitor.c` | `netlink_recvbuf` ignora parámetro `newsize` |
| BUG-032 | `server.c` | `static periodic_timer` global no usado |
| BUG-033 | `util.c` | `get_pid_t` sin validar contenido del pidfile |
| BUG-034 | `iwlist.c` | Falta `break` explícito tras `IWEVQUAL` |
| BUG-035 | `netlink_monitor.c` | `localtime()` + `ubus_send_event` sin comprobar `ctx` |
| BUG-036 | `policy.c` | Código muerto: `check_auth_cb`, `wpa_launcher_done_cb`, etc. |

---

## Diagrama: ciclo WiFi actual (puntos de fallo)

```mermaid
flowchart TD
  WC[wireless_connection] --> Defer[ubus_defer_request]
  Defer --> WPA[wpa_supplicant → proc.pid]
  WPA --> TMO[ifup_cb 2s]
  TMO --> IFUP[proc.pid = ifup]
  IFUP --> U1[ubus_complete #1]
  IFUP --> IP[check_ip_retry]
  IP --> U2[ubus_complete #2]
  WPA --> WPAexit[wpa_process_cb]
  WPAexit --> Free[free task / U3]
  Cancel[cancel_previous_task] --> Kill[kill proc.pid = ifup]
  Uninst[uninstall_saved_wifi] --> UAF[UAF tras free]
```

---

## Estado de correcciones (2026-06-03)

| ID | Estado | Notas |
|----|--------|-------|
| BUG-001 | Corregido | `uninstall_saved_wifi_handler` usa `cancel_active_task` |
| BUG-002 | Corregido | `ifup_proc` separado de `proc` (wpa); cancelación mata ambos PIDs |
| BUG-003 | Corregido | `req_completed`, `dead`, sin doble `ubus_complete` en IP retry |
| BUG-004 | Corregido | `passwd` opcional en ubus |
| BUG-005 | Corregido | `path_allowed_for_wifi_config` antes de escribir |
| BUG-006 | Corregido | Guard `IFLA_MTU` |
| BUG-007 | Corregido | `iwlist()` devuelve -1 |
| BUG-008 | Corregido | `memcpy` acotado, Quality solo si válido |
| BUG-009 | Corregido | `config_load` en `main` + re-parse CLI |
| BUG-010 | Corregido | Interfaces fuera de `need_fullpath` |
| BUG-011 | Corregido | `default_lockfile` sin espacio inicial |
| BUG-012 | Corregido | Hotplug siempre llama a `wired_connection_hotplug_trigger` |
| BUG-013 | Corregido | `waitpid` si falla `malloc` en `append_wpa_config` |
| BUG-014 | Corregido | `nl_msg_append()` sustituye `strcat` en mensajes netlink |
| BUG-015 | Corregido | `if_index2name` comprueba resultado |
| BUG-016 | Corregido | `posix_spawnattr_destroy` una sola vez |
| BUG-017 | Corregido | `cancel_active_task` cancela cualquier tarea activa |
| BUG-018 | Corregido | `task->path[1024]` |
| BUG-019 | Corregido | Hotplug diferido con `uloop_timeout` |
| BUG-020 | Corregido | Señales marcan `shutdown_requested`; `uloop_end` en `periodic_cb` |
| BUG-021 | Corregido | `kernel_init()` devuelve error; `main` aborta arranque |
| BUG-022 | Corregido | Mensajes `MSG_TRUNC` descartados |
| BUG-023 | Corregido | `get_pid_t` valida pidfile y PID |
| BUG-024 | Corregido | `--kill` / `--check` usan `goto cleanup` |
| BUG-025 | Corregido | `chmod(path, 0600)` en WPA |
| BUG-028 | Corregido | Hotplug también en interfaces nuevas (`index == 0`) |
| BUG-033 | Corregido | `strtol` con validación en `get_pid_t` |
| BUG-035 | Corregido | `localtime_r` y guard `ctx` en `log_netlink_event` |
| BUG-026 | Corregido | `config_load_from_args` escribe en el `config_t` pasado por parámetro |
| BUG-027 | Corregido | `get_fullpath` con `malloc` + `snprintf` acotado |
| BUG-029 | Corregido | `config_dup_field` devuelve `-1` si falla `strdup` |
| BUG-030 | Corregido | Comprueba `u->fd <= 0` (incluye fd 0) |
| BUG-031 | Corregido | `netlink_recvbuf` aplica el parámetro `bufsize` |
| BUG-032 | Corregido | `periodic_timer` local en `main`, no global huérfano |
| BUG-034 | Corregido | `break` tras `IWEVQUAL` (sin caída al `default`) |
| BUG-036 | Corregido | Eliminado código muerto (`real_ifup_launch`, `get_wpa_status`, etc.) |

## Orden de corrección aplicado

1. BUG-001, BUG-004, BUG-005, BUG-016 (policy.c inmediatos) — hecho
2. BUG-003, BUG-002, BUG-017 (ciclo de vida ubus/WiFi) — hecho
3. BUG-006, BUG-012, BUG-015 (netlink_monitor.c) — hecho
4. BUG-007, BUG-008 (iwlist.c) — hecho
5. BUG-009, BUG-010, BUG-011 (config + server) — hecho
6. BUG-013 (util.c) — hecho
7. BUG-026–036 (config, netlink, limpieza policy) — hecho

---

## Referencias

- Cliente GTK: `simple-netaid-gtk` (ubus `ering.netaid` / comandos en `gtk.ini`)
- Librería compartida: `libnetaid` (`iproute()`, etc.)
