Netdev List
 help / color / mirror / Atom feed
* [PATCH net] net: vlan: fix vlan name truncation
@ 2026-09-04 21:00 Janis Edvarts Lacis
  0 siblings, 0 replies; only message in thread
From: Janis Edvarts Lacis @ 2026-09-04 21:00 UTC (permalink / raw)
  To: netdev
  Cc: davem, edumazet, kuba, pabeni, horms, linux-kernel,
	Janis Edvarts Lacis

register_vlan_device() from net/8021q/vlan.c sets name based on a field
name_type from struct vlan_net. If name_type is VLAN_NAME_TYPE_RAW_PLUS_VID
or VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, register_vlan_device() sets vlan
device's name to the actual net_device's name and adds vid at the end of
this name separated by a dot.

Network interface's name is limited to at most 16 characters, including NUL.
Therefore, if the real_dev->name is long enough, then adding the vid
at the end of this name can lead to the result exceeding 16 bytes which
leads to a truncated name for the vlan device created in register_vlan_device().

This patch fixes the issue by returning -ENAMETOOLONG from
register_vlan_device() if the newly created name does not fit in 16
bytes.

The bug was discovered when compiling with flag W=1, the following warning comes up:
linux/net/8021q/vlan.c: In function ‘vlan_ioctl_handler’:
linux/net/8021q/vlan.c:250:46: error: ‘%i’ directive output may be truncated writing between 1 and 5 bytes into a region of size between 0 and 15 [-Werror=format-truncation=]
  250 |                 snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id);
      |                                              ^~
In function ‘register_vlan_device’,
    inlined from ‘vlan_ioctl_handler’ at linux/net/8021q/vlan.c:588:9:
linux/net/8021q/vlan.c:250:42: note: directive argument in the range [0, 65535]
  250 |                 snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id);
      |                                          ^~~~~~~

Build & run the reproducer:
    gcc poc.c -o poc
    chmod +x poc.sh
    ./poc.sh

======BEGIN poc.sh======
#!/usr/bin/env bash

sudo ip link add vlan1234567890 type dummy
sudo ./poc

# name will not match the expected printed from poc.c on the unpatched
# kernel, there will be no vlan interface at all on the patched one
ip a
======END poc.sh========

======BEGIN poc.c======
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/sockios.h>

#define IF_NAME "vlan1234567890"

int main()
{
    struct vlan_ioctl_args args = {
	.cmd = ADD_VLAN_CMD,
	.u.VID = 1234,
    };

    strcpy(args.device1, IF_NAME);

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
	perror("socket");
	return 1;
    }

    /* fails with -ENAMETOOLONG */
    if (ioctl(fd, SIOCSIFVLAN, &args) < 0) {
	perror("SIOCSIFVLAN");
	close(fd);
	return 1;
    }

    printf("Expected name: %s.%i\n", IF_NAME, args.u.VID);
    close(fd);
    return 0;
}
======END poc.c========

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Janis Edvarts Lacis <janislacis06@gmail.com>
---
 net/8021q/vlan.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 2d2efb877975..b51092d217de 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -220,7 +220,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
 	struct net *net = dev_net(real_dev);
 	struct vlan_net *vn = net_generic(net, vlan_net_id);
 	char name[IFNAMSIZ];
-	int err;
+	int err, len;
 
 	if (vlan_id >= VLAN_VID_MASK)
 		return -ERANGE;
@@ -234,7 +234,9 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
 	switch (vn->name_type) {
 	case VLAN_NAME_TYPE_RAW_PLUS_VID:
 		/* name will look like:	 eth1.0005 */
-		snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, vlan_id);
+		len = snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, vlan_id);
+		if (len >= sizeof(name))
+			err = -ENAMETOOLONG;
 		break;
 	case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:
 		/* Put our vlan.VID in the name.
@@ -246,7 +248,9 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
 		/* Put our vlan.VID in the name.
 		 * Name will look like:	 eth0.5
 		 */
-		snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id);
+		len = snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id);
+		if (len >= sizeof(name))
+			err = -ENAMETOOLONG;
 		break;
 	case VLAN_NAME_TYPE_PLUS_VID:
 		/* Put our vlan.VID in the name.
@@ -256,6 +260,9 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
 		snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id);
 	}
 
+	if (err)
+		return err;
+
 	new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name,
 			       NET_NAME_UNKNOWN, vlan_setup);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-04 21:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-04 21:00 [PATCH net] net: vlan: fix vlan name truncation Janis Edvarts Lacis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox