There are several important points here, many of which have already been covered in the comments.
Firstly, time you have is not known. There are empirical values (10 minutes before iOS 7/ 3 minutes with iOS 7), but these are not guaranteed. In particular, if you wake from sleep to do work (e.g. geofenced alert), you may not get the full time, you may only get the time remaining from your last time. There are particular actions you can take that will reset the time (e.g. getting your location with GPS may reset the timer in some versions of iOS).
Secondly, you're not being killed because you're still doing work, you're being killed because you have told the OS you're still doing work. The OS doesn't care about your network transfer, it cares about your beginBackgroundTaskWithExpirationHandler.
You can verify this from the crash report, which will say "has active assertions beyond permitted time"
There are three possible reasons for this.
1) The OS called your completion handler, but you didn't call endBackgroundTask in time. You don't get much time when the background handler gets called, but I doubt that this is the problem, your code is pretty compact.
2) The OS called your completion handler, but you didn't call endBackgroundTask at all. I've inherited code that does this, the normal reason is that the code isn't re-entrant, and it is called twice. bgtask is updated to the second value, so when the completion handlers fire, bgtask is ended twice for one task and never for the other. Again, I think you're safe, this is normally a problem for member variables, in your case, bgtask should be copied by the block.
3) The OS didn't call your background handler ( unlikely, but I have some probably unfounded suspicions about iOS 7).
The next possibility, which is not really a background execution issue is that you're not really crashing. Run your app disconnected from Xcode and see if it generates a crash report. If it doesn't, you're probably just being ejected due to memory pressure. If this is really a too long in the background issue, you'll see the exception code is 0x0badfood. Bad food is what makes the watchdog timer angry.
I think background processes used to be removed from the background apps when they were quietly ejected, but now the OS replaces them with a screenshot and starts them anew if the user brings them to the foreground.