I think this was a bug that was introduced in iOS 6 because we've seen it as well. Not only will we get duplicate disconnect callbacks, but sometimes we get disconnect callbacks from players who are actually still in the game and moving around just fine.
What I've done to get around this is to verify that the GKPlayer really is disconnected when I get the disconnect callback. All I do is check the global copy of the GKMatch that I keep around during the game, and see if the GKPlayer is still in there. If so, then that player didn't actually disconnect, so I can ignore the message:
NSString *id;
for (id in gCurrentMatch.playerIDs)
{
if ([id isEqualToString:playerID])
{
NSLog(@"player is NOT really disconnected!!!");
return; // just bail and ignore this
}
}