Unverified Commit 1408cff1 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!15712 drbd: Fix five use after free bugs in get_initial_state

parents 9866a4dd 293e3839
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -1688,22 +1688,22 @@ struct sib_info {
};
void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib);

extern void notify_resource_state(struct sk_buff *,
extern int notify_resource_state(struct sk_buff *,
				  unsigned int,
				  struct drbd_resource *,
				  struct resource_info *,
				  enum drbd_notification_type);
extern void notify_device_state(struct sk_buff *,
extern int notify_device_state(struct sk_buff *,
				unsigned int,
				struct drbd_device *,
				struct device_info *,
				enum drbd_notification_type);
extern void notify_connection_state(struct sk_buff *,
extern int notify_connection_state(struct sk_buff *,
				    unsigned int,
				    struct drbd_connection *,
				    struct connection_info *,
				    enum drbd_notification_type);
extern void notify_peer_device_state(struct sk_buff *,
extern int notify_peer_device_state(struct sk_buff *,
				     unsigned int,
				     struct drbd_peer_device *,
				     struct peer_device_info *,
+25 −16
Original line number Diff line number Diff line
@@ -4598,7 +4598,7 @@ static int nla_put_notification_header(struct sk_buff *msg,
	return drbd_notification_header_to_skb(msg, &nh, true);
}

void notify_resource_state(struct sk_buff *skb,
int notify_resource_state(struct sk_buff *skb,
			   unsigned int seq,
			   struct drbd_resource *resource,
			   struct resource_info *resource_info,
@@ -4640,16 +4640,17 @@ void notify_resource_state(struct sk_buff *skb,
		if (err && err != -ESRCH)
			goto failed;
	}
	return;
	return 0;

nla_put_failure:
	nlmsg_free(skb);
failed:
	drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n",
			err, seq);
	return err;
}

void notify_device_state(struct sk_buff *skb,
int notify_device_state(struct sk_buff *skb,
			 unsigned int seq,
			 struct drbd_device *device,
			 struct device_info *device_info,
@@ -4689,16 +4690,17 @@ void notify_device_state(struct sk_buff *skb,
		if (err && err != -ESRCH)
			goto failed;
	}
	return;
	return 0;

nla_put_failure:
	nlmsg_free(skb);
failed:
	drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n",
		 err, seq);
	return err;
}

void notify_connection_state(struct sk_buff *skb,
int notify_connection_state(struct sk_buff *skb,
			     unsigned int seq,
			     struct drbd_connection *connection,
			     struct connection_info *connection_info,
@@ -4738,16 +4740,17 @@ void notify_connection_state(struct sk_buff *skb,
		if (err && err != -ESRCH)
			goto failed;
	}
	return;
	return 0;

nla_put_failure:
	nlmsg_free(skb);
failed:
	drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n",
		 err, seq);
	return err;
}

void notify_peer_device_state(struct sk_buff *skb,
int notify_peer_device_state(struct sk_buff *skb,
			      unsigned int seq,
			      struct drbd_peer_device *peer_device,
			      struct peer_device_info *peer_device_info,
@@ -4788,13 +4791,14 @@ void notify_peer_device_state(struct sk_buff *skb,
		if (err && err != -ESRCH)
			goto failed;
	}
	return;
	return 0;

nla_put_failure:
	nlmsg_free(skb);
failed:
	drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n",
		 err, seq);
	return err;
}

void notify_helper(enum drbd_notification_type type,
@@ -4845,7 +4849,7 @@ void notify_helper(enum drbd_notification_type type,
		 err, seq);
}

static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
{
	struct drbd_genlmsghdr *dh;
	int err;
@@ -4859,11 +4863,12 @@ static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq)
	if (nla_put_notification_header(skb, NOTIFY_EXISTS))
		goto nla_put_failure;
	genlmsg_end(skb, dh);
	return;
	return 0;

nla_put_failure:
	nlmsg_free(skb);
	pr_err("Error %d sending event. Event seq:%u\n", err, seq);
	return err;
}

static void free_state_changes(struct list_head *list)
@@ -4890,6 +4895,7 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
	unsigned int seq = cb->args[2];
	unsigned int n;
	enum drbd_notification_type flags = 0;
	int err = 0;

	/* There is no need for taking notification_mutex here: it doesn't
	   matter if the initial state events mix with later state chage
@@ -4898,32 +4904,32 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)

	cb->args[5]--;
	if (cb->args[5] == 1) {
		notify_initial_state_done(skb, seq);
		err = notify_initial_state_done(skb, seq);
		goto out;
	}
	n = cb->args[4]++;
	if (cb->args[4] < cb->args[3])
		flags |= NOTIFY_CONTINUES;
	if (n < 1) {
		notify_resource_state_change(skb, seq, state_change->resource,
		err = notify_resource_state_change(skb, seq, state_change->resource,
					     NOTIFY_EXISTS | flags);
		goto next;
	}
	n--;
	if (n < state_change->n_connections) {
		notify_connection_state_change(skb, seq, &state_change->connections[n],
		err = notify_connection_state_change(skb, seq, &state_change->connections[n],
					       NOTIFY_EXISTS | flags);
		goto next;
	}
	n -= state_change->n_connections;
	if (n < state_change->n_devices) {
		notify_device_state_change(skb, seq, &state_change->devices[n],
		err = notify_device_state_change(skb, seq, &state_change->devices[n],
					   NOTIFY_EXISTS | flags);
		goto next;
	}
	n -= state_change->n_devices;
	if (n < state_change->n_devices * state_change->n_connections) {
		notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n],
		err = notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n],
						NOTIFY_EXISTS | flags);
		goto next;
	}
@@ -4938,6 +4944,9 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb)
		cb->args[4] = 0;
	}
out:
	if (err)
		return err;
	else
		return skb->len;
}

+9 −9
Original line number Diff line number Diff line
@@ -1549,7 +1549,7 @@ int drbd_bitmap_io_from_worker(struct drbd_device *device,
	return rv;
}

void notify_resource_state_change(struct sk_buff *skb,
int notify_resource_state_change(struct sk_buff *skb,
				  unsigned int seq,
				  struct drbd_resource_state_change *resource_state_change,
				  enum drbd_notification_type type)
@@ -1562,10 +1562,10 @@ void notify_resource_state_change(struct sk_buff *skb,
		.res_susp_fen = resource_state_change->susp_fen[NEW],
	};

	notify_resource_state(skb, seq, resource, &resource_info, type);
	return notify_resource_state(skb, seq, resource, &resource_info, type);
}

void notify_connection_state_change(struct sk_buff *skb,
int notify_connection_state_change(struct sk_buff *skb,
				    unsigned int seq,
				    struct drbd_connection_state_change *connection_state_change,
				    enum drbd_notification_type type)
@@ -1576,10 +1576,10 @@ void notify_connection_state_change(struct sk_buff *skb,
		.conn_role = connection_state_change->peer_role[NEW],
	};

	notify_connection_state(skb, seq, connection, &connection_info, type);
	return notify_connection_state(skb, seq, connection, &connection_info, type);
}

void notify_device_state_change(struct sk_buff *skb,
int notify_device_state_change(struct sk_buff *skb,
				unsigned int seq,
				struct drbd_device_state_change *device_state_change,
				enum drbd_notification_type type)
@@ -1589,10 +1589,10 @@ void notify_device_state_change(struct sk_buff *skb,
		.dev_disk_state = device_state_change->disk_state[NEW],
	};

	notify_device_state(skb, seq, device, &device_info, type);
	return notify_device_state(skb, seq, device, &device_info, type);
}

void notify_peer_device_state_change(struct sk_buff *skb,
int notify_peer_device_state_change(struct sk_buff *skb,
				     unsigned int seq,
				     struct drbd_peer_device_state_change *p,
				     enum drbd_notification_type type)
@@ -1606,7 +1606,7 @@ void notify_peer_device_state_change(struct sk_buff *skb,
		.peer_resync_susp_dependency = p->resync_susp_dependency[NEW],
	};

	notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type);
	return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type);
}

static void broadcast_state_change(struct drbd_state_change *state_change)
@@ -1614,7 +1614,7 @@ static void broadcast_state_change(struct drbd_state_change *state_change)
	struct drbd_resource_state_change *resource_state_change = &state_change->resource[0];
	bool resource_state_has_changed;
	unsigned int n_device, n_connection, n_peer_device, n_peer_devices;
	void (*last_func)(struct sk_buff *, unsigned int, void *,
	int (*last_func)(struct sk_buff *, unsigned int, void *,
			  enum drbd_notification_type) = NULL;
	void *uninitialized_var(last_arg);

+4 −4
Original line number Diff line number Diff line
@@ -44,19 +44,19 @@ extern struct drbd_state_change *remember_old_state(struct drbd_resource *, gfp_
extern void copy_old_to_new_state_change(struct drbd_state_change *);
extern void forget_state_change(struct drbd_state_change *);

extern void notify_resource_state_change(struct sk_buff *,
extern int notify_resource_state_change(struct sk_buff *,
					 unsigned int,
					 struct drbd_resource_state_change *,
					 enum drbd_notification_type type);
extern void notify_connection_state_change(struct sk_buff *,
extern int notify_connection_state_change(struct sk_buff *,
					   unsigned int,
					   struct drbd_connection_state_change *,
					   enum drbd_notification_type type);
extern void notify_device_state_change(struct sk_buff *,
extern int notify_device_state_change(struct sk_buff *,
				       unsigned int,
				       struct drbd_device_state_change *,
				       enum drbd_notification_type type);
extern void notify_peer_device_state_change(struct sk_buff *,
extern int notify_peer_device_state_change(struct sk_buff *,
					    unsigned int,
					    struct drbd_peer_device_state_change *,
					    enum drbd_notification_type type);