Hello folks,
I've been using a nice program on ppc32 with a ppc64
system+kernel. It uses netlink to determine some network interface
information. Recent kernels cause it to exit at the netlink stage. At
first, I thought it was a bug in the program. Now I'm not so sure.
The situation is specifically the use of SIOCGIFNAME in 32bit
binaries on 64 bit platforms+kernels. I've tested ppc32 on ppc64 and
ia32 on amd64. amd64 on amd64, ia32 on ia32,and ppc64 on ppc64
all work fine.
I've cooked up a test program to evince the problem. It just
asks netlink for an interface list, then uses SIOCGIFNAME to get the
interface name. On kernels before commit
32da477a5bfe96b6dfc8960e0d22d89ca09fd10a [NET]: Don't implement
dev_ifname32 inline, the test program runs fine. Kernels after, I get
EFAULT. This behavior is the same as the original program.
Instrumenting the kernel with printks, the EFAULT comes from
the first copy_in_user() at line 325 of fs/compat_ioctl.c (in
dev_ifname32()). I put some access_ok() checks in, and they do not
trigger (access is ok). The call never even gets into sys_ioctl().
I'm assuming at this point that copy_in_user() for ia32/amd64
and ppc32/ppc64 is what is having trouble. Test program follows.
Joel
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <asm/types.h>
#include <linux/rtnetlink.h>
#define NETLINK_BUFSIZE 16384
static void bail(int rc, char *fmt, ...)
{
va_list args;
if (fmt) {
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
exit(rc);
}
int main(int argc, char *argv[])
{
int fd, ioctl_fd, rc, len;
struct {
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;
struct sockaddr_nl nladdr;
static char rcvbuf[NETLINK_BUFSIZE];
struct nlmsghdr *h;
struct iovec iov = {rcvbuf, sizeof(rcvbuf) };
struct msghdr msg = {
(void *)&nladdr, sizeof(nladdr),
&iov, 1,
NULL, 0,
0
};
struct ifreq ifr;
struct ifaddrmsg *ifa;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0)
bail(1, "Unable to open netlink socket: %s\n", strerror(errno));
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)))
bail(1, "Unable to set socket options: %s\n", strerror(errno));
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_type = RTM_GETADDR;
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = 1;
req.g.rtgen_family = AF_INET;
if (sendto(fd, (void *)&req, sizeof(req), 0,
(struct sockaddr *)&nladdr, sizeof(nladdr)) < 0)
bail(1, "Unable to send netlink request: %s\n", strerror(errno));
while (1)
{
rc = recvmsg(fd, &msg, 0);
if (!rc)
bail(1, "Netlink socket closed\n");
h = (struct nlmsghdr *)rcvbuf;
if (h->nlmsg_type == NLMSG_DONE)
break;
if (h->nlmsg_type == NLMSG_ERROR)
bail(1, "Error from netlink socket\n");
len = rc;
for (; NLMSG_OK(h, len); h = NLMSG_NEXT(h, len)) {
if (h->nlmsg_type != RTM_NEWADDR)
continue;
ioctl_fd = socket(AF_INET, SOCK_STREAM, 0);
if (ioctl_fd < 0)
bail(1, "Unable to create ioctl socket: %s\n",
strerror(errno));
ifa = NLMSG_DATA(h);
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_ifindex = ifa->ifa_index;
rc = ioctl(ioctl_fd, SIOCGIFNAME, &ifr);
if (rc)
bail(1, "Unable to get name: %s\n", strerror(errno));
fprintf(stdout, "Interface %d, %s\n", ifr.ifr_ifindex,
ifr.ifr_ifrn.ifrn_name);
}
}
return 0;
}
--
"What no boss of a programmer can ever understand is that a programmer
is working when he's staring out of the window"
- With apologies to Burton Rascoe
Joel Becker
Principal Software Developer
Oracle
E-mail: [email protected]
Phone: (650) 506-8127
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]