Package: ifupdown
Version: 0.7.47.2
Severity: important
Tags: patch
User: [email protected]
Usertags: origin-ubuntu utopic ubuntu-patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Hello Maintainers, 

In Ubuntu, the attached patch was applied in a hotfix repository:

  * Removed buggy fine-grained lock and introduced big-lock (LP: #1337873)

Description:

It was brought to my attention (by others) that ifupdown runs into race 
conditions on some specific cases.

[Impact]

When trying to deploy many servers at once (higher chances of happening) or 
from time-to-time, like any other intermittent race-condition. Interfaces are 
not brought up like they should and this has a big impact for servers that 
cannot rely on network start scripts.

The problem is caused by a race condition when init(upstart) starts up network 
interfaces in parallel.

[Test Case]

Use attached script to reproduce the error (it might take some hours, in a 
single virtual machine, for the error to occur).

(example 1)

*** sequence to trigger race-condition ***

(a) ifup eth0                     (b) ifup -a for eth0
- -----------------------------------------------------------------
1-1. Lock ifstate.lock file.
                                  1-1. Wait for locking ifstate.lock
                                      file.
1-2. Read ifstate file to check
     the target NIC.
1-3. close(=release) ifstate.lock
     file.
1-4. Judge that the target NIC
     isn't processed.
                                  1-2. Read ifstate file to check
                                       the target NIC.
                                  1-3. close(=release) ifstate.lock
                                       file.
                                  1-4. Judge that the target NIC
                                       isn't processed.
2. Lock and update ifstate file.
   Release the lock.
                                  2. Lock and update ifstate file.
                                     Release the lock.

(example 2)

Bonding device using eth0.
ifenslave for eth0 is also executed in parallel, eth0 remains down.

*** sequence to trigger race-condition ***

(a) ifenslave of eth0             (b) ifenslave of eth0
- ------------------------------------------------------------------
3. Execute ifenslave of eth0.      3. Execute ifenslave of eth0.
4. Link down the target NIC.
5. Write NIC id to
   /sys/class/net/bond0/bonding
   /slaves then NIC gets up
                                  4. Link down the target NIC.
                                  5. Fails to write NIC id to
                                     /sys/class/net/bond0/bonding/
                                     slaves it is already written.

(example 3)

bonding is not set to active-backup as defined in config file: When the 
init(upstart) executes "if-pre-up.d/ifenslave" script and "if-pre-up.d/vlan" 
script for bond0 device in parallel, the "if-pre-up.d/ifenslave" script fails 
to change the bonding mode with a error message, "bonding: unable to update 
mode of bond0 because interface is up.".

*** sequence to trigger race-condition ***

(a)ifup bond0                     (b)ifup -a
- -----------------------------------------------------------------------
1. Update statefile about bond0.
                                  1. Does nothing about bond0
                                     because statefile is already
                                     updated about it.
2. ifenslave::setup_master()
   sysfs_change_down mode 1
   and link down bond0.
                                  2. Link up bond0 by the vlan
                                     script on the processing
                                     for linking up bond0.201(*1).
3. "echo 1 > .../mode" fails.

[ /etc/network/if-pre-up.d/vlan ]

46 if [ -n "$IF_VLAN_RAW_DEVICE" ] && [ ! -d /sys/class/net/$IFACE ]; then
47     if [ ! -x /sbin/vconfig ]; then
48         exit 0
49     fi
50     if ! ip link show dev "$IF_VLAN_RAW_DEVICE" > /dev/null; then
51         echo "$IF_VLAN_RAW_DEVICE does not exist, unable to create $IFACE"
52         exit 1
53     fi
54     ip link set up dev $IF_VLAN_RAW_DEVICE     <-- (*1).
55     vconfig add $IF_VLAN_RAW_DEVICE $VLANID
56 fi

[Regression Potential]

 * Not fix an already existent race condition.

[Other Info]

Example: [ /etc/network/interfaces ]

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual
 bond-master bond0

auto eth1
iface eth1 inet manual
 bond-master bond0

auto bond0
iface bond0 inet dhcp
 bond-slaves eth0 eth1
 hwaddress 11:22:33:44:55:66
 bond-primary eth0
 bond-mode 1
 bond-miimon 100
 bond-updelay 200
 bond-downdelay 200

auto bond0.201
iface bond0.201 inet dhcp
 hwaddress 11:22:33:44:55:66
 vlan-raw-device bond0
....

auto bond0.205
iface bond0.205 inet dhcp
 hwaddress 11:22:33:44:55:66
 vlan-raw-device bond0

Thanks for considering this patch.

Let me know if there is anything I can do to help you with this.

Regards

Rafael Tinoco

- -- System Information:
Debian Release: jessie/sid
  APT prefers trusty-updates
  APT policy: (500, 'trusty-updates'), (500, 'trusty-security'), (500, 
'trusty'), (100, 'trusty-backports')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.13.0-30-generic (SMP w/8 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=UTF-8 (charmap=UTF-8) (ignored: LC_ALL set 
to en_US.UTF-8)
Shell: /bin/sh linked to /bin/dash

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4

iQEcBAEBCgAGBQJTtuWZAAoJEAynk4KHaD/AKM4H/j/8IjttNkJqbc65My1xhpEE
/O+2jwzarEjtzg4d8IzipK52ebWlzfiJFsIAKIOjJzjgyqsrbZ14PbK3NcN3QMCi
vq4JAW81dhnKeYO1w0xtOvM/g0wYlSqy9dPrPlriX1pg7icapYo5xrG78y/WVCXL
vKQoQgWj/dIHQSRBTgjPIPTQohXu0kNYfOzdV7c/D/4HbqpCxnQd3nx4k6cGOZem
ucW7S0dPaxwnIs0oPML8dOGPvF7ei0k/defhrjFTBjuajmpanfLvlc42kt4SNhRa
MNVCTA4q7viy3MPbZVUz0AWC7k23YguTq+5VKTqDWyNqu2VStgw52RM9eARYpmQ=
=xCRD
-----END PGP SIGNATURE-----
diff -Nru ifupdown-0.7.47.2ubuntu4.1/debian/changelog ifupdown-0.7.47.2ubuntu4.2~lp1337873/debian/changelog
diff -Nru ifupdown-0.7.47.2ubuntu4.1/debian/control ifupdown-0.7.47.2ubuntu4.2~lp1337873/debian/control
--- ifupdown-0.7.47.2ubuntu4.1/debian/control	2013-12-02 20:55:40.000000000 -0200
+++ ifupdown-0.7.47.2ubuntu4.2~lp1337873/debian/control	2014-07-04 14:29:27.000000000 -0300
@@ -1,8 +1,7 @@
 Source: ifupdown
 Section: admin
 Priority: important
-Maintainer: Ubuntu Developers <[email protected]>
-XSBC-Original-Maintainer: Andrew Shadura <[email protected]>
+Maintainer: Andrew Shadura <[email protected]>
 Standards-Version: 3.9.4
 Build-Depends: debhelper (>= 9.20120410~)
 Vcs-Hg: http://anonscm.debian.org/hg/collab-maint/ifupdown/
diff -Nru ifupdown-0.7.47.2ubuntu4.1/main.c ifupdown-0.7.47.2ubuntu4.2~lp1337873/main.c
--- ifupdown-0.7.47.2ubuntu4.1/main.c	2014-03-21 16:27:36.000000000 -0300
+++ ifupdown-0.7.47.2ubuntu4.2~lp1337873/main.c	2014-07-04 14:12:47.000000000 -0300
@@ -126,46 +126,37 @@
     exit(0);
 }
 
-FILE * lock_state(const char * argv0) {
-    FILE *lock_fp;
-    lock_fp = fopen(lockfile, no_act ? "r" : "a+");
-    if (lock_fp == NULL) {
-        if (!no_act) {
-            fprintf(stderr, "%s: failed to open lockfile %s: %s\n", argv0, lockfile, strerror(errno));
-            exit(1);
-        } else {
-            return NULL;
-        }
-    }
-
-    int flags;
-
-    if ((flags = fcntl(fileno(lock_fp), F_GETFD)) < 0 || fcntl(fileno(lock_fp), F_SETFD, flags | FD_CLOEXEC) < 0) {
-        fprintf(stderr, "%s: failed to set FD_CLOEXEC on lockfile %s: %s\n", argv0, lockfile, strerror(errno));
-        exit(1);
-    }
+int fakespin(void)
+{
+    static int fd = -1;
+    struct flock fl;
 
-    if (lock_fd(fileno(lock_fp)) < 0) {
-        if (!no_act) {
-            fprintf(stderr, "%s: failed to lock lockfile %s: %s\n", argv0, lockfile, strerror(errno));
-            exit(1);
+    fl.l_type = F_WRLCK;
+    fl.l_whence = SEEK_SET;
+    fl.l_start = 0;
+    fl.l_len = 1;
+
+    if (fd == -1)
+        fd = open(lockfile, O_WRONLY|O_CREAT, 0666);
+
+    if (fd != -1)
+        if((fcntl(fd, F_SETLK, &fl)) == -1)
+        {
+            usleep(250000);
+            return 1;
         }
-    }
 
-    return lock_fp;
+    return 0;
 }
 
 static const char *read_state(const char *argv0, const char *iface)
 {
     char *ret = NULL;
 
-    FILE *lock_fp;
     FILE *state_fp;
     char buf[80];
     char *p;
 
-    lock_fp = lock_state(argv0);
-
     state_fp = fopen(statefile, no_act ? "r" : "a+");
     if (state_fp == NULL) {
         if (!no_act) {
@@ -211,24 +202,16 @@
         state_fp = NULL;
     }
 
-    if (lock_fp != NULL) {
-        fclose(lock_fp);
-        lock_fp = NULL;
-    }
-
     return ret;
 }
 
 static void read_all_state(const char *argv0, char ***ifaces, int *n_ifaces)
 {
     int i;
-    FILE *lock_fp;
     FILE *state_fp;
     char buf[80];
     char *p;
 
-    lock_fp = lock_state(argv0);
-
     state_fp = fopen(statefile, no_act ? "r" : "a+");
     if (state_fp == NULL) {
         if (!no_act) {
@@ -279,24 +262,16 @@
         fclose(state_fp);
         state_fp = NULL;
     }
-
-    if (lock_fp != NULL) {
-        fclose(lock_fp);
-        lock_fp = NULL;
-    }
 }
 
 static void update_state(const char *argv0, const char *iface, const char *state)
 {
     FILE *tmp_fp;
 
-    FILE *lock_fp;
     FILE *state_fp;
     char buf[80];
     char *p;
 
-    lock_fp = lock_state(argv0);
-
     state_fp = fopen(statefile, no_act ? "r" : "a+");
     if (state_fp == NULL) {
         if (!no_act) {
@@ -370,11 +345,6 @@
         fclose(state_fp);
         state_fp = NULL;
     }
-
-    if (lock_fp != NULL) {
-        fclose(lock_fp);
-        lock_fp = NULL;
-    }
 }
 
 static int lock_fd(int fd)
@@ -632,6 +602,9 @@
         usage(argv[0]);
     }
 
+    while(fakespin())
+        continue;
+
     defn = read_interfaces(interfaces);
     if (!defn) {
         fprintf(stderr, "%s: couldn't read interfaces file \"%s\"\n", argv[0], interfaces);

Reply via email to